Comment créer une API multi-protocole avec REST, GraphQL et gRPC ?

Ashley Innocent

Ashley Innocent

13 March 2026

Comment créer une API multi-protocole avec REST, GraphQL et gRPC ?

Apidog pour les entreprises

Déploiement sur site

SSO & RBAC

Conforme SOC 2

Explorer Apidog Enterprise

TL;DR

Construisez des API multi-protocoles en séparant la logique métier des couches de protocole. Créez une couche de domaine partagée, puis ajoutez des adaptateurs REST, GraphQL et gRPC par-dessus. Modern PetstoreAPI démontre cette architecture avec des modèles de données cohérents sur les trois protocoles.

Introduction

Votre API sert les clients web, les applications mobiles et les microservices internes. Les clients web veulent REST pour la simplicité. Les applications mobiles veulent GraphQL pour réduire le transfert de données. Les microservices veulent gRPC pour la performance. Devez-vous construire trois API distinctes ?

Non. Vous construisez une API avec trois couches de protocole. La logique métier reste la même. Seuls les adaptateurs de protocole changent. C'est l'architecture d'API multi-protocole.

Modern PetstoreAPI implémente REST, GraphQL et gRPC à partir d'un cœur partagé. La même logique de magasin d'animaux de compagnie sert les trois protocoles avec un comportement cohérent.

💡
Si vous construisez ou testez des API multi-protocoles, Apidog prend en charge les tests REST, GraphQL et gRPC dans un seul outil. Vous pouvez vérifier que tous les protocoles renvoient des données cohérentes et tester des flux de travail multi-protocoles.
bouton

Dans ce guide, vous apprendrez à architecturer des API multi-protocoles, à implémenter des couches de protocole et à assurer la cohérence entre les protocoles en utilisant Modern PetstoreAPI comme référence.

Architecture multi-protocole

Les API multi-protocoles séparent les préoccupations en couches.

Architecture en couches

┌─────────────────────────────────────────┐
│  Couche de protocole (REST/GraphQL/gRPC)     │
├─────────────────────────────────────────┤
│  Couche d'application (Cas d'utilisation)          │
├─────────────────────────────────────────┤
│  Couche de domaine (Logique métier)          │
├─────────────────────────────────────────┤
│  Couche de données (Base de données, Cache)           │
└─────────────────────────────────────────┘

Couche de protocole : Gère les requêtes HTTP, GraphQL, les appels gRPC Couche d'application : Orchestre les cas d'utilisation (créer un animal, passer une commande) Couche de domaine : Règles métier (validation, calculs) Couche de données : Persistance (base de données, cache)

Principes clés

1. Cœur agnostique du protocole

La logique métier ne connaît pas HTTP, GraphQL ou gRPC. Elle fonctionne avec des objets de domaine.

2. Adaptateurs de protocole minces

Les couches de protocole traduisent entre les formats de protocole et les objets de domaine. Elles ne contiennent pas de logique métier.

3. Modèles de données partagés

Tous les protocoles utilisent les mêmes modèles de domaine en interne, garantissant la cohérence.

4. Déploiement indépendant

Chaque protocole peut être déployé séparément si nécessaire.

Couche de domaine partagée

La couche de domaine contient la logique métier partagée par tous les protocoles.

Modèles de domaine

// Modèle de domaine (agnostique du protocole)
class Pet {
  id: string;
  name: string;
  species: Species;
  status: PetStatus;
  price: number;

  constructor(data: PetData) {
    this.validate(data);
    Object.assign(this, data);
  }

  validate(data: PetData): void {
    if (!data.name || data.name.length < 2) {
      throw new ValidationError('Name must be at least 2 characters');
    }
    if (data.price < 0) {
      throw new ValidationError('Price cannot be negative');
    }
  }

  adopt(userId: string): Order {
    if (this.status !== PetStatus.AVAILABLE) {
      throw new BusinessError('Pet is not available for adoption');
    }
    this.status = PetStatus.ADOPTED;
    return new Order({
      petId: this.id,
      userId,
      total: this.price
    });
  }
}

Ce modèle fonctionne pour REST, GraphQL et gRPC. La validation et les règles métier sont les mêmes.

Cas d'utilisation

// Cas d'utilisation (agnostique du protocole)
class AdoptPetUseCase {
  constructor(
    private petRepository: PetRepository,
    private orderRepository: OrderRepository
  ) {}

