CLI утилита для генерации TypeScript API клиента из OpenAPI спецификации. - Поддержка локальных файлов и URL для спецификаций - Кастомизация имени выходного файла через флаг --name - Генерация типизированного клиента с SWR хуками - Минимальный вывод логов для лучшего UX
283 lines
7.8 KiB
TypeScript
283 lines
7.8 KiB
TypeScript
/**
|
||
* Примеры использования сгенерированных use* функций
|
||
* с SWR и React Query
|
||
*/
|
||
|
||
import { Api, HttpClient } from './output/Api';
|
||
import useSWR from 'swr';
|
||
import { useQuery } from '@tanstack/react-query';
|
||
|
||
// ============================================
|
||
// НАСТРОЙКА API КЛИЕНТА
|
||
// ============================================
|
||
|
||
const httpClient = new HttpClient({
|
||
baseUrl: 'https://cdn.example.com',
|
||
});
|
||
|
||
// Устанавливаем токен (например, из localStorage)
|
||
if (typeof window !== 'undefined') {
|
||
const token = localStorage.getItem('auth_token');
|
||
if (token) {
|
||
httpClient.setSecurityData({ token });
|
||
}
|
||
}
|
||
|
||
const api = new Api(httpClient);
|
||
|
||
// ============================================
|
||
// ПРИМЕР 1: ИСПОЛЬЗОВАНИЕ С SWR
|
||
// ============================================
|
||
|
||
// Простой GET запрос без параметров
|
||
function UserProfile() {
|
||
const profileConfig = api.auth.useGetProfile();
|
||
|
||
const { data, error, isLoading } = useSWR(
|
||
profileConfig.path, // Ключ для кеша
|
||
() => api.auth.getProfile() // Функция для загрузки данных
|
||
);
|
||
|
||
if (isLoading) return <div>Загрузка...</div>;
|
||
if (error) return <div>Ошибка: {error.message}</div>;
|
||
if (!data) return null;
|
||
|
||
return (
|
||
<div>
|
||
<h1>Профиль пользователя</h1>
|
||
<p>Email: {data.email}</p>
|
||
<p>Имя: {data.firstName} {data.lastName}</p>
|
||
<p>Email подтверждён: {data.isEmailVerified ? 'Да' : 'Нет'}</p>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// GET запрос с параметрами
|
||
function ProjectDetails({ projectId }: { projectId: string }) {
|
||
const projectConfig = api.projects.useFindOne({ id: projectId });
|
||
|
||
const { data: project, error, isLoading } = useSWR(
|
||
[projectConfig.path, projectId], // Составной ключ
|
||
() => api.projects.findOne({ id: projectId })
|
||
);
|
||
|
||
if (isLoading) return <div>Загрузка проекта...</div>;
|
||
if (error) return <div>Ошибка: {error.message}</div>;
|
||
if (!project) return null;
|
||
|
||
return (
|
||
<div>
|
||
<h2>{project.name}</h2>
|
||
<p>{project.description}</p>
|
||
<p>Bucket: {project.s3Bucket}</p>
|
||
<p>Region: {project.s3Region}</p>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// Список с автоматической ревалидацией
|
||
function ProjectsList() {
|
||
const projectsConfig = api.projects.useFindAll();
|
||
|
||
const { data: projects, error, isLoading, mutate } = useSWR(
|
||
projectsConfig.path,
|
||
() => api.projects.findAll(),
|
||
{
|
||
refreshInterval: 5000, // Обновлять каждые 5 секунд
|
||
revalidateOnFocus: true, // Обновлять при фокусе на окно
|
||
}
|
||
);
|
||
|
||
const handleCreateProject = async () => {
|
||
await api.projects.create({
|
||
name: 'Новый проект',
|
||
description: 'Описание',
|
||
});
|
||
|
||
// Обновляем список
|
||
mutate();
|
||
};
|
||
|
||
if (isLoading) return <div>Загрузка списка...</div>;
|
||
if (error) return <div>Ошибка: {error.message}</div>;
|
||
|
||
return (
|
||
<div>
|
||
<h2>Мои проекты ({projects?.length || 0})</h2>
|
||
<button onClick={handleCreateProject}>Создать проект</button>
|
||
<ul>
|
||
{projects?.map((project) => (
|
||
<li key={project.id}>
|
||
{project.name} - {project.slug}
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// ============================================
|
||
// ПРИМЕР 2: ИСПОЛЬЗОВАНИЕ С REACT QUERY
|
||
// ============================================
|
||
|
||
function UserProfileWithReactQuery() {
|
||
const profileConfig = api.auth.useGetProfile();
|
||
|
||
const { data, error, isLoading } = useQuery({
|
||
queryKey: [profileConfig.path],
|
||
queryFn: () => api.auth.getProfile(),
|
||
});
|
||
|
||
if (isLoading) return <div>Загрузка...</div>;
|
||
if (error) return <div>Ошибка</div>;
|
||
|
||
return (
|
||
<div>
|
||
<h1>{data?.firstName} {data?.lastName}</h1>
|
||
<p>{data?.email}</p>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
function ProjectsListWithReactQuery() {
|
||
const projectsConfig = api.projects.useFindAll();
|
||
|
||
const { data: projects, isLoading } = useQuery({
|
||
queryKey: [projectsConfig.path],
|
||
queryFn: () => api.projects.findAll(),
|
||
staleTime: 5 * 60 * 1000, // 5 минут
|
||
refetchInterval: 30000, // Обновлять каждые 30 секунд
|
||
});
|
||
|
||
if (isLoading) return <div>Загрузка...</div>;
|
||
|
||
return (
|
||
<div>
|
||
<h2>Проекты</h2>
|
||
{projects?.map((p) => (
|
||
<div key={p.id}>{p.name}</div>
|
||
))}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// ============================================
|
||
// ПРИМЕР 3: УСЛОВНАЯ ЗАГРУЗКА
|
||
// ============================================
|
||
|
||
function ConditionalProfile({ userId }: { userId?: string }) {
|
||
const profileConfig = api.auth.useGetProfile();
|
||
|
||
const { data } = useSWR(
|
||
// Загружаем только если есть userId
|
||
userId ? profileConfig.path : null,
|
||
() => api.auth.getProfile()
|
||
);
|
||
|
||
return data ? <div>{data.email}</div> : null;
|
||
}
|
||
|
||
// ============================================
|
||
// ПРИМЕР 4: ЗАВИСИМЫЕ ЗАПРОСЫ
|
||
// ============================================
|
||
|
||
function DependentQueries() {
|
||
// Сначала получаем список проектов
|
||
const projectsConfig = api.projects.useFindAll();
|
||
const { data: projects } = useSWR(
|
||
projectsConfig.path,
|
||
() => api.projects.findAll()
|
||
);
|
||
|
||
// Затем получаем первый проект (только когда список загружен)
|
||
const firstProjectId = projects?.[0]?.id;
|
||
const projectConfig = firstProjectId
|
||
? api.projects.useFindOne({ id: firstProjectId })
|
||
: null;
|
||
|
||
const { data: firstProject } = useSWR(
|
||
projectConfig ? [projectConfig.path, firstProjectId] : null,
|
||
() => firstProjectId ? api.projects.findOne({ id: firstProjectId }) : null
|
||
);
|
||
|
||
return (
|
||
<div>
|
||
<h3>Всего проектов: {projects?.length || 0}</h3>
|
||
{firstProject && (
|
||
<div>
|
||
<h4>Первый проект:</h4>
|
||
<p>{firstProject.name}</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// ============================================
|
||
// ПРИМЕР 5: СОЗДАНИЕ ХУКА-ОБЁРТКИ
|
||
// ============================================
|
||
|
||
// Универсальный хук для всех GET запросов
|
||
function useApiQuery<T>(
|
||
useConfigFn: () => { path: string; method: 'GET'; secure?: boolean },
|
||
apiFn: () => Promise<T>,
|
||
options?: Parameters<typeof useSWR>[2]
|
||
) {
|
||
const config = useConfigFn();
|
||
return useSWR<T>(config.path, apiFn, options);
|
||
}
|
||
|
||
// Использование
|
||
function MyComponent() {
|
||
const { data, error, isLoading } = useApiQuery(
|
||
api.auth.useGetProfile,
|
||
api.auth.getProfile,
|
||
{ revalidateOnFocus: true }
|
||
);
|
||
|
||
// ...
|
||
}
|
||
|
||
// ============================================
|
||
// ПРИМЕР 6: ПОЛЬЗОВАТЕЛЬСКИЙ FETCHER ДЛЯ SWR
|
||
// ============================================
|
||
|
||
// Создаём универсальный fetcher
|
||
const apiFetcher = async (key: string | string[]) => {
|
||
const path = Array.isArray(key) ? key[0] : key;
|
||
|
||
// Находим соответствующий метод API
|
||
// В реальном приложении можно использовать маппинг
|
||
return api.auth.getProfile(); // пример
|
||
};
|
||
|
||
// SWRConfig для всего приложения
|
||
import { SWRConfig } from 'swr';
|
||
|
||
function App() {
|
||
return (
|
||
<SWRConfig
|
||
value={{
|
||
fetcher: apiFetcher,
|
||
revalidateOnFocus: false,
|
||
dedupingInterval: 2000,
|
||
}}
|
||
>
|
||
<UserProfile />
|
||
<ProjectsList />
|
||
</SWRConfig>
|
||
);
|
||
}
|
||
|
||
export {
|
||
UserProfile,
|
||
ProjectDetails,
|
||
ProjectsList,
|
||
UserProfileWithReactQuery,
|
||
ProjectsListWithReactQuery,
|
||
ConditionalProfile,
|
||
DependentQueries,
|
||
useApiQuery,
|
||
};
|
||
|