💻 Développement

dev-openapi-contract-first

Design d'API Contract-First avec OpenAPI/Swagger, génération de code, validation de contrats et documentation interactive.

⚡ Installation & lancement en 1 commande

Copiez-collez dans votre terminal : le skill s'installe dans ~/.claude/skills et Claude Code se lance directement dessus.

macOS / Linux
curl -fsSL https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.sh | sh -s -- dev-openapi-contract-first --launch
Windows (PowerShell)
iex "& { $(iwr -useb https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.ps1) } dev-openapi-contract-first -Launch"

🚀 Déjà installé ?

claude "/dev-openapi-contract-first"

Ou tapez /dev-openapi-contract-first dans une session Claude Code, ou décrivez simplement votre besoin — le skill se déclenche automatiquement via le skill-router.

🔑 Déclencheurs automatiques

Le skill s'active automatiquement quand votre demande contient :

OpenAPISwaggercontract firstspécification APIopenapi.yamlswagger.jsongénération de code API

📦 Installation manuelle

git clone https://github.com/khalilbenaz/claude-skills-collection.git cp -r claude-skills-collection/skills/dev-openapi-contract-first ~/.claude/skills/

Payload du plugin : skills/dev-openapi-contract-first · source éditable : dev-skills/openapi-contract-first

📖 Manuel

Design API Contract-First avec OpenAPI

Workflow en étapes

  1. Choisir la version OpenAPI — utiliser 3.1.0 pour tout nouveau projet (support JSON Schema complet, nullable remplacé par type: [string, 'null']). Rester sur 3.0.x uniquement si l'outillage cible ne supporte pas encore 3.1.
  2. Rédiger la spec avant le code — commencer par les paths, les schemas required, les codes d'erreur. Ne pas générer la spec depuis le code existant : c'est du code-first déguisé.
  3. Valider et linter la spec (Spectral) avant tout commit.
  4. Faire reviewer par les consommateurs — frontend, mobile, partenaires — avant de freezer le contrat.
  5. Générer serveur et/ou client depuis la spec validée.
  6. Implémenter derrière le contrat généré ; l'implémentation ne doit jamais diverger du contrat.
  7. Détecter les breaking changes en CI avant chaque PR mergée.
  8. Publier la doc interactive (Swagger UI, Redoc, Scalar).

Structure de référence (OpenAPI 3.1)

openapi: 3.1.0
info:
  title: Payment API
  version: 1.0.0
  contact:
    name: Équipe Paiements
    email: payments@company.com

servers:
  - url: https://api.company.com/v1
    description: Production
  - url: https://api-staging.company.com/v1
    description: Staging

paths:
  /payments:
    post:
      operationId: createPayment   # OBLIGATOIRE — utilisé pour nommer la méthode générée
      summary: Créer un paiement
      tags: [Payments]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePaymentRequest'
            example:
              amount: 5000
              currency: EUR
              recipient_id: usr_abc123
      responses:
        '201':
          description: Paiement créé
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Payment'
        '400':
          $ref: '#/components/responses/BadRequest'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'

    get:
      operationId: listPayments
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/LimitParam'
      responses:
        '200':
          description: Liste paginée
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentList'

components:
  schemas:
    CreatePaymentRequest:
      type: object
      required: [amount, currency, recipient_id]
      properties:
        amount:
          type: integer
          minimum: 1
          description: Montant en centimes
        currency:
          type: string
          enum: [EUR, USD, GBP]
        recipient_id:
          type: string
          pattern: '^usr_[a-zA-Z0-9]+$'

    Payment:
      type: object
      required: [id, amount, currency, status, created_at]
      properties:
        id:
          type: string
          format: uuid
        amount:
          type: integer
        currency:
          type: string
        status:
          $ref: '#/components/schemas/PaymentStatus'
        created_at:
          type: string
          format: date-time

    PaymentStatus:
      type: string
      enum: [pending, processing, completed, failed]

    PaymentList:
      type: object
      required: [data, pagination]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Payment'
        pagination:
          $ref: '#/components/schemas/Pagination'

    Pagination:
      type: object
      required: [page, limit, total]
      properties:
        page:
          type: integer
        limit:
          type: integer
        total:
          type: integer

    Error:
      type: object
      required: [code, message]
      properties:
        code:
          type: string
        message:
          type: string
        details:
          type: array
          items:
            type: object

  parameters:
    PageParam:
      name: page
      in: query
      schema:
        type: integer
        default: 1
        minimum: 1
    LimitParam:
      name: limit
      in: query
      schema:
        type: integer
        default: 20
        minimum: 1
        maximum: 100

  responses:
    BadRequest:
      description: Requête invalide
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    UnprocessableEntity:
      description: Données non traitables
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

security:
  - BearerAuth: []

Validation et linting

# Linting Spectral (règles OpenAPI + règles customs)
npx @stoplight/spectral-cli lint openapi.yaml --ruleset .spectral.yaml

# Valider la syntaxe seule
npx @apidevtools/swagger-parser validate openapi.yaml

# Détecter les breaking changes entre deux versions
oasdiff breaking openapi-v1.yaml openapi-v2.yaml
oasdiff breaking openapi-v1.yaml openapi-v2.yaml --fail-on ERR  # sortie non-zéro = CI fail

Règleset Spectral minimal .spectral.yaml :

extends: ['spectral:oas']
rules:
  operation-operationId: error
  operation-tags: warn
  oas3-api-servers: error

Génération de code

.NET — NSwag

# Client C#
nswag openapi2csclient \
  /input:openapi.yaml \
  /output:PaymentApiClient.cs \
  /namespace:MyApp.ApiClients \
  /className:PaymentApiClient \
  /generateClientInterfaces:true

# Contrôleur serveur (interface + stub)
nswag openapi2cscontroller \
  /input:openapi.yaml \
  /output:PaymentControllerBase.cs \
  /namespace:MyApp.Controllers \
  /controllerBaseClass:ControllerBase

TypeScript

# Types seuls (léger, recommandé pour fetch natif)
npx openapi-typescript openapi.yaml -o ./src/api/schema.d.ts

# Client complet (fetch)
npx @openapitools/openapi-generator-cli generate \
  -i openapi.yaml -g typescript-fetch -o ./src/api/client \
  --additional-properties=supportsES6=true,npmVersion=10

Java / Spring Boot

openapi-generator-cli generate \
  -i openapi.yaml -g spring \
  -o ./generated \
  --additional-properties=interfaceOnly=true,useSpringBoot3=true

Critères de décision

SituationRecommandation
Nouvelle API, équipe multi-stackContract-First obligatoire
API existante à documenterGénérer la spec depuis code (code-first), puis migrer vers contract-first
Partenaires externes consomment l'APIVersionner dans l'URL (/v1/), publier Redoc/Scalar
Micro-changement non-breakingOK sans bump de version majeure
Changement breaking (suppression champ, rename)Nouvelle version (/v2/) + période de dépréciation
Authentification multi-schémasDéclarer tous les securitySchemes, appliquer au niveau global ou opération

Garde-fous / Anti-patterns

Ne pas faire :

Pièges courants :


Bonnes pratiques 2026