Catalogue of series articles
Chapter I gin preliminary understanding
Chapter 2 setting API
Note:
- The series of articles are learning notes corresponding to the original English books mentioned above
- Related to their own practice code, including comments, on my gitee Welcome, star
- All contents are allowed to be reproduced. If the copyright of the book is infringed, please contact to delete it
- 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
- 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
- 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)