🧩 Schemas — Guide PRO (Web & Dev)
“Schema” = contrat + structure + règles : DB schema, JSON Schema, OpenAPI, GraphQL schema, Avro/Proto, schema.org (SEO), config schemas, migrations, versioning, validation & governance.
1
Concept & vocabulaire
schema vs data, contract, constraints
Fondations2
DB Schema (SQL)
tables, keys, constraints, namespace
DBProd3
ORM & Migrations
model schema, migrations, drift, rollback
ORM4
JSON Schema
validation, required, formats, $ref
Validation5
OpenAPI / Swagger
contract API REST, codegen, mocks
API6
GraphQL Schema
types, queries, mutations, federation
GraphQL7
Avro / Protobuf
schemas event-driven, evolution rules
Events8
Schema.org (SEO)
JSON-LD, rich snippets, entities
SEO9
Config Schemas
YAML/JSON validation, policy, IaC
Ops10
Versioning & compat
backward/forward, semver, deprecation
Gouvernance11
Pipeline de validation
request → validate → persist → publish
Qualité12
Outils & patterns
lint, tests de contrat, mocks, CI
ToolingCONCEPT
- Schema = description formelle de la forme des données + règles (types, contraintes, invariants).
- But : réduire l’ambiguïté entre systèmes (FE/BE/DB/Events) et rendre les erreurs détectables tôt.
- Trois questions : Quoi (structure) / Qui (ownership) / Quand (versioning).
+------------------------------+ | SCHEMA = CONTRAT + RÈGLES | +------------------------------+ DB: tables/constraints API: request/response types Events: message evolution SEO: structured data for bots
Règle d’or : le schema n’est pas la donnée — c’est la règle qui dit si la donnée est valide.
# Exemple “contrat” (humain) User: id: integer (required) email: string (required, email format) age: integer (optional, min 18) => Si tu ne peux pas l’exprimer clairement, le schema manque.
- Écrire le schema avant l’implémentation (“contract-first”) si l’API est publique / multi-clients.
- Mettre des exemples (valides & invalides) à côté du schema.
- Automatiser : lint → tests → génération docs → compat checks.
- “Schema = documentation approximative” (non testée) → divergence inévitable.
- Champs “any/opaque” partout → le schema ne protège plus rien.
- Breaking changes silencieux (renommage champ, changement type).
Un schema non enforced en CI/Runtime devient vite une déco.
| KPI | Pourquoi | Cible |
|---|---|---|
| % endpoints couverts par un schema | contrat explicite | 100% |
| Erreurs “validation” vs “500” | qualité des inputs | validation ↑ / 500 ↓ |
| Breaking changes / mois | stabilité | ≈ 0 |
- Chaque objet métier a un contrat (types + règles).
- Le contrat est versionné (tag, commit, registry).
- Le contrat est testé (CI) et idéalement enforced (runtime).
- Tu as une stratégie deprecation (deadline + fallback).
# Pattern utile : “valid/invalid fixtures” fixtures/ user.valid.json user.invalid_missing_email.json user.invalid_age_negative.json => tests de contrat simples, lisibles, robustes.
DB SCHEMA
- En SQL, “schema” peut vouloir dire :
- 1) La structure : tables/colonnes/types/contraintes/index.
- 2) Un namespace : ex. PostgreSQL
public,auth,reporting. - Objectif : garantir des invariants au plus près des données.
+-----------------------------+ | DB SCHEMA | +-----------------------------+ tables -> types keys -> relations constraints -> invariants indexes -> perf contracts
-- PostgreSQL (exemple) CREATE SCHEMA IF NOT EXISTS auth; CREATE TABLE auth.users ( id bigserial PRIMARY KEY, email text NOT NULL UNIQUE, created_at timestamptz NOT NULL DEFAULT now(), age int CHECK (age IS NULL OR age >= 18) ); -- Contrat : email unique, age>=18, created_at toujours renseigné
- Mettre les règles critiques en DB : NOT NULL, UNIQUE, FK, CHECK.
- Éviter que l’appli soit le seul gardien (“business rules only in code” = drift).
- Nommer et documenter les contraintes : les erreurs DB deviennent lisibles.
- Contrôler le “schema drift” (prod ≠ migrations) via CI/CD.
- Tout en
NULL+ zéro contrainte → la DB ne protège rien. - FK absentes “pour la perf” → incohérences, delete orphelins.
- Types “fourre-tout” (text/json) sans validation → dette de données.
| KPI | Cible | Action |
|---|---|---|
| Tables sans PK | 0 | Ajouter PK / surrogate key |
| Colonnes critiques NULLables | 0 | NOT NULL + backfill |
| Violations FK/UNIQUE | 0 | Fix data + constraints |
- PK sur chaque table.
- FK explicites + index associés si nécessaire.
- Contraintes CHECK pour invariants métier simples.
- Types précis (éviter text/json “par défaut”).
- Migrations idempotentes + rollback strategy.
ORM & MIGRATIONS
- Un ORM (Django/SQLAlchemy/etc.) a son propre “schema” : models + migrations.
- Risque : drift (DB réelle ≠ migrations ≠ code).
- But : garder un seul source of truth et des déploiements reproductibles.
# Exemple mental (peu importe le framework) Model User: email: string unique not null created_at: datetime default now Migration: add column / add constraint / add index Drift typique: prod a une colonne en plus ou une contrainte manquante
- CI : appliquer migrations sur une DB “from scratch” + exécuter tests.
- Pour prod : migration safe (add column nullable → backfill → set not null).
- “Expand/Contract pattern” pour changements lourds (renommage, split table, etc.).
- Monitoring : détecter les migrations lentes/verrouillantes.
Sur les grosses tables : éviter “ALTER type” bloquant, préférer shadow columns + swap.
- Modifier la DB à la main en prod puis “oublier” de créer la migration.
- Migration qui fait data + schema sans stratégie (rollback impossible).
- Renommage champ = breaking change si clients / ETL / BI existent.
- Migrations linéaires et reproductibles.
- Stratégie rollback (ou forward-only documenté).
- Validation “schema drift” automatisée (CI + check prod).
- Changements “online” pour tables volumineuses.
JSON SCHEMA
- JSON Schema décrit la forme d’un JSON : types, required, enum, formats, min/max, regex, etc.
- Usage : validation d’inputs (API), config, documents, storage JSON, contracts inter-services.
- Force : validation automatique + réutilisation via
$ref.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"additionalProperties": false,
"properties": {
"id": {"type":"integer"},
"email": {"type":"string","format":"email"},
"age": {"type":"integer","minimum":18}
},
"required": ["id","email"]
}# points clés - required = champs obligatoires - additionalProperties=false = pas de champs “surprise” - format=email = validation sémantique minimale
- Verrouiller l’objet :
additionalProperties=false(sinon dérive silencieuse). - Factoriser via
$ref(User, Money, Address…). - Avoir des fixtures “valid/invalid” et tester en CI.
- Générer documentation + exemples automatiquement.
- “type: object” sans properties → useless.
- Tout en
anyOfcomplexes → schema incompréhensible. - Formats non testés (ou faux sentiment de sécurité).
- Types + required définis.
- Règles métier simples intégrées (min/max/enum).
- Interdiction de champs inconnus si besoin.
- Tests de validation en CI.
OPENAPI
- OpenAPI décrit une API REST : endpoints, params, auth, request/response schemas, erreurs.
- Valeur : doc vivante + codegen + mocks + contract tests.
Très utile dès que tu as plusieurs clients (web + mobile + partenaires).
openapi: 3.1.0
info: { title: Users API, version: "1.0.0" }
paths:
/users/{id}:
get:
parameters:
- in: path
name: id
required: true
schema: { type: integer }
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/User"
components:
schemas:
User:
type: object
required: [id, email]
properties:
id: { type: integer }
email: { type: string, format: email }- Définir des réponses d’erreur standard (
400/401/403/404/409/422) avec schema commun. - Mettre des examples request/response (très important pour les clients).
- Bloquer les breaking changes via tooling (diff de spec en CI).
- Contract tests : serveur conforme à la spec + clients générés compilent.
- Spec écrite “après” et jamais synchronisée → faux contrat.
- “schema: {}” partout → doc inutile.
- Changements sans versionning/deprecation → chaos côté clients.
- Chaque endpoint a params + réponses typées.
- Auth documentée (bearer, api key, oauth…).
- Erreurs standardisées avec schema.
- Spec versionnée + diff check en CI.
GRAPHQL SCHEMA
- GraphQL a un schema central (SDL) : types, champs, queries/mutations, inputs, enums.
- Contrat puissant : le client sait exactement ce qu’il peut demander.
- Attention : la perf se gère (N+1, depth/complexity, caching).
type User { id: ID!, email: String!, age: Int }
type Query { user(id: ID!): User }
input CreateUserInput { email: String!, age: Int }
type Mutation { createUser(input: CreateUserInput!): User! }- Limiter la complexité : depth/complexity limits + timeouts.
- Résoudre N+1 (DataLoader pattern, batching).
- Déprécier proprement :
@deprecated(reason: "...")+ fenêtre de migration. - Registry/federation si multi-services.
- Schémas trop “DB-like” (exposer tables internes) → couplage fort.
- Aucune limite → requêtes monstrueuses / DoS applicatif.
- Champs qui changent de sens sans versioning → clients cassés.
- Schema SDL versionné.
- Déprecations tracées.
- Limits + protections perf.
- Tests de contrat (introspection + snapshot).
AVRO / PROTOBUF
- Pour l’event-driven (Kafka, Pub/Sub, RabbitMQ), le schema devient vital.
- Protobuf : contrats stricts, codegen, perf (binaire), IDs de champs.
- Avro : très utilisé en data pipelines (compat rules, schema registry).
- Problème majeur : schema evolution (backward/forward/full).
// Protobuf (extrait)
message UserCreated {
int64 id = 1;
string email = 2;
int32 age = 3; // optional by presence semantics depending on syntax/version
}# Règles d’évolution (simplifiées) - ajouter un champ : OK (si optional / default) - supprimer un champ : dangereux (préférer "deprecated") - renuméroter un field id : NON (breaking)
- Avoir un Schema Registry (même minimal) + validation à la publication.
- Politique d’évolution : backward-only vs full-compat selon tes consommateurs.
- Déprécier avant de supprimer, et attendre la fin de fenêtre de migration.
- Tester compat en CI (ex: “new schema is backward compatible”).
- Publier des events JSON sans schema → consumers fragiles.
- Breaking change silencieux → incidents cross-services.
- Pas d’ownership → “tout le monde change tout”.
- Schema versionné + registry.
- Compat checks en CI.
- Deprecation policy claire.
- Consumer tests (canaries) sur nouveaux schémas.
SCHEMA.ORG (SEO)
- Ici “schema” = données structurées pour moteurs de recherche (souvent en JSON-LD).
- But : aider Google/Bing à comprendre une page (Article, Product, Organization, FAQ…).
- Impact : rich snippets, knowledge panels, meilleure compréhension sémantique.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Schemas en dev : guide",
"author": { "@type": "Person", "name": "Guillaume" },
"datePublished": "2026-02-12"
}
</script>- Utiliser JSON-LD (simple à injecter server-side).
- Rester fidèle au contenu visible (sinon risque de pénalité).
- Tester régulièrement (données structurées) et versionner les templates.
- Mettre du schema “fake” (FAQ inventée, reviews fausses) → mauvais plan.
- Dupliquer/injecter plusieurs JSON-LD incohérents sur la même page.
- Type schema.org cohérent (Article/Product/Org…).
- Champs essentiels présents.
- Pas de divergence contenu vs markup.
CONFIG SCHEMAS
- Config schema = valider des fichiers de config (YAML/JSON) avant déploiement.
- Très utile en Ops/IaC : éviter un déploiement cassé pour une clé manquante.
- Approche : JSON Schema / validation applicative / policies (OPA) selon le niveau.
# Exemple de config "attendue"
app:
env: "prod"
port: 8080
database_url: "postgres://..."
limits:
rate_per_min: 1200
# Un schema te permet d’empêcher :
# - port string au lieu d’int
# - database_url manquant
# - env hors {dev,staging,prod}- Valider en CI (pré-merge) et au démarrage applicatif.
- Garder des defaults explicites (sinon comportement surprise).
- Documenter les “breaking config changes” (nouvelle clé requise, clé supprimée).
- Config “libre” sans validation → incidents “bêtes” en prod.
- Secrets directement dans les configs versionnées.
- Schema de config (même minimal) + validation CI.
- Defaults + required clarifiés.
- Secrets externalisés (vault/variables d’env).
VERSIONING & COMPAT
- Le vrai sujet des schemas en prod, c’est l’évolution.
- Backward compatible : les anciens consumers continuent de fonctionner.
- Forward compatible : les nouveaux consumers supportent d’anciens messages.
- Breaking change : nécessite version majeure / endpoint v2 / migration plan.
# REST (typique) - add field optional => OK - remove field => breaking - change type string->int => breaking - rename field => breaking (sauf alias/deprecation) # DB - add column nullable => OK - set NOT NULL sans backfill => risque (breaking en runtime) - drop column => breaking pour ETL/BI/old code
- Définir une policy deprecation : annonce + window + date de retrait.
- Prefer “additive changes” (ajout) plutôt que modifications destructives.
- Versionner les contrats : tags, releases, registry.
- Mettre un “compat gate” en CI : refuser un breaking change non versionné.
- “On change vite, les clients suivront” → non.
- Deprecation sans date → personne ne migre.
- Pas d’inventaire des consumers → impossible de savoir qui casse.
- Types & champs stables.
- Breaking change = version majeure ou endpoint v2.
- Deprecation documentée avec deadline.
- Compat checks automatisés.
VALIDATION PIPELINE
- Le schema doit vivre dans le flux : entrée API → validations → DB → events → analytics.
- Idéal : les erreurs de contrat deviennent des 422/400 propres, pas des 500.
Client | v API Gateway / Router | v (1) Validate request schema -----> reject 400/422 (with details) | v (2) Business rules + auth | v (3) Persist with DB constraints ---> reject 409/constraint error (mapped) | v (4) Publish event with message schema -> registry compat gate | v Consumers validate / parse -> store / act
- Validation “shape” (types/required) tôt, règles métier ensuite.
- Mapper proprement erreurs DB (unique/fk/check) vers erreurs API.
- Centraliser les contrats (repo “schemas” / registry) pour éviter la divergence.
- Tracer : quelles versions de schema sont utilisées en prod.
- Validation request/response (au moins request).
- DB constraints pour invariants critiques.
- Contrat event (schema evolution gérée).
- Observabilité des erreurs de validation.
TOOLS & PATTERNS
- Pattern “contract-first” : spec → mocks → impl → tests → clients.
- Pattern “contract-tests” : vérifier automatiquement la conformité (producer/consumer).
- Pattern “schema registry” : un référentiel, un ownership, des règles d’évolution.
# Idées d’automatisation (CI) - Lint schema (format + conventions) - Validate fixtures (valid/invalid) - Diff compat (old vs new) - Generate docs (HTML/markdown) - Generate clients (si besoin) - Publish schema artifact (registry)
# “Contract tests” minimalistes Given: OpenAPI/JSON Schema When: run tests against API Then: responses match schemas + required fields are present
- Nommer les objets : User vs UserV2 (éviter V2 trop tôt, préférer compat).
- Éviter les duplications : un schema “User” réutilisé partout via ref.
- Limiter les “any/unknown” aux zones réellement extensibles.
- Mettre des “examples” dans les schemas (accélère FE & QA).
- Docs séparées du schema → drift.
- Règles d’évolution implicites (“au feeling”).
- Aucune ownership → personne n’ose dire non aux breaking changes.
- Repo/registry des schemas + ownership.
- Compat gate en CI.
- Fixtures valid/invalid.
- Docs auto + exemples.
RÉFÉRENCES
- Quand tu dis “schema”, précise le contexte : DB / JSON / API / GraphQL / Events / SEO.
- Le bon réflexe : contract + validation + versioning.
- JSON Schema (spec + drafts)
- OpenAPI (3.0/3.1) + tooling codegen
- GraphQL SDL + deprecations
- Protocol Buffers / Avro + schema evolution
- schema.org + JSON-LD
Tu peux compléter cette liste avec tes liens internes Ideo-Lab (guides API, DB, ETL, SEO).
- Contrats centralisés + ownership.
- Validation automatisée (CI) + erreurs propres (runtime).
- Versioning & compat (deprecation policy).
CHEAT-SHEET
SCHEMA (web/dev) = règle qui décrit la structure des données. DB schema : tables/colonnes/types/contraintes (+ schema namespace) JSON Schema : validation de JSON (required, types, $ref) OpenAPI : contrat API REST (request/response/errors) GraphQL schema : types/queries/mutations (+ deprecations) Avro/Proto : contrat events/messages + evolution rules schema.org : données structurées SEO (JSON-LD)
SAFE (souvent) : - ajouter un champ optional - ajouter une colonne nullable - ajouter un nouvel endpoint / nouveau type BREAKING (souvent) : - supprimer/renommer un champ - changer type string->int - rendre obligatoire un champ sans default/backfill - supprimer une colonne utilisée par ETL/BI
“Pour moi un schema, c’est un contrat formel : 1) il définit les types et contraintes, 2) il est validé automatiquement (CI + runtime), 3) il est versionné avec une politique de compatibilité. Ça évite les ambiguïtés FE/BE/DB et réduit les incidents de prod.”
