Introduction
La synchronisation entre le frontend et le backend est un défi constant dans les applications modernes. Les contrats d’API évoluent, les types changent, et maintenir manuellement la couche API devient rapidement une source d’erreurs. RTK Query, combiné avec la génération automatique depuis OpenAPI/Swagger, offre une solution élégante à ce problème.
Dans cet article, nous allons explorer comment automatiser complètement la génération de notre couche API Redux Toolkit Query à partir de notre documentation Swagger backend.
Pourquoi automatiser la génération ?
Les avantages
- Type safety garantie : Les types TypeScript sont générés directement depuis la spec OpenAPI
- Synchronisation automatique : Chaque modification backend se reflète immédiatement côté frontend
- Moins d’erreurs : Élimination des erreurs de typage manuel
- Gain de temps : Plus besoin d’écrire manuellement les endpoints et types
- Documentation vivante : Le code généré est toujours en phase avec la spec
Configuration initiale
Installation des dépendances
npm install @reduxjs/toolkit react-redux
npm install -D @rtk-query/codegen-openapi
Configuration du fichier de génération
Créez un fichier openapi-config.ts à la racine du projet :
import type { ConfigFile } from '@rtk-query/codegen-openapi';
const config: ConfigFile = {
schemaFile: 'https://api.votre-backend.com/swagger.json',
apiFile: './src/store/emptyApi.ts',
apiImport: 'emptySplitApi',
outputFile: './src/store/api.ts',
exportName: 'api',
hooks: true,
tag: true,
};
export default config;
Création de l’API de base
Créez le fichier src/store/emptyApi.ts :
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
export const emptySplitApi = createApi({
baseQuery: fetchBaseQuery({ baseUrl: 'https://api.votre-backend.com' }),
endpoints: () => ({}),
});
Génération de l’API
Commande de génération
Ajoutez dans votre package.json :
{
"scripts": {
"generate:api": "rtk-query-codegen-openapi openapi-config.ts"
}
}
Exécutez la génération :
npm run generate:api
Résultat généré
Le fichier src/store/api.ts sera automatiquement créé avec tous vos endpoints :
import { emptySplitApi as api } from "./emptyApi";
const injectedRtkApi = api.injectEndpoints({
endpoints: (build) => ({
getUsers: build.query<GetUsersApiResponse, GetUsersApiArg>({
query: (queryArg) => ({ url: `/users`, params: queryArg }),
}),
getUserById: build.query<GetUserByIdApiResponse, GetUserByIdApiArg>({
query: (queryArg) => ({ url: `/users/${queryArg.id}` }),
}),
createUser: build.mutation<CreateUserApiResponse, CreateUserApiArg>({
query: (queryArg) => ({ url: `/users`, method: 'POST', body: queryArg.body }),
}),
// ... tous les autres endpoints
}),
overrideExisting: false,
});
export { injectedRtkApi as api };
export const { useGetUsersQuery, useGetUserByIdQuery, useCreateUserMutation } = injectedRtkApi;
Utilisation dans les composants
Requête simple
import { useGetUsersQuery } from '@/store/api';
function UsersList() {
const { data, isLoading, error } = useGetUsersQuery({ page: 1, limit: 10 });
if (isLoading) return <div>Chargement...</div>;
if (error) return <div>Erreur</div>;
return (
<ul>
{data?.users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Mutation
import { useCreateUserMutation } from '@/store/api';
function CreateUserForm() {
const [createUser, { isLoading }] = useCreateUserMutation();
const handleSubmit = async (formData: UserInput) => {
try {
await createUser({ body: formData }).unwrap();
// Success
} catch (error) {
// Error handling
}
};
return <form onSubmit={handleSubmit}>...</form>;
}
Personnalisation avancée
Ajout de tags pour le cache invalidation
Modifiez openapi-config.ts pour inclure la logique de tags :
const config: ConfigFile = {
// ... config précédente
tag: true,
endpointOverrides: [
{
pattern: 'getUsers',
type: 'query',
providesTags: ['User'],
},
{
pattern: 'createUser',
type: 'mutation',
invalidatesTags: ['User'],
},
],
};
Transformation des réponses
Vous pouvez étendre les endpoints générés :
import { api } from './api';
export const enhancedApi = api.enhanceEndpoints({
endpoints: {
getUsers: {
transformResponse: (response) => {
return response.users.map(user => ({
...user,
fullName: `${user.firstName} ${user.lastName}`,
}));
},
},
},
});
Intégration dans le workflow
Script pre-commit
Ajoutez un hook Git pour générer automatiquement l’API :
{
"husky": {
"hooks": {
"pre-commit": "npm run generate:api && git add src/store/api.ts"
}
}
}
CI/CD
Intégrez la vérification dans votre pipeline :
- name: Generate API
run: npm run generate:api
- name: Check for changes
run: |
git diff --exit-code src/store/api.ts || \
(echo "API not in sync with OpenAPI spec" && exit 1)
Conclusion
L’automatisation de la génération RTK Query depuis Swagger/OpenAPI transforme radicalement la façon dont nous maintenons la synchronisation frontend/backend. Cette approche élimine une classe entière d’erreurs, accélère le développement et garantit que notre code reste toujours en phase avec les contrats d’API.
Les bénéfices sont immédiats : type safety garantie, moins de code boilerplate, et un workflow de développement plus fluide. Si vous utilisez déjà RTK Query, l’adoption de la génération automatique est une évolution naturelle qui paiera rapidement ses dividendes.
Points clés à retenir :
- La génération automatique élimine les erreurs de synchronisation
- Le type safety TypeScript est garanti par la spec OpenAPI
- L’intégration dans le workflow (hooks, CI/CD) assure la cohérence
- La personnalisation reste possible via les overrides et extensions