front-hub/src/stores/makeRequest.ts

97 lines
2.5 KiB
TypeScript
Raw Normal View History

2023-03-31 14:59:54 +00:00
import axios, { AxiosResponse } from "axios";
import { create } from "zustand";
import { persist } from "zustand/middleware";
2023-03-31 14:59:54 +00:00
2023-03-20 11:40:19 +00:00
type Token = string;
2023-03-31 14:59:54 +00:00
interface AuthStore {
2023-03-20 11:40:19 +00:00
token: Token;
2023-03-31 14:59:54 +00:00
makeRequest: <TRequest = unknown, TResponse = unknown>(props: FirstRequest<TRequest>) => Promise<TResponse>;
clearToken: () => void;
}
2023-03-31 14:59:54 +00:00
interface FirstRequest<T> {
2023-03-20 11:40:19 +00:00
method?: string;
url: string;
2023-03-31 14:59:54 +00:00
body?: T;
2023-03-20 11:40:19 +00:00
useToken?: boolean;
contentType?: boolean;
2023-03-31 14:59:54 +00:00
signal?: AbortSignal;
2023-04-13 16:48:17 +00:00
withCredentials?: boolean;
}
2023-03-31 14:59:54 +00:00
export const authStore = create<AuthStore>()(
2023-03-20 11:40:19 +00:00
persist(
(set, get) => ({
token: "",
2023-03-31 14:59:54 +00:00
makeRequest: <TRequest, TResponse>(props: FirstRequest<TRequest>): Promise<TResponse> => {
2023-03-20 11:40:19 +00:00
const newProps = { ...props, HC: (newToken: Token) => set({ token: newToken }), token: get().token };
2023-03-31 14:59:54 +00:00
return makeRequest<TRequest, TResponse>(newProps);
2023-03-20 11:40:19 +00:00
},
clearToken: () => set({ token: "" }),
}),
{
name: "token",
}
)
);
2023-03-31 14:59:54 +00:00
interface MakeRequest<T> extends FirstRequest<T> {
2023-03-20 11:40:19 +00:00
HC: (newToken: Token) => void;
token: Token;
}
2023-03-31 14:59:54 +00:00
async function makeRequest<TRequest, TResponse>({
method = "post",
url,
body,
useToken = true,
contentType = false,
HC,
token,
signal,
2023-04-13 16:48:17 +00:00
withCredentials,
2023-03-31 14:59:54 +00:00
}: MakeRequest<TRequest>) {
2023-03-20 11:40:19 +00:00
//В случае 401 рефреш должен попробовать вызваться 1 раз
let headers: any = {};
if (useToken) headers["Authorization"] = token;
2023-04-13 16:48:17 +00:00
if (contentType) headers["Content-Type"] = "*/*";
2023-03-31 14:59:54 +00:00
try {
const response = await axios<TRequest, AxiosResponse<TResponse & { accessToken?: string; }>>(
2023-04-13 16:48:17 +00:00
{ url, method, headers, data: body, signal, withCredentials }
2023-03-31 14:59:54 +00:00
);
if (response.data?.accessToken) {
HC(response.data.accessToken);
}
return response.data;
} catch (error: any) {
2023-04-13 16:48:17 +00:00
if (error?.response?.status === 401 && !withCredentials) {
2023-05-12 14:33:44 +00:00
const refreshResponse = await refresh(token);
2023-03-31 14:59:54 +00:00
if (refreshResponse.data?.accessToken) HC(refreshResponse.data.accessToken);
headers["Authorization"] = refreshResponse.data.accessToken;
const response = await axios<TRequest, AxiosResponse<TResponse>>(
{ url, method, headers, data: body, signal }
);
return response.data;
}
throw error;
}
}
2023-05-12 14:33:44 +00:00
function refresh(token:Token) {
2023-03-31 14:59:54 +00:00
return axios<never, AxiosResponse<{ accessToken: string; }>>("https://admin.pena.digital/auth/refresh", {
2023-03-20 11:40:19 +00:00
headers: {
2023-05-12 14:33:44 +00:00
Authorization: token,
2023-03-20 11:40:19 +00:00
"Content-Type": "application/json",
},
});
}