-- NORMAL -- ~/projets/trekker.md projet 05 / 06

trekker

Une API de randonnées où chaque requête passe d’abord au gabarit du contrat partagé.

Stack
TypeScript · NestJS · Drizzle
Année
2026
Dépôt
github.com/Popoch39/trekker ↗
A

Anatomie

8 pièces · une seule les compte
Fig. 1 Meuble à fiches et gabarit Zod
01234567890012345678900123456789001234567890/v1/treks
  1. 01GET /api/v1/treksL8–24 ↗

    Recevoir la demande

    Reçoit la demande de liste ; sans session ouverte, l’API répond 401.

    TreksController

    15@ApiTags('treks')

    16@Controller('treks')

    17export class TreksController {

  2. 02pageSize ≤ 100L126–185 ↗

    Vérifier chaque paramètre

    Un seul contrat pour l’API, le web et le mobile : filtres, position, 100 par page.

    trekListQuerySchema

    133export const trekListQuerySchema = paginationQuerySchema

    134 .extend({

    135 difficulty: trekDifficultySchema.optional(),

  3. Refuser une demande fausse

    Répond 422 avec la liste des champs fautifs, au format standard RFC 9457.

    ZodValidationException

    52if (exception instanceof ZodValidationException) {

    53 return {

    54 ...base,

  4. 04limit / offsetL127–151 ↗

    Découper une page

    Trie par nom puis id, saute les pages précédentes et garde 20 itinéraires.

    toLimitOffset()

    127const where = conditions.length > 0 ? and(...conditions) : undefined;

    128const { limit, offset } = toLimitOffset(query);

    130const [rows, total] = await Promise.all([

  5. 05Promise.allL152–160 ↗

    Compter les résultats

    Compte tous les résultats en même temps : 100 itinéraires donnent 5 pages.

    $count()

    154 this.db.$count(treks, where),

    155]);

    157return {

  6. 06toSummary()L49–74 ↗

    Alléger chaque résultat

    Sert nom, distance et dénivelé sans la trace GPS, trop lourde pour une liste.

    trekSummarySchema

    55export const trekSummarySchema = entityBaseSchema.extend({

    56 name: nonEmptyString,

    57 distanceMeters: z.int().min(0),

  7. 07index(name, id)L142–148 ↗

    Accélérer le tri

    Un index sur nom puis id : 0,9 ms au lieu de 130 ms par page, sur 2 442 itinéraires.

    treks_name_id_idx

    148index('treks_name_id_idx').on(table.name, table.id),

  8. 08pgTable('treks')L57–91 ↗

    Stocker les itinéraires

    Une table Postgres : une ligne par itinéraire, avec sa trace et son départ.

    treks

    57export const treks = pgTable(

    58 'treks',

    59 {

GET ?page=1 → 200 · 20 fiches · p. 1/5 · total 100
Lecture des notes

Tirez une poignée pour demander sa pageFaites glisser un tiroir vers vous pour demander sa page

Fig. 1 — Chaque tiroir est une page de 20 itinéraires sur les 100 de la fixture livrée. La fiche de demande passe d’abord au gabarit, trekListQuerySchema, le contrat Zod que partagent l’API, le web et le mobile : une proximité incomplète ou une page de plus de 100 fiches finit au bac de rejet, en 422. Les fiches tiennent sur la tige dans l’ordre name, id, que suit l’index treks_name_id_idx (0,9 ms au lieu de 130 sur 2 442 treks), et sortent sans leur tracé.

Nomen­clature

  1. 01 Fente à serrure Reçoit la fiche de demande ; la serrure exige une session. Code : apps/api/src/modules/treks/treks.controller.ts, lignes 8–24 ↗
  2. 02 Gabarit à broches Vérifie chaque champ de la fiche de demande et ses verrous avant de la laisser passer. Code : packages/contracts/src/treks.ts, lignes 126–185 ↗
  3. 03 Bac de rejet Recueille la fiche refusée, avec le détail des champs fautifs. Code : apps/api/src/common/filters/problem-details.filter.ts, lignes 52–61 ↗
  4. 04 Tige et presse-fiches Tient les fiches dans l’ordre name, id ; le presse-fiches en isole vingt, après celles des tiroirs précédents. Code : apps/api/src/modules/treks/treks.service.ts, lignes 127–151 ↗
  5. 05 Totalisateur Compte toutes les fiches qui répondent, pendant que le tiroir sort, et en déduit le nombre de pages. Code : apps/api/src/modules/treks/treks.service.ts, lignes 152–160 ↗
  6. 06 Fiche résumé Ce qui sort du tiroir : la fiche sans son tracé, qui reste au fond. Code : packages/contracts/src/treks.ts, lignes 49–74 ↗
  7. 07 Glissières à billes Font sortir le tiroir sans qu’on trie le meuble. Code : packages/db/src/schema/treks.ts, lignes 142–148 ↗
  8. 08 Corps à tiroirs Le meuble lui-même : chaque fiche y est rangée une fois. Code : packages/db/src/schema/treks.ts, lignes 57–91 ↗