Restful API Server

Simple Server

GitHub repo

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 :

Il suffit alors de lancer notre magnifique app avec la commande go run main.go et aller tester nos routes.

Untitled

Untitled

Aussi simple que ça.

Simple music server

GitHub repo

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 :

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 :


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 :


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 🤗

Untitled

Untitled

Untitled

Untitled

Untitled

GGWP 👏


Revision #1
Created 9 May 2022 19:27:54 by Noé Larrieu-Lacoste
Updated 9 May 2022 19:30:46 by Noé Larrieu-Lacoste