  async execute(petId: string, userId: string): Promise<Order> {
    const pet = await this.petRepository.findById(petId);
    if (!pet) {
      throw new NotFoundError('Pet not found');
    }

    const order = pet.adopt(userId);
    await this.petRepository.save(pet);
    await this.orderRepository.save(order);

    return order;
  }
}

Ce cas d'utilisation fonctionne qu'il soit appelé depuis REST, GraphQL ou gRPC.

Couche de protocole REST

La couche REST traduit les requêtes HTTP en opérations de domaine.

Contrôleur REST

// Adaptateur REST
class PetsController {
  constructor(private adoptPetUseCase: AdoptPetUseCase) {}

  async adoptPet(req: Request, res: Response): Promise<void> {
    try {
      const { petId } = req.params;
      const { userId } = req.body;

      const order = await this.adoptPetUseCase.execute(petId, userId);

      res.status(201).json({
        id: order.id,
        petId: order.petId,
        userId: order.userId,
        total: order.total,
        status: order.status
      });
    } catch (error) {
      this.handleError(error, res);
    }
  }

  private handleError(error: Error, res: Response): void {
    if (error instanceof NotFoundError) {
      res.status(404).json({
        type: 'https://petstoreapi.com/errors/not-found',
        title: 'Not Found',
        status: 404,
        detail: error.message
      });
    } else if (error instanceof ValidationError) {
      res.status(400).json({
        type: 'https://petstoreapi.com/errors/validation-error',
        title: 'Validation Error',
        status: 400,
        detail: error.message
      });
    } else {
      res.status(500).json({
        type: 'https://petstoreapi.com/errors/internal-error',
        title: 'Internal Server Error',
        status: 500
      });
    }
  }
}

Routes REST

app.post('/v1/pets/:petId/adopt', (req, res) =>
  petsController.adoptPet(req, res)
);

Points de terminaison REST de Modern PetstoreAPI

Couche de protocole GraphQL

La couche GraphQL traduit les requêtes GraphQL en opérations de domaine.

Schéma GraphQL

type Pet {
  id: ID!
  name: String!
  species: Species!
  status: PetStatus!
  price: Float!
}

type Order {
  id: ID!
  petId: ID!
  userId: ID!
  total: Float!
  status: OrderStatus!
}

type Mutation {
  adoptPet(petId: ID!, userId: ID!): Order!
}

Résolveur GraphQL

// Adaptateur GraphQL
const resolvers = {
  Mutation: {
    adoptPet: async (
      _parent: any,
      args: { petId: string; userId: string },
      context: Context
    ): Promise<Order> => {
      try {
        return await context.adoptPetUseCase.execute(
          args.petId,
          args.userId
        );
      } catch (error) {
        throw new GraphQLError(error.message, {
          extensions: {
            code: error instanceof NotFoundError ? 'NOT_FOUND' :
                  error instanceof ValidationError ? 'BAD_USER_INPUT' :
                  'INTERNAL_SERVER_ERROR'
          }
        });
      }
    }
  }
};

Requête GraphQL

mutation {
  adoptPet(
    petId: "019b4132-70aa-764f-b315-e2803d882a24"
    userId: "user-123"
  ) {
    id
    total
    status
  }
}

Schéma GraphQL de Modern PetstoreAPI

Couche de protocole gRPC

La couche gRPC traduit les messages Protocol Buffer en opérations de domaine.

Définition du tampon de protocole

syntax = "proto3";

package petstore.v1;

service PetService {
  rpc AdoptPet(AdoptPetRequest) returns (AdoptPetResponse);
}

message AdoptPetRequest {
  string pet_id = 1;
  string user_id = 2;
}

message AdoptPetResponse {
  string order_id = 1;
  string pet_id = 2;
  string user_id = 3;
  double total = 4;
  string status = 5;
}

Implémentation du service gRPC

// Adaptateur gRPC
class PetServiceImpl implements IPetService {
  constructor(private adoptPetUseCase: AdoptPetUseCase) {}

