generated from VLADIMIR/template_frontend
add client
This commit is contained in:
@@ -0,0 +1,270 @@
|
||||
import axios, { type AxiosInstance, type InternalAxiosRequestConfig, AxiosError } from 'axios';
|
||||
import type {
|
||||
LoginReq,
|
||||
LoginRsp,
|
||||
SignupReq,
|
||||
SignupRsp,
|
||||
RefreshPasswordReq,
|
||||
RefreshPasswordRsp,
|
||||
RefreshReq,
|
||||
RefreshRsp,
|
||||
GetUsersReq,
|
||||
GetUsersRsp,
|
||||
GetUserByIdReq,
|
||||
GetUserByIdRsp,
|
||||
GetMeReq,
|
||||
GetMeRsp,
|
||||
AddUserRoleReq,
|
||||
AddUserRoleRsp,
|
||||
DeleteUserRoleReq,
|
||||
DeleteUserRoleRsp,
|
||||
GetPermissionsReq,
|
||||
GetPermissionsRsp,
|
||||
UploadFileReq,
|
||||
UploadFileRsp,
|
||||
DownloadFileReq,
|
||||
AddScenarioReq,
|
||||
AddScenarioRsp,
|
||||
GetMyScenariosReq,
|
||||
GetMyScenariosRsp,
|
||||
GetScenarioReq,
|
||||
GetScenarioRsp,
|
||||
UpdateScenarioReq,
|
||||
UpdateScenarioRsp,
|
||||
DeleteScenarioReq,
|
||||
DeleteScenarioRsp,
|
||||
AddScenarioPlaceReq,
|
||||
AddScenarioPlaceRsp,
|
||||
UpdateScenarioPlaceReq,
|
||||
UpdateScenarioPlaceRsp,
|
||||
DeleteScenarioPlaceReq,
|
||||
DeleteScenarioPlaceRsp,
|
||||
PingReq,
|
||||
PingRsp,
|
||||
EchoReq,
|
||||
EchoRsp,
|
||||
} from './generated/main';
|
||||
|
||||
// Типизированный ответ с error полем
|
||||
type ApiResponse<T> = T & { error?: string };
|
||||
|
||||
class ApiClient {
|
||||
private client: AxiosInstance;
|
||||
private baseUrl: string;
|
||||
|
||||
constructor() {
|
||||
this.baseUrl = import.meta.env.VITE_API_URL || 'http://localhost:8080';
|
||||
this.client = axios.create({
|
||||
baseURL: this.baseUrl,
|
||||
timeout: 30000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// Интерсептор для токена
|
||||
this.client.interceptors.request.use((config) => {
|
||||
const token = localStorage.getItem('accessToken');
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
});
|
||||
|
||||
// Интерсептор для рефреша токена
|
||||
this.client.interceptors.response.use(
|
||||
(response) => response,
|
||||
async (error: AxiosError) => {
|
||||
const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean };
|
||||
|
||||
if (error.response?.status === 401 && !originalRequest._retry) {
|
||||
originalRequest._retry = true;
|
||||
|
||||
try {
|
||||
const refreshToken = localStorage.getItem('refreshToken');
|
||||
if (!refreshToken) {
|
||||
throw new Error('No refresh token');
|
||||
}
|
||||
|
||||
const response = await this.refresh({ refreshToken });
|
||||
localStorage.setItem('accessToken', response.accessToken!);
|
||||
localStorage.setItem('refreshToken', response.refreshToken!);
|
||||
|
||||
originalRequest.headers.Authorization = `Bearer ${response.accessToken}`;
|
||||
return this.client(originalRequest);
|
||||
} catch (refreshError) {
|
||||
// Рефреш не удался — разлогиниваем
|
||||
localStorage.removeItem('accessToken');
|
||||
localStorage.removeItem('refreshToken');
|
||||
window.location.href = '/login';
|
||||
return Promise.reject(refreshError);
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// ---------- AUTH ----------
|
||||
|
||||
async ping(params: PingReq = {}): Promise<ApiResponse<PingRsp>> {
|
||||
const { data } = await this.client.get('/api/test/ping');
|
||||
return data;
|
||||
}
|
||||
|
||||
async echo(params: EchoReq): Promise<ApiResponse<EchoRsp>> {
|
||||
const { data } = await this.client.post('/api/test/echo', params);
|
||||
return data;
|
||||
}
|
||||
|
||||
async signup(params: SignupReq): Promise<ApiResponse<SignupRsp>> {
|
||||
const { data } = await this.client.post('/api/auth/signup', params);
|
||||
return data;
|
||||
}
|
||||
|
||||
async refreshPassword(params: RefreshPasswordReq): Promise<ApiResponse<RefreshPasswordRsp>> {
|
||||
const { data } = await this.client.post('/api/auth/refresh-password', params);
|
||||
return data;
|
||||
}
|
||||
|
||||
async login(params: LoginReq): Promise<ApiResponse<LoginRsp>> {
|
||||
const { data } = await this.client.post('/api/auth/login', params);
|
||||
if (data.accessToken) {
|
||||
localStorage.setItem('accessToken', data.accessToken);
|
||||
if (data.refreshToken) {
|
||||
localStorage.setItem('refreshToken', data.refreshToken);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
async refresh(params: RefreshReq): Promise<ApiResponse<RefreshRsp>> {
|
||||
const { data } = await this.client.post('/api/auth/refresh', params);
|
||||
return data;
|
||||
}
|
||||
|
||||
async logout(): Promise<void> {
|
||||
localStorage.removeItem('accessToken');
|
||||
localStorage.removeItem('refreshToken');
|
||||
}
|
||||
|
||||
// ---------- USERS ----------
|
||||
|
||||
async getUsers(params: GetUsersReq = {}): Promise<ApiResponse<GetUsersRsp>> {
|
||||
const { data } = await this.client.get('/api/users');
|
||||
return data;
|
||||
}
|
||||
|
||||
async getUserById(params: GetUserByIdReq): Promise<ApiResponse<GetUserByIdRsp>> {
|
||||
const { data } = await this.client.get(`/api/users/${params.id}`);
|
||||
return data;
|
||||
}
|
||||
|
||||
async getMe(params: GetMeReq = {}): Promise<ApiResponse<GetMeRsp>> {
|
||||
const { data } = await this.client.get('/api/users/me');
|
||||
return data;
|
||||
}
|
||||
|
||||
async addUserRole(params: AddUserRoleReq): Promise<ApiResponse<AddUserRoleRsp>> {
|
||||
const { id, role } = params;
|
||||
const { data } = await this.client.post(`/api/users/${id}/role/add`, { role });
|
||||
return data;
|
||||
}
|
||||
|
||||
async deleteUserRole(params: DeleteUserRoleReq): Promise<ApiResponse<DeleteUserRoleRsp>> {
|
||||
const { id, role } = params;
|
||||
const { data } = await this.client.post(`/api/users/${id}/role/delete`, { role });
|
||||
return data;
|
||||
}
|
||||
|
||||
// ---------- PERMISSIONS ----------
|
||||
|
||||
async getPermissions(params: GetPermissionsReq = {}): Promise<ApiResponse<GetPermissionsRsp>> {
|
||||
const { data } = await this.client.get('/api/ui/permissions');
|
||||
return data;
|
||||
}
|
||||
|
||||
// ---------- FILES ----------
|
||||
|
||||
async uploadFile(params: UploadFileReq): Promise<ApiResponse<UploadFileRsp>> {
|
||||
if (!params.data) {
|
||||
throw new Error('File data is required');
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('filename', params.filename!);
|
||||
// Преобразуем bytes в Blob
|
||||
const dataArray = new Uint8Array(params.data);
|
||||
const blob = new Blob([dataArray]);
|
||||
formData.append('data', blob);
|
||||
|
||||
const { data } = await this.client.post('/api/files/upload', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
async downloadFile(params: DownloadFileReq): Promise<Blob> {
|
||||
const response = await this.client.get(`/api/files/${params.filename}`, {
|
||||
responseType: 'blob',
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// ---------- SCENARIOS ----------
|
||||
|
||||
async addScenario(params: AddScenarioReq): Promise<ApiResponse<AddScenarioRsp>> {
|
||||
const { data } = await this.client.post('/api/scenario', params);
|
||||
return data;
|
||||
}
|
||||
|
||||
async getMyScenarios(params: GetMyScenariosReq = {}): Promise<ApiResponse<GetMyScenariosRsp>> {
|
||||
const { data } = await this.client.get('/api/my-scenarios');
|
||||
return data;
|
||||
}
|
||||
|
||||
async getScenario(params: GetScenarioReq): Promise<ApiResponse<GetScenarioRsp>> {
|
||||
const { data } = await this.client.get(`/api/scenarios/${params.id}`);
|
||||
return data;
|
||||
}
|
||||
|
||||
async updateScenario(params: UpdateScenarioReq): Promise<ApiResponse<UpdateScenarioRsp>> {
|
||||
const { id, ...body } = params;
|
||||
const { data } = await this.client.put(`/api/scenarios/${id}`, body);
|
||||
return data;
|
||||
}
|
||||
|
||||
async deleteScenario(params: DeleteScenarioReq): Promise<ApiResponse<DeleteScenarioRsp>> {
|
||||
const { data } = await this.client.delete(`/api/scenarios/${params.id}`);
|
||||
return data;
|
||||
}
|
||||
|
||||
// ---------- SCENARIO PLACES ----------
|
||||
|
||||
async addScenarioPlace(params: AddScenarioPlaceReq): Promise<ApiResponse<AddScenarioPlaceRsp>> {
|
||||
const { id, place } = params;
|
||||
const { data } = await this.client.post(`/api/scenarios/${id}/places`, place);
|
||||
return data;
|
||||
}
|
||||
|
||||
async updateScenarioPlace(params: UpdateScenarioPlaceReq): Promise<ApiResponse<UpdateScenarioPlaceRsp>> {
|
||||
const { id, code, place } = params;
|
||||
const { data } = await this.client.put(`/api/scenarios/${id}/places/${code}`, place);
|
||||
return data;
|
||||
}
|
||||
|
||||
async deleteScenarioPlace(params: DeleteScenarioPlaceReq): Promise<ApiResponse<DeleteScenarioPlaceRsp>> {
|
||||
const { id, code } = params;
|
||||
const { data } = await this.client.delete(`/api/scenarios/${id}/places/${code}`);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
// Единый экспорт
|
||||
export const api = new ApiClient();
|
||||
|
||||
// Экспорт типов для удобства
|
||||
export * from './generated/main';
|
||||
Reference in New Issue
Block a user