Restful API Server
Simple Server
Pour utiliser Gin, il suffit d’importer github.com/gin-gonic/gin
au niveau de son fichier main et de créer une variable qui va contenir notre fameux routeur.
package main
import "github.com/gin-gonic/gin"
func main() {
router := gin.Default()
}
Il faut ensuite lui définir des routes sur lesquels il va écouter. Dans notre exemple, nous ferons 2 GET qui renvoient un JSON facilement grâce à la librairie Gin.
package main
import "github.com/gin-gonic/gin"
func main() {
router := gin.Default()
router.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello World!",
})
})
router.GET("/ping", func(c *gin.Context) {
c.IndentedJSON(200, gin.H{
"message": "pong",
})
})
}
Enfin, il faut lui dire de se lancer et d’écouter sur un port spécifique grâce à une dernière ligne.
package main
import "github.com/gin-gonic/gin"
func main() {
router := gin.Default()
router.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello World!",
})
})
router.GET("/ping", func(c *gin.Context) {
c.IndentedJSON(200, gin.H{
"message": "pong",
})
})
router.Run(":9090")
}
Dans ce code, nous :
- Initialisons un routeur Gin en utilisant Default.
- Utilisons le GET, pour associer la méthode HTTP
GET
et le chemin/, /ping
à une fonction contenant le contexte de la requête - Utilisons
c.JSON
ou bienc.IndentedJSON
permettent de simplement convertir une structure (en l’occurrencegin.H
qui permet d’en créer une à la volée)
Il suffit alors de lancer notre magnifique app avec la commande go run main.go
et aller tester nos routes.
Aussi simple que ça.
Simple music server
Pour complexifier un peu plus les choses, on va refaire la même chose, mais avec quelques structures et un peu de découpage. L'objectif étant de servir une API de gestion d’une liste d’album de musique (Très originale oui).
On va essayer de faire du pseudo MVC et l’architecture de notre application sera la suivante :
controllers/
| controller.go
| command.go
| query.go
data/
| albums.go
models/
| album.go
main.go
go.mod
go.sum
Models
Nous allons dans un premier temps définir la structure d’un album. Il faut déclarer dans le fichier models/album.go
la structure suivante :
package models
type Album struct {
ID string `json:"id"`
Title string `json:"title"`
Artist string `json:"artist"`
Price float64 `json:"price"`
}
Les balises telles que json:"artist"
spécifient le nom d'un champ lorsque le contenu de la structure est sérialisé en JSON.
Sans eux, le JSON utiliserait les noms de champs des propriétés, avec la majuscule, ce qui n'est pas très courant (pour rappel, en go, la majuscule, en début de variable ou fonction, permet de définir sa visibilité en dehors de son package) .
Data
On va ensuite déclarer une liste d’albums qui nous serviront de “base de données” pour notre application.
Remplissons dans le fichier data/albums.go
de cette manière :
package data
import "gin-form/simple_music_api/models"
var Albums = []models.Album{
{
ID: "1",
Title: "Taste of you",
Artist: "Rezz",
Price: 1.99,
},
{
ID: "2",
Title: "Go",
Artist: "Google",
Price: 9999,
},
{
ID: "3",
Title: "C#",
Artist: "Microsoft",
Price: -1,
},
}
Controllers
Occupons-nous de la partie controllers désormais !
Dans un premier temps, nous allons écrire nos fonctions servant à récupérer les données uniquement (en mode CQS tu connais).
Le fichier controllers/query.go
va contenir deux fonctions :
- Une permettant de récupérer la liste des albums
- Une autre permettant de récupérer un seul album par son ID
La première partie du fichier ressemblera simplement à ça
package controllers
import (
"gin-form/simple_music_api/data"
"github.com/gin-gonic/gin"
"net/http"
)
func getAlbums(c *gin.Context) {
c.IndentedJSON(http.StatusOK, data.Albums)
}
Dans ce code, nous :
- Écrivons une fonction
getAlbums
qui prend ungin.Context
en paramètre.gin.Context
est la partie la plus importante de Gin. Il prend en charge la requête, les détailles, la validation et sérialisation JSON, et plus encore.
- Appelons la fonction
c.IdentedJSON
afin de sérialiser notre tableaudata.Albums
en JSON indenté proprement. - Utilisons une librairie interne à go
net/http
pour récupérer le code HTTP voulu (200). On pourrait écrire directement 200 à la main, mais maintenant vous savez que cette librairie existe 😉
La deuxième méthode est un peu plus complexe et permet de récupérer un album parmi ceux existants avec son ID, qui sera passé dans le chemin de la requête (/album/:id
).
func getAlbumByID(c *gin.Context) {
id := c.Param("id")
for _, album := range data.Albums {
if album.ID == id {
c.IndentedJSON(http.StatusOK, album)
return
}
}
c.IndentedJSON(http.StatusNotFound, gin.H{"error": "Album not found"})
}
Nous allons maintenant nous occuper du fichier controllers/command.go
qui contiendra notre fonction permettant d’ajouter un album à notre liste.
package controllers
import (
"gin-form/simple_music_api/data"
"gin-form/simple_music_api/models"
"github.com/gin-gonic/gin"
"net/http"
)
func addAlbum(c *gin.Context) {
var newAlbum models.Album
if err := c.BindJSON(&newAlbum); err != nil {
c.IndentedJSON(400, gin.H{
"message": "Invalid JSON",
"error": err.Error(),
})
return
}
data.Albums = append(data.Albums, newAlbum)
c.IndentedJSON(http.StatusCreated, newAlbum)
}
Dans cette fonction nous :
- Déclarons une variable
newAlbum
de typeAlbum
- Utilisons la méthode fournit par Gin
c.BindJSON
qui va tenter de parser le body de notre requête dans notre structure en se basant sur le format décrit plus haut (les fameuxjson:"artist"
).- Si, on n’y parvient pas, on renvoie un code erreur avec un message et stoppons l’exécution de la méthode.
- Ajoutons notre nouvel album à notre tableau
- Renvoyons un code de Création et l’album qui vient d’être enregistré
Les fonctions écrites plus hautes sont privées, il va falloir donc faire quelque chose pour qu’elles puissent être utilisées par notre routeur se trouvant dans le fichier main.go
.
Ça sera le but de notre fichier controllers/controller.go
qui va s’occuper de faire notre routage :
package controllers
import "github.com/gin-gonic/gin"
func SourceControllers(router*gin.Engine) {
router.GET("/albums", getAlbums)
router.GET("/albums/:id", getAlbumByID)
router.POST("/albums", addAlbum)
}
Nous pouvons enfin relier tout ça à notre routeur principal dans le fichier main.go
package main
import (
"gin-form/simple_music_api/controllers"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
controllers.SourceControllers(router)
router.Run(":8080")
}
On peut maintenant aller tester tout ça 🤗
GGWP 👏