Comment créer une route ressource

La route ressource te permet de créer un endpoint API te permettant de renvoyer une réponse au format JSON, PDF, XML, CSV ... À peu près tous les formats imaginables qu'un serveur peut renvoyer. Pour la mettre en place, il suffit de ne pas exporter de composant React par défaut.

4 min read
Déverrouillez votre potentiel

avec React Router 7

Vous en avez marre de...

❌ perdre du temps à chercher des informations éparpillées
❌ ne pas avoir de retour sur votre progression
Assistant IA spécialisé

Posez vos questions 24/7 à notre IA experte en React Router 7

Quiz interactifs

Validez vos acquis avec des quiz personnalisés et un feedback instantané

9 modules
45 leçons
Accès à vie
299.00
-50%

Dans React Router 7, une route ressource (resource route) n’affiche pas de composant React, mais renvoie directement une réponse HTTP (JSON, CSV, PDF, XML, etc.). C’est idéal pour proposer une API interne ou générer un fichier à télécharger (sitemap, robots.txt, export de données, etc.).

Tu vas apprendre à :

  1. Créer une route JSON avec Response.json.
  2. Générer un CSV et un PDF via new Response.
  3. Déclarer ces routes dans app/routes.ts.
  4. Ajouter des liens <Link reloadDocument> pour forcer le téléchargement.

1. Route JSON avec Response.json

1.1. Créer le fichier de route

app/routes/users.json.tsx
1
import { getUsers } from '~/users.server';
2
import type { LoaderFunctionArgs } from 'react-router';
3
4
// @callout: La fonction loader renvoie du JSON directement
5
export async function loader({}: LoaderFunctionArgs) {
6
// ^? Méthode utilitaire pour JSON et headers par défaut
7
return Response.json(
8
{ users: await getUsers() },
9
{
10
headers: {
11
'Cache-Control': 'public, max-age=3600', // ^? Mise en cache 1 heure
12
},
13
}
14
);
15
}

1.2. Déclarer la route

app/routes.ts
1
import { type RouteConfig, index, route } from '@react-router/dev/routes';
2
3
export default [
4
index('routes/home.tsx'),
5
// ^? Route JSON à la racine
6
route('users.json', 'routes/users.json.tsx'),
7
] satisfies RouteConfig;

2. Export CSV manuellement

2.1. Fichier CSV

app/routes/users.csv.tsx
1
import { getUsers } from '~/users.server';
2
3
// @callout: Génère une chaîne CSV à partir d’un tableau
4
export async function loader() {
5
const users = await getUsers();
6
// 1. Entête
7
let csv = ['id', 'name', 'slug'].join(',') + '\r\n';
8
// 2. Lignes de données
9
users.forEach((u) => {
10
csv += [u.id, u.name, u.slug].join(',') + '\r\n';
11
});
12
13
return new Response(csv, {
14
headers: {
15
'Content-Type': 'text/csv',
16
'Content-Disposition': `attachment; filename="users.csv"`,
17
},
18
});
19
}

2.2. Déclaration dans routes.ts

app/routes.ts
1
import { type RouteConfig, index, route } from '@react-router/dev/routes';
2
3
export default [
4
index('routes/home.tsx'),
5
route('users.json', 'routes/users.json.tsx'),
6
route('users.csv', 'routes/users.csv.tsx'),
7
] satisfies RouteConfig;

3. Générez un PDF avec PDFKit

3.1. Installer PDFKit

Terminal
1
npm install pdfkit @types/pdfkit

3.2. Route PDF

