API en Go : REST, GraphQL et gRPC — que choisir en 2025

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Pourquoi Go est-il le langage idéal pour les API ?

\n\n

Lorsqu'il s'agit de créer des API à forte charge, Go (Golang) occupe avec confiance une place de choix. Sa nature compilée, sa prise en charge intégrée de la concurrence via les goroutines et sa syntaxe minimaliste permettent d'écrire des microservices rapides et fiables. Mais quel protocole choisir pour votre prochain projet : le classique REST, le flexible GraphQL ou l'ultra-rapide gRPC ?

\n\n

Dans cet article, nous ne nous contenterons pas de lister les différences — nous écrirons du code réel en Go pour chaque approche, analyserons les benchmarks et donnerons des critères de choix clairs. C'est parti !

\n\n

API REST en Go : un classique éprouvé

\n\n

REST (Representational State Transfer) reste la norme de facto pour les API publiques. Go offre une excellente bibliothèque standard net/http, ainsi que des frameworks populaires comme gin et echo.

\n\n

Exemple de serveur REST en Go pur

\n\n

Commençons par un simple service CRUD pour gérer des tâches. Voici à quoi ressemble une API REST minimale en Go sans dépendances externes :

\n\n
package main\n\nimport (\n    "encoding/json"\n    "log"\n    "net/http"\n    "sync"\n)\n\ntype Task struct {\n    ID   int    `json:"id"`\n    Name string `json:"name"`\n}\n\nvar (\n    tasks   = []Task{{ID: 1, Name: "Apprendre Go"}}\n    mu      sync.Mutex\n    nextID  = 2\n)\n\nfunc getTasks(w http.ResponseWriter, r *http.Request) {\n    mu.Lock()\n    defer mu.Unlock()\n    w.Header().Set("Content-Type", "application/json")\n    json.NewEncoder(w).Encode(tasks)\n}\n\nfunc createTask(w http.ResponseWriter, r *http.Request) {\n    var task Task\n    if err := json.NewDecoder(r.Body).Decode(&task); err != nil {\n        http.Error(w, err.Error(), http.StatusBadRequest)\n        return\n    }\n    mu.Lock()\n    task.ID = nextID\n    nextID++\n    tasks = append(tasks, task)\n    mu.Unlock()\n    w.WriteHeader(http.StatusCreated)\n    json.NewEncoder(w).Encode(task)\n}\n\nfunc main() {\n    http.HandleFunc("/tasks", func(w http.ResponseWriter, r *http.Request) {\n        switch r.Method {\n        case http.MethodGet:\n            getTasks(w, r)\n        case http.MethodPost:\n            createTask(w, r)\n        default:\n            http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)\n        }\n    })\n    log.Println("API REST démarrée sur :8080")\n    log.Fatal(http.ListenAndServe(":8080", nil))\n}\n
\n\n

Avantages de REST en Go :

\n
    \n
  • Simplicité et prévisibilité — chaque endpoint renvoie une structure de données fixe
  • \n
  • Excellente mise en cache via les en-têtes HTTP
  • \n
  • Large support d'outils (Swagger, Postman)
  • \n
\n\n

Inconvénients : Sur-récupération (over-fetching) et sous-récupération (under-fetching) des données. Si le client a besoin uniquement du nom de la tâche, il reçoit quand même le JSON complet.

\n\n

GraphQL en Go : flexibilité des requêtes

\n\n

GraphQL résout le problème de redondance des données. Le client décide lui-même des champs dont il a besoin. La communauté Go propose la puissante bibliothèque gqlgen, qui génère du code à partir du schéma.

\n\n

Exemple de serveur GraphQL avec gqlgen

\n\n

Définissons d'abord le schéma schema.graphql :

\n\n
type Task {\n    id: ID!\n    name: String!\n}\n\ntype Query {\n    tasks: [Task!]!\n}\n\ntype Mutation {\n    createTask(name: String!): Task!\n}\n
\n\n

Lançons maintenant la génération et écrivons les résolveurs en Go :

\n\n
package main\n\nimport (\n    "log"\n    "net/http"\n    "github.com/99designs/gqlgen/graphql/handler"\n    "github.com/99designs/gqlgen/graphql/playground"\n)\n\n// Nous supposons que le code généré existe déjà\ntype Resolver struct {\n    tasks []Task\n    mu    sync.Mutex\n}\n\nfunc (r *Resolver) Tasks(ctx context.Context) ([]Task, error) {\n    r.mu.Lock()\n    defer r.mu.Unlock()\n    return r.tasks, nil\n}\n\nfunc (r *Resolver) CreateTask(ctx context.Context, name string) (*Task, error) {\n    r.mu.Lock()\n    defer r.mu.Unlock()\n                

Blogs

Book Recommendations