  async adoptPet(
    call: ServerUnaryCall<AdoptPetRequest, AdoptPetResponse>,
    callback: sendUnaryData<AdoptPetResponse>
  ): Promise<void> {
    try {
      const { petId, userId } = call.request;

      const order = await this.adoptPetUseCase.execute(petId, userId);

      callback(null, {
        orderId: order.id,
        petId: order.petId,
        userId: order.userId,
        total: order.total,
        status: order.status
      });
    } catch (error) {
      callback({
        code: error instanceof NotFoundError ? status.NOT_FOUND :
              error instanceof ValidationError ? status.INVALID_ARGUMENT :
              status.INTERNAL,
        message: error.message
      });
    }
  }
}

Service gRPC de Modern PetstoreAPI

Comment Modern PetstoreAPI implémente le multi-protocole

Modern PetstoreAPI démontre l'architecture multi-protocole avec des exemples concrets.

Vue d'ensemble de l'architecture

Modern PetstoreAPI
├── Couche de domaine
│   ├── Animal de compagnie (entité)
│   ├── Commande (entité)
│   └── Cas d'utilisation
│       ├── CréerAnimal
│       ├── AdopterAnimal
│       └── PasserCommande
├── Couche REST
│   ├── /v1/pets
│   ├── /v1/orders
│   └── Spécification OpenAPI 3.2
├── Couche GraphQL
│   ├── Résolveurs de requêtes
│   ├── Résolveurs de mutations
│   └── Schéma GraphQL
└── Couche gRPC
    ├── ServiceAnimal
    ├── ServiceCommande
    └── Définitions .proto

Modèles de données cohérents

Tous les protocoles renvoient les mêmes données :

REST :

{
  "id": "019b4132-70aa-764f-b315-e2803d882a24",
  "name": "Fluffy",
  "species": "CAT"
}

GraphQL :

{
  "data": {
    "pet": {
      "id": "019b4132-70aa-764f-b315-e2803d882a24",
      "name": "Fluffy",
      "species": "CAT"
    }
  }
}

gRPC :

{
  pet_id: "019b4132-70aa-764f-b315-e2803d882a24"
  name: "Fluffy"
  species: CAT
}

Mêmes données, formats différents.

Validation partagée

La validation a lieu dans la couche de domaine, de sorte que tous les protocoles appliquent les mêmes règles :

// Validation de domaine (partagée)
if (name.length < 2) {
  throw new ValidationError('Name must be at least 2 characters');
}

REST renvoie :

{
  "type": "https://petstoreapi.com/errors/validation-error",
  "status": 400,
  "detail": "Name must be at least 2 characters"
}

GraphQL renvoie :

{
  "errors": [{
    "message": "Name must be at least 2 characters",
    "extensions": {"code": "BAD_USER_INPUT"}
  }]
}

gRPC renvoie :

code: INVALID_ARGUMENT
message: "Name must be at least 2 characters"

Même validation, formats d'erreur spécifiques au protocole.

Tester les API multi-protocoles avec Apidog

Apidog prend en charge le test des trois protocoles.

Tester le point de terminaison REST

POST https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24/adopt
Content-Type: application/json

{
  "userId": "user-123"
}

Tester la mutation GraphQL

mutation {
  adoptPet(
    petId: "019b4132-70aa-764f-b315-e2803d882a24"
    userId: "user-123"
  ) {
    id
    total
  }
}

Tester le service gRPC

grpc.petstore.v1.PetService/AdoptPet
{
  "pet_id": "019b4132-70aa-764f-b315-e2803d882a24",
  "user_id": "user-123"
}

Vérifier la cohérence

Vérifiez que les trois protocoles renvoient les mêmes données :

  1. Appeler le point de terminaison REST
  2. Appeler la mutation GraphQL
  3. Appeler le service gRPC
  4. Comparer les résultats

Apidog peut automatiser ce test multi-protocoles.

Stratégies de déploiement

Stratégie 1 : Service unique

Déployer tous les protocoles dans un seul service :

┌─────────────────────────┐
│  Service PetstoreAPI    │
│  ├── REST (port 8080)   │
│  ├── GraphQL (port 8081)│
│  └── gRPC (port 50051)  │
└─────────────────────────┘

Avantages : Déploiement simple, ressources partagées Inconvénients : Tous les protocoles évoluent ensemble

Stratégie 2 : Services séparés

Déployer chaque protocole séparément :

┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│ Service REST │  │ Service GraphQL  │  │ Service gRPC │
│ (port 8080)  │  │ (port 8081)  │  │ (port 50051) │
└──────────────┘  └──────────────┘  └──────────────┘
       │                 │                  │
       └─────────────────┴──────────────────┘
                         │
                  ┌──────────────┐
                  │ Noyau partagé  │
                  │   Bibliothèque    │
                  └──────────────┘

Avantages : Mise à l'échelle indépendante, isolation des protocoles Inconvénients : Déploiement plus complexe

Stratégie 3 : Passerelle API

Utilisez une passerelle API pour acheminer vers des backends spécifiques au protocole :

                ┌─────────────┐
                │ Passerelle API │
                └─────────────┘
                       │
        ┌──────────────┼──────────────┐
        │              │              │
┌───────▼──────┐ ┌────▼─────┐ ┌──────▼──────┐
│ Backend REST │ │ GraphQL  │ │ Backend gRPC│
└──────────────┘ └──────────┘ └─────────────┘

Avantages : Routage centralisé, limitation de débit, authentification Inconvénients : Latence supplémentaire, complexité de la passerelle

Modern PetstoreAPI utilise la Stratégie 1 pour la simplicité.

Conclusion

Les API multi-protocoles offrent aux clients une flexibilité sans dupliquer la logique métier. En séparant les couches de protocole de la logique de domaine, vous pouvez prendre en charge REST, GraphQL et gRPC à partir d'un noyau partagé.

Modern PetstoreAPI démontre cette architecture avec des modèles de données cohérents, une validation partagée et des adaptateurs spécifiques au protocole. Que les clients utilisent REST pour la simplicité, GraphQL pour la flexibilité ou gRPC pour la performance, ils accèdent au même magasin d'animaux de compagnie avec les mêmes règles métier.

Testez vos API multi-protocoles avec Apidog pour assurer la cohérence entre les protocoles. Explorez Modern PetstoreAPI pour voir l'architecture multi-protocole en action.

bouton

FAQ

Dois-je prendre en charge les trois protocoles ?

Non. Commencez par REST pour les API publiques. Ajoutez GraphQL si les clients ont besoin d'une récupération de données flexible. Ajoutez gRPC pour les microservices internes. N'ajoutez des protocoles que lorsque vous avez un cas d'utilisation clair.

Comment puis-je maintenir la cohérence des protocoles ?

Partagez la logique métier dans une couche de domaine. Les adaptateurs de protocole ne devraient que traduire les formats, et non contenir de règles métier. Testez tous les protocoles pour vérifier qu'ils renvoient les mêmes données.

Puis-je versionner les protocoles indépendamment ?

Oui. REST peut être en v2 tandis que GraphQL est en v1. Mais cela crée de la complexité. Essayez de maintenir les protocoles synchronisés si possible.

Comment gérer l'authentification entre les protocoles ?

Utilisez la même authentification dans tous les protocoles. REST utilise des jetons Bearer dans les en-têtes. GraphQL utilise les mêmes jetons. gRPC utilise des métadonnées. La couche de domaine valide les jetons de la même manière.

Qu'en est-il de WebSocket et SSE ?

WebSocket et SSE sont des protocoles de transport, pas des protocoles d'API. Vous pouvez les ajouter aux côtés de REST/GraphQL/gRPC pour des mises à jour en temps réel. Modern PetstoreAPI inclut les deux.

Comment documenter les API multi-protocoles ?

Utilisez OpenAPI pour REST, le schéma GraphQL pour GraphQL et les fichiers .proto pour gRPC. Modern PetstoreAPI fournit les trois à l'adresse https://docs.petstoreapi.com/

Puis-je utiliser des bases de données différentes pour différents protocoles ?

Oui, mais cela crée des problèmes de cohérence. Il est préférable d'utiliser la même couche de données pour tous les protocoles. Laissez les adaptateurs de protocole gérer les différences de format.

Comment tester les API multi-protocoles ?

Utilisez Apidog pour tester tous les protocoles dans un seul outil. Créez des suites de tests qui vérifient la cohérence entre les protocoles. Vérifiez que REST, GraphQL et gRPC renvoient les mêmes données pour les mêmes opérations.

Pratiquez le Design-first d'API dans Apidog

Découvrez une manière plus simple de créer et utiliser des API

Comment créer une API multi-protocole avec REST, GraphQL et gRPC ?