API REST en GO
Introduction à l’API REST et à Go
Qu’est-ce qu’une API REST ?
-
API : interface pour communiquer avec un service ou une application de manière automatisée.
-
REST : style d’architecture web, où l’on utilise généralement HTTP pour effectuer des opérations CRUD (Create, Read, Update, Delete).
Pourquoi utiliser Go pour une API REST ?
Go est langage rapide et compilé. Il est ainsi idéal pour des services performants.
Création d'un serveur HTTP minimal
Créer le serveur
Nous avons appris à créer un serveur web dans la leçon précédente.
Nous allons en créer un autre pour notre API.
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Bienvenue sur mon API Go !")
})
fmt.Println("Le port 8080 est utilisé pour lancer l'API Go !")
http.ListenAndServe(":8080", nil)
}
Tester le serveur
go run main.go
Dans le navigateur de votre choix, si vous tapez l'url localhost:8080, vous devriez voir :

Manipuler des données (struct, JSON)
Imaginons qu’on veuille manipuler des "items". On définit un type Item
grâce à struct
:
type Item struct {
ID int `json:"id"`
Name string `json:"name"`
}
Les tags json:"..."
indiquent comment Go encode/décode cette struct
en JSON.
On stocke ensuite les items dans une slice
.
var items = []Item{
{ID: 1, Name: "Item A"},
{ID: 2, Name: "Item B"},
}
On aura 2️⃣ items.
Gérer des endpoints
Qu'est-ce qu'un endpoints ?
Un endpoint est un point d’accès à une API auquel est associé une méthode HTTP (GET, POST, PUT, DELETE, etc...) et une "URL", afin que le client puisse envoyer une requête précise (par exemple GET /items) pour réaliser une action donnée.
GET : Récupérer la liste des items
package main
import (
"encoding/json"
"fmt"
"net/http"
)
type Item struct {
ID int `json:"id"`
Name string `json:"name"`
}
var items = []Item{
{ID: 1, Name: "Item A"},
{ID: 2, Name: "Item B"},
}
func itemsHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
// On renvoie la liste en JSON
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(items)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
w.Write([]byte("Méthode non autorisée"))
}
}
func main() {
http.HandleFunc("/", itemsHandler)
fmt.Println("Le port 8080 est utilisé pour lancer l'API Go !")
http.ListenAndServe(":8080", nil)
}
Voici comment comprendre le code (ligne 19 à 27).
r.method
permet de vérifier la méthode : GET, POST, ...
json.NewEncoder(w).Encode(items)
encode items
en JSON
et l’envoie dans la réponse.
w.Header().Set("Content-Type", ...)
: indique que la réponse est au format JSON.
Rappelez-vous que w
correspond à la réponse que nous envoyons.
Lorsque vous tapez l'url localhost:8080 dans votre navigateur, le résultat suivant apparaîtra :
[
{
"id":1,
"name":"Item A"
},
{
"id":2,
"name":"Item B"
}
]
Le serveur vous envoie des données sous forme JSON
.
POST : Ajouter un nouvel item
On va maintenant utiliser utiliser la méthode POST
pour ajouter un élément.
package main
import (
"encoding/json"
"fmt"
"net/http"
)
type Item struct {
ID int `json:"id"`
Name string `json:"name"`
}
var items = []Item{
{ID: 1, Name: "Item A"},
{ID: 2, Name: "Item B"},
}
func itemsHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodPost:
w.Header().Set("Content-Type", "application/json")
var newItem Item
err := json.NewDecoder(r.Body).Decode(&newItem)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{"error": "Données invalides"})
return
}
// Générer un ID (simplement la longueur + 1, par exemple)
newItem.ID = len(items) + 1
items = append(items, newItem)
// Répondre avec l'item créé
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(newItem)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
w.Write([]byte("Méthode non autorisée"))
}
}
func main() {
http.HandleFunc("/", itemsHandler)
fmt.Println("Le port 8080 est utilisé pour lancer l'API Go !")
http.ListenAndServe(":8080", nil)
}
Nous allons expliquer ce code.
Ligne 24 ► var newItem Item
: Nous déclarons la variable newItem
de type Item
. Ce type, généralement une struct
, va nous permettre de stocker les informations que nous allons extraire du corps (body) de la requête. Cela nous permettra de récupérer la nouvelle donnée.
Ligne 25 ► err := json.NewDecoder(r.Body).Decode(&newItem)
: Nous créons ensuite un décodeur JSON
basé sur r.Body
, qui contient le contenu de la requête HTTP
au format JSON
. Avec la méthode Decode(&newItem)
, nous demandons à ce décodeur de convertir le JSON
reçu en un objet Item
. Le résultat de cette opération peut produire une erreur (par exemple si le JSON est mal formé), c’est pourquoi nous stockons cette éventuelle erreur dans la variable err
.
Ligne 26 ► if err != nil { ... }
: Nous vérifions si la variable err
n’est pas nulle, ce qui signifierait que la phase de décodage a échoué. Si err != nil
, alors quelque chose s’est mal passé, soit parce que le JSON
n’est pas valide, soit parce qu’il ne correspond pas à la structure Item
.
Ligne 27 ► w.WriteHeader(http.StatusBadRequest)
: Si l’erreur err
indique effectivement un problème, nous renvoyons au client un code HTTP 400 (Bad Request)
. Cela signifie que la requête était invalide ou mal formulée, ce qui donne une indication claire au client de la nature de l’erreur.
Ligne 28 ► json.NewEncoder(w).Encode(map[string]string{"error": "Données invalides"})
: Après avoir spécifié le code d’erreur, nous répondons également avec un petit JSON qui contient une clé "error" et la valeur "Données invalides". Cette réponse est encodée à l’aide de json.NewEncoder(w).Encode(...)
, ce qui permet au client (le navigateur) de comprendre la raison de l’échec.
Ligne 29 ► return
: Nous utilisons return
pour sortir immédiatement de la fonction handler
, car nous ne voulons pas poursuivre le traitement si les données envoyées par le client ne sont pas conformes.