app/routes/users.pdf.tsx
1
import PDFDocument from 'pdfkit';
2
import { getUsers } from '~/users.server';
3
4
// @callout: PDFKit génère un flux de données PDF
5
export async function loader() {
6
const users = await getUsers();
7
const doc = new PDFDocument();
8
const chunks: Uint8Array[] = [];
9
10
doc.on('data', (chunk) => chunks.push(chunk));
11
doc.fontSize(16).text('Users list', { align: 'center' }).moveDown();
12
13
users.forEach((u) => {
14
doc.fontSize(12).text(`${u.id}: ${u.name}`).moveDown(0.5);
15
});
16
17
doc.end();
18
19
// ^? Attendre la fin du flux avant de répondre
20
return new Promise<Response>((resolve) => {
21
doc.on('end', () => {
22
const pdfBuffer = Buffer.concat(chunks);
23
resolve(
24
new Response(pdfBuffer, {
25
headers: {
26
'Content-Type': 'application/pdf',
27
'Content-Disposition': `attachment; filename="users.pdf"`,
28
},
29
})
30
);
31
});
32
});
33
}

3.3. Ajouter dans routes.ts

app/routes.ts
1
import { type RouteConfig, index, route } from '@react-router/dev/routes';
2
3
export default [
4
index('routes/home.tsx'),
5
route('users.json', 'routes/users.json.tsx'),
6
route('users.csv', 'routes/users.csv.tsx'),
7
route('users.pdf', 'routes/users.pdf.tsx'),
8
] satisfies RouteConfig;

4. Lier dans le layout

Pour permettre à l’utilisateur de télécharger ces fichiers, ajoute des liens avec reloadDocument :

app/routes/_usersLayout.tsx
1
import { Link, href, Outlet, useLoaderData } from 'react-router';
2
import { getUsers } from '~/users.server';
3
4
export default function UsersLayout() {
5
const users = useLoaderData<typeof loader>().users;
6
return (
7
<div>
8
<nav className="flex gap-2">
9
<Link to={href('/users.json')} reloadDocument className="btn">
10
JSON
11
</Link>
12
<Link to={href('/users.csv')} reloadDocument className="btn">
13
CSV
14
</Link>
15
<Link to={href('/users.pdf')} reloadDocument className="btn">
16
PDF
17
</Link>
18
</nav>
19
<Outlet />
20
</div>
21
);
22
}

Points clés

  • Une route ressource n’exporte pas de composant par défaut.
  • Utilise Response.json(...) ou new Response(...) pour contrôler le body et les headers.
  • Déclare ces routes au même niveau que tes pages (app/routes.ts).
  • <Link reloadDocument> force le téléchargement de l’API/fichier.
  • Très utile pour exposer un sitemap.xml, robots.txt, ou des API simples.

Exercices rapides

  1. Crée une route /sitemap.xml qui renvoie un plan de site au format XML (éléments <url>).
  2. Gère une route robots.txt statique via new Response(...) et ajoute-la dans le layout root.
  3. Simule une route ressource /api/avatar.png qui renvoie une image binaire stockée dans public/.
Premium
Quiz interactif
Testez vos connaissances et validez votre compréhension du module avec notre quiz interactif.
1

Comprendre les concepts fondamentaux

Quelle est la principale différence entre les composants client et serveur dans React ?

Les composants client s'exécutent uniquement dans le navigateur
Les composants serveur peuvent utiliser useState
Les composants client sont plus rapides
Il n'y a aucune différence significative
2

Optimisation des performances

Quelle technique est recommandée pour éviter les rendus inutiles dans React ?

Utiliser React.memo pour les composants fonctionnels
Ajouter plus d'états locaux
Éviter d'utiliser les props
Toujours utiliser les class components
3

Architecture des données

Quel hook permet de gérer les effets de bord dans un composant React ?

useEffect
useState
useMemo
useContext
4

Gestion des erreurs

Comment implémenter la gestion des erreurs pour les requêtes API dans React ?

Utiliser try/catch avec async/await
Ignorer les erreurs
Toujours afficher un message d'erreur
Rediriger l'utilisateur
5

Déploiement et CI/CD

Quelle est la meilleure pratique pour déployer une application React en production ?

Utiliser un service CI/CD comme GitHub Actions
Copier les fichiers manuellement via FTP
Envoyer le code source complet
Ne jamais mettre à jour l'application

Débloquez ce quiz et tous les autres contenus premium en achetant ce cours