ch2 setting API -- creating distributed applications using go gin

Catalogue of series articles

Chapter I gin preliminary understanding
Chapter 2 setting API


Note:

  1. The series of articles are learning notes corresponding to the original English books mentioned above
  2. Related to their own practice code, including comments, on my gitee Welcome, star
  3. All contents are allowed to be reproduced. If the copyright of the book is infringed, please contact to delete it
  4. Notes are constantly updated

Set API

preface

This chapter describes how to build restful APIs,
Introduce other methods of HTTP and routing methods.
There is also how to write OpenAPI and generate API documents.

Microservice application architecture based on gin framework

In short, microservices manage methods under the http protocol by exposing restful APIs

Define data model

type Recipe struct {
   Name         string    `json:"name"` // Specify fields using annotations
   Tags         []string  `json:"tags"`
   Ingredients  []string  `json:"ingredients"`
   Instructions []string  `json:"instructions"`
   PublishedAt  time.Time `json:"PublishedAt"`
}

Annotations are added after the data model to help Go and JSON in the field name

http node method

Implement HTTP routing

1. Define global variables to store data

After using the database, you can directly use the data returned by the database

var recipes []Recipe
func init() {
    recipes = make([]recipes, 0)
}

2. Write POST response processing function

func NewRecipeHandler(c *gin.Context) {
   var recipe Recipe
    // Get and bind to the data entity from the body of the POST request
    // c.ShouldBindJSON(&recipe)
   if err := c.ShouldBindJSON(&recipe); err != nil {
      c.JSON(http.StatusBadRequest, gin.H{
         "error": err.Error()})
      return
   }
   // Generate unique ID code
   recipe.ID = xid.New().String()
   recipe.PublishedAt = time.Now()
   recipes = append(recipes, recipe)
   // Return the data model entity recipe to json mode
   c.JSON(http.Status(OK, recipe)
}

3. Write GET response function

func ListRecipesHandler(c *gin.Context) {
   c.JSON(http.StatusOK, recipes)
}

4. Get data from json file and initialize entity

func init() {
   // Use the text file json to simulate the database for initializing the data model
   recipes = make([]Recipe, 0)
   // Generally, go will look for files in the root path of the project
   file, _ := ioutil.ReadFile("recipes.json")
   _ = json.Unmarshal([]byte(file), &recipes)
}

5. Write PUT response function and update the specified data

// The URL passes the parameter ID and updates the specified entity data
func UpdateRecipeHandler(c *gin.Context) {
   id := c.Param("id")
   var recipe Recipe
   // 1. Initialize entity with body
   if err := c.ShouldBindJSON(&recipe); err != nil {
      c.JSON(http.StatusBadRequest, gin.H{
         "error": err.Error()})
      return
   }
   // Locate the recipe with the ID specified by the URL in the local data
   index := -1
   for i := 0; i < len(recipes); i++ {
      if recipes[i].ID == id {
         index = i
      }
   }
   if index == -1 {
      c.JSON(http.StatusNotFound, gin.H{
         "error": "Recipe not found"})
      return
   }
   // Update the found recipe to local data
   recipes[index] = recipe
   c.JSON(http.StatusOK, recipe)
}

6. Write the DELETE response function to find and DELETE the specified entity

func DeleteRecipeHandler(c *gin.Context) {
   id := c.Param("id")
   index := -1
   for i := 0; i < len(recipes); i++ {
      if recipes[i].ID == id {
         index = i
      }
   }
   if index == -1 {
      c.JSON(http.StatusNotFound, gin.H{
         "error": "Recipe not found"})
      return
   }
   // The array splicing method deletes the element with index as the index
   recipes = append(recipes[:index], recipes[index+1:]...)
   c.JSON(http.StatusOK, gin.H{
      "message": "Recipe has been deleted"})
}

7. Write GET/recipes/search?tag=? response function

// The URL passes the parameter ID and updates the specified entity data
func UpdateRecipeHandler(c *gin.Context) {
   id := c.Param("id")
   var recipe Recipe
   // 1. Initialize entity with body
   if err := c.ShouldBindJSON(&recipe); err != nil {
      c.JSON(http.StatusBadRequest, gin.H{
         "error": err.Error()})
      return
   }
   // Locate the recipe with the ID specified by the URL in the local data
   index := -1
   for i := 0; i < len(recipes); i++ {
      if recipes[i].ID == id {
         index = i
      }
   }
   if index == -1 {
      c.JSON(http.StatusNotFound, gin.H{
         "error": "Recipe not found"})
      return
   }
   // Update the found recipe to local data
   recipes[index] = recipe
   c.JSON(http.StatusOK, recipe)
}

Write OpenAPI description (OAS)

As an API specification or API definition language, OAS should contain the following information when describing an API:

  • Basic information of API
  • Valid path and operation (HTTP method)
  • Expected input (query, path parameters, request body, etc.) and response (HTTP status code, response body, etc.) corresponding to each operation

Generate API description using Go Swagger

  1. On the line of package main, write the description information of the API
// Recipes API
//
// This is a sample recipes API.
//
// Schemes: http
// host: localhost:8080
// BasePath: /
// Version: 1.0.0
// Contact: Mohamed Labouardy <mohamed@labourdy.com> https://labourardy.com
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
// swagger:meta

Execute in the project root directory

swagger generate spec -o ./swagger.json

This document generates json type instructions. If the suffix is yml or yaml, yaml files will be generated

implement

swagger serve ./swagger.json

The document just generated will be used to render a local document

  1. Document specific API s on the Handler function
// swagger:operation GET /recipes recipes listRecipes
// Returns list of recipes
// ---
// produces:
// - application/json
// responses:
// '200':
// description: Successful operation
func ListRecipesHandler(c *gin.Context) {
   c.JSON(http.StatusOK, recipes)
}
// swagger:operation PUT /recipes/{id} recipes updateRecipe
// Update an existing recipe
// ---
// parameters:
// - name: id
// in: path
// description: ID of the recipe
// required: true
// type: string
// produces:
// - application/json
// responses:
// '200':
// description: Successful operation
func UpdateRecipeHandler(c *gin.Context)

Keywords: Go Back-end

Added by dandare on Tue, 15 Feb 2022 07:09:28 +0200