Builders Academy
REST, GraphQL et gRPC — Concevoir des APIs
1 of 1

Chapitre 1 · Leçon 1

REST API Design

Conventions, nommage, versioning et documentation

Section 1

Conventions de nommage REST

Step 1

URLs, méthodes et structure de réponse

Une bonne API REST est prévisible. Ses URLs, méthodes et réponses suivent des conventions que tout développeur peut comprendre sans documentation.

snippet.typescript

typescript
1// ✅ Conventions REST
2
3// URLs — noms au pluriel, pas de verbes
4// ❌ /getTutorials, /createTutorial, /deleteTutorialById/:id
5// ✅ /tutorials (GET = liste, POST = créer)
6// ✅ /tutorials/:id (GET = détail, PUT = remplacer, PATCH = modifier, DELETE = supprimer)
7// ✅ /tutorials/:id/chapters (sous-ressource)
8// ✅ /tutorials/:id/chapters/:chapterId/lessons
9
10// Filtrage, pagination, tri — via query params
11// GET /tutorials?level=Beginner&categorySlug=web&page=2&limit=10&sort=-publishedAt
12
13// Structure de réponse cohérente
14interface ApiResponse<T> {
15  data: T;
16  meta?: {
17    total: number;
18    page: number;
19    limit: number;
20    totalPages: number;
21  };
22}
23
24interface ApiError {
25  error: string;
26  code: string;            // Code machine pour le frontend
27  details?: Record<string, string[]>; // Erreurs de validation
28}
29
30// ✅ Pagination standardisée
31app.get("/api/v1/tutorials", async (req, res) => {
32  const { page = "1", limit = "20", level, categorySlug } = req.query;
33  const pageNum = Math.max(1, parseInt(page as string));
34  const limitNum = Math.min(100, parseInt(limit as string));
35  const skip = (pageNum - 1) * limitNum;
36
37  const [tutorials, total] = await prisma.$transaction([
38    prisma.tutorial.findMany({
39      where: { level: level as string, categorySlug: categorySlug as string },
40      skip,
41      take: limitNum,
42      orderBy: { publishedAt: "desc" },
43    }),
44    prisma.tutorial.count({
45      where: { level: level as string, categorySlug: categorySlug as string },
46    }),
47  ]);
48
49  res.json({
50    data: tutorials,
51    meta: {
52      total,
53      page: pageNum,
54      limit: limitNum,
55      totalPages: Math.ceil(total / limitNum),
56    },
57  });
58});

Step 2

Versioning et GraphQL vs REST

Quand choisir GraphQL plutôt que REST ? GraphQL brille quand le client a besoin de flexibilité sur les données ou quand les données sont fortement imbriquées.

snippet.typescript

typescript
1// ✅ Conventions REST
2
3// URLs — noms au pluriel, pas de verbes
4// ❌ /getTutorials, /createTutorial, /deleteTutorialById/:id
5// ✅ /tutorials (GET = liste, POST = créer)
6// ✅ /tutorials/:id (GET = détail, PUT = remplacer, PATCH = modifier, DELETE = supprimer)
7// ✅ /tutorials/:id/chapters (sous-ressource)
8// ✅ /tutorials/:id/chapters/:chapterId/lessons
9
10// Filtrage, pagination, tri — via query params
11// GET /tutorials?level=Beginner&categorySlug=web&page=2&limit=10&sort=-publishedAt
12
13// Structure de réponse cohérente
14interface ApiResponse<T> {
15  data: T;
16  meta?: {
17    total: number;
18    page: number;
19    limit: number;
20    totalPages: number;
21  };
22}
23
24interface ApiError {
25  error: string;
26  code: string;            // Code machine pour le frontend
27  details?: Record<string, string[]>; // Erreurs de validation
28}
29
30// ✅ Pagination standardisée
31app.get("/api/v1/tutorials", async (req, res) => {
32  const { page = "1", limit = "20", level, categorySlug } = req.query;
33  const pageNum = Math.max(1, parseInt(page as string));
34  const limitNum = Math.min(100, parseInt(limit as string));
35  const skip = (pageNum - 1) * limitNum;
36
37  const [tutorials, total] = await prisma.$transaction([
38    prisma.tutorial.findMany({
39      where: { level: level as string, categorySlug: categorySlug as string },
40      skip,
41      take: limitNum,
42      orderBy: { publishedAt: "desc" },
43    }),
44    prisma.tutorial.count({
45      where: { level: level as string, categorySlug: categorySlug as string },
46    }),
47  ]);
48
49  res.json({
50    data: tutorials,
51    meta: {
52      total,
53      page: pageNum,
54      limit: limitNum,
55      totalPages: Math.ceil(total / limitNum),
56    },
57  });
58});

Topics and skills covered

  • REST
  • API Design
  • OpenAPI
  • Versioning
  • Pagination