Основные интерфейсы данных MFA
Вот пример, как мы можем типизировать данные, относящиеся к MFA. Предположим, у нас есть API, которое обрабатывает:
- Генерацию и отправку кода.
- Подтверждение кода пользователем.
Начнём с создания интерфейсов:
// Типизация данных, отправляемых на сервер для генерации кода MFA
export interface GenerateMFARequest {
userId: string; // Идентификатор пользователя
}
// Ответ от сервера после генерации кода
export interface GenerateMFAResponse {
success: boolean; // Успешно ли сгенерирован код
message?: string; // Сообщение об ошибке (в случае неудачи)
}
// Типизация данных для подтверждения кода MFA
export interface ConfirmMFARequest {
userId: string; // Идентификатор пользователя
code: string; // Введённый код подтверждения
}
// Ответ от сервера после подтверждения кода
export interface ConfirmMFAResponse {
success: boolean; // Успешно ли подтверждение
token?: string; // JWT-токен в случае успешного подтверждения
message?: string; // Сообщение об ошибке (при неудаче)
}
Обратите внимание, что мы используем опциональные свойства message, token в ответах API, поскольку они могут отсутствовать в некоторых сценариях. Это делает наш код более гибким и безопасным.
Работа с типизированными данными в компонентах
После того как мы определили интерфейсы, можно приступить к использованию этих данных в наших компонентах.
Предположим, у нас есть компонент, который позволяет пользователю ввести код MFA для подтверждения. Мы будем отправлять запрос на сервер и обрабатывать ответ.
Вот пример кода такого компонента:
import React, { useState } from "react";
import axios from "axios";
import { ConfirmMFARequest, ConfirmMFAResponse } from "./types"; // Импорт интерфейсов
const ConfirmMFA = () => {
const [code, setCode] = useState<string>(""); // Состояние для ввода кода
const [error, setError] = useState<string | null>(null); // Состояние для ошибок
const [loading, setLoading] = useState<boolean>(false); // Состояние загрузки
const handleConfirm = async () => {
setLoading(true);
setError(null);
// Формируем запрос
const requestData: ConfirmMFARequest = {
userId: "12345", // ID пользователя, захардкожен для примера
code,
};
try {
// Отправляем запрос на сервер
const response = await axios.post<ConfirmMFAResponse>(
"/api/confirm-mfa",
requestData
);
if (response.data.success) {
alert("MFA подтверждена, токен: " + response.data.token);
} else {
setError(response.data.message || "Неизвестная ошибка");
}
} catch (err) {
setError("Ошибка сети или сервера");
} finally {
setLoading(false);
}
};
return (
<div>
<h3>Введите код MFA</h3>
<input
type="text"
value={code}
onChange={(e) => setCode(e.target.value)}
placeholder="Введите код"
/>
<button onClick={handleConfirm} disabled={loading}>
{loading ? "Подтверждение..." : "Подтвердить"}
</button>
{error && <p style={{ color: "red" }}>{error}</p>}
</div>
);
};
export default ConfirmMFA;
Что здесь происходит?
- Состояние
codeотвечает за хранение текущего ввода пользователя. - При клике на кнопку "Подтвердить" отправляется запрос на сервер с кодом и идентификатором пользователя.
- Мы типизируем запрос
ConfirmMFARequestи ответConfirmMFAResponse, чтобы избежать ошибок при обработке данных. - Возможные ошибки (например, неверный код или сетевые проблемы) обрабатываются и отображаются пользователю.
Расширяем компонент: использование хуков
Теперь улучшим этот компонент, вынеся логику отправки запроса в кастомный хук. Это позволит переиспользовать логику в других частях приложения.
Создаём хук для подтверждения MFA
import { useState } from "react";
import axios from "axios";
import { ConfirmMFARequest, ConfirmMFAResponse } from "./types";
export const useConfirmMFA = () => {
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);
const confirmMFA = async (requestData: ConfirmMFARequest): Promise<string | null> => {
setLoading(true);
setError(null);
try {
const response = await axios.post<ConfirmMFAResponse>(
"/api/confirm-mfa",
requestData
);
if (response.data.success) {
return response.data.token || null;
} else {
setError(response.data.message || "Неизвестная ошибка");
return null;
}
} catch (err) {
setError("Ошибка сети или сервера");
return null;
} finally {
setLoading(false);
}
};
return { confirmMFA, loading, error };
};
Использование хука в компоненте
Теперь компонент ConfirmMFA будет выглядеть проще:
import React, { useState } from "react";
import { useConfirmMFA } from "./useConfirmMFA";
const ConfirmMFA = () => {
const [code, setCode] = useState<string>(""); // Состояние для ввода кода
const { confirmMFA, loading, error } = useConfirmMFA();
const handleConfirm = async () => {
const token = await confirmMFA({ userId: "12345", code });
if (token) {
alert("MFA подтверждена, токен: " + token);
}
};
return (
<div>
<h3>Введите код MFA</h3>
<input
type="text"
value={code}
onChange={(e) => setCode(e.target.value)}
placeholder="Введите код"
/>
<button onClick={handleConfirm} disabled={loading}>
{loading ? "Подтверждение..." : "Подтвердить"}
</button>
{error && <p style={{ color: "red" }}>{error}</p>}
</div>
);
};
export default ConfirmMFA;
Обратите внимание: теперь вся логика взаимодействия с сервером вынесена в отдельный хук, что делает компонент легче и чище.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