The purpose is to practice to become Go's web framework Echo. Even if you toggle the value, I think there are cases where the bool value of the database is set to true <=> false, and there are cases where records in the database are inserted or deleted (such as creating a favorite function using an intermediate table). .. This time, after implementing the former as a BoolToggler model, we will implement the latter by adding a favorite function for BoolToggler to the User model. (It's a surreal and impractical application, but it's a practice so I don't care ...) I put the whole code on GitHub.
models
This is the main subject 1 of this article. Toggle True <=> False for a column value of type bool in the model. I defined such a model and migrated.
models/bool_toggler.go
package models
import (
"github.com/jinzhu/gorm"
)
type BoolToggler struct {
// type gorm.Model struct {
// ID uint `gorm:"primaryKey"`
// CreatedAt time.Time
// UpdatedAt time.Time
// DeletedAt gorm.DeletedAt `gorm:"index"`
// }
gorm.Model
Toggler bool `json:"toggler"`
}
It is a structure with a simple bool value called Toggler. Implement the api part.
web/api/toggle_bool_toggler.go
package api
import (
"github.com/labstack/echo"
"github.com/valyala/fasthttp"
"strconv"
"hello/models"
"hello/middlewares"
)
func ToggleBoolToggler() echo.HandlerFunc {
return func(c echo.Context) error {
//DB connection middleware
dbs := c.Get("dbs").(*middlewares.DatabaseClient)
//Since the path parameter is string, convert it to uint
intId, _ := strconv.Atoi(c.Param("id"))
uintId := uint(intId)
boolToggler := models.BoolToggler{}
if dbs.DB.First(&boolToggler, uintId).RecordNotFound() {
//If the id is specified incorrectly, status code 404 is returned.
return c.JSON(fasthttp.StatusNotFound, "The boolToggler with the specified id was not found.")
} else {
//Invert bool value and save
boolToggler.Toggler = !boolToggler.Toggler
dbs.DB.Save(&boolToggler)
return c.JSON(fasthttp.StatusOK, boolToggler)
}
}
}
web/api/get_bool_toggler.go
package api
import (
"github.com/labstack/echo"
"github.com/valyala/fasthttp"
"hello/models"
"hello/middlewares"
"strconv"
)
func GetBoolToggler() echo.HandlerFunc {
return func(c echo.Context) error {
dbs := c.Get("dbs").(*middlewares.DatabaseClient)
intId, _ := strconv.Atoi(c.Param("id"))
uintId := uint(intId)
boolToggler := models.BoolToggler{}
if dbs.DB.First(&boolToggler, uintId).RecordNotFound() {
return c.JSON(fasthttp.StatusNotFound, "The boolToggler with the specified id was not found.")
} else {
return c.JSON(fasthttp.StatusOK, boolToggler.Toggler)
}
}
}
It's basically the same as before. Instead of updating the data, I just take the Boolean value and put it in the response.
routes/api.go
func Init(e *echo.Echo) {
g := e.Group("/api")
{
g.PUT("/bool_toggler/:id/toggle", api.ToggleBoolToggler())
g.GET("/bool_toggler/:id", api.GetBoolToggler())
}
}
Let's test the operation so far.
curl http://localhost:8080/api/bool_toggler/1
>> false
curl -XPUT http://localhost:8080/api/bool_toggler/1/toggle
>> {"ID":1,"CreatedAt":"2020-10-05T14:54:27Z","UpdatedAt":"2020-10-07T10:49:12.1435735Z","DeletedAt":null,"toggler":true}
curl http://localhost:8080/api/bool_toggler/1
>> true
//Unregistered data
curl http://localhost:8080/api/bool_toggler/3
>> "The boolToggler with the specified id was not found.
I was able to confirm that it was working well.
models
We will implement an API that deletes and inserts values in the data that expresses the relationship in the intermediate table.
We'll start by creating a simple User model. Since the purpose is to implement relational many-to-many data as a simple application with an intermediate table, we do not create an authentication function. Anyway, it is a model with only a time stamp and a name. Migrate in the same way.
To create a many-to-many database with GORM, https://gorm.io/ja_JP/docs/many_to_many.html
models/user.go
package models
import (
"github.com/jinzhu/gorm"
)
type User struct {
gorm.Model
name string `json:"name"`
//Bool with the name Favorites_Store toggler
Favorites []*BoolToggler `gorm:"many2many:user_favorite_togglers;"`
}
Although it is a URI design first, there is no authentication function, so
/api/favorite/users/:user_id/bool_togglers/:toggler_id
You can see that it is necessary to refer to each entity from multiple path parameters with the URI. The following is the API part, but since it has become quite complicated, I left a lot of comments
web/api/toggle_favorite_bool_toggler.go
package api
import (
"github.com/labstack/echo"
"github.com/valyala/fasthttp"
"strconv"
"hello/models"
"hello/middlewares"
)
func ToggleFavoriteToggler() echo.HandlerFunc {
return func(c echo.Context) error {
//Structure that creates JSON for response
type Response struct {
UserId uint
BoolTogglerId uint
Favorite bool
}
//DB connection
dbs := c.Get("dbs").(*middlewares.DatabaseClient)
//Convert path parameters to uint
intUserId, _ := strconv.Atoi(c.Param("user_id"))
uintUserId := uint(intUserId)
intTogglerId, _ := strconv.Atoi(c.Param("toggler_id"))
uintTogglerId := uint(intTogglerId)
//Instantiate a Response structure
var resJSON Response
resJSON.UserId = uintUserId
resJSON.BoolTogglerId = uintTogglerId
//Pass boolToggler with ID when Appending
var boolToggler models.BoolToggler
boolToggler.ID = uintTogglerId
//Enable user relations in Preload and select
user := &models.User{}
dbs.DB.Preload("Favorites", "bool_toggler_id = ?", uintTogglerId).
Find(&user, uintUserId)
//Add a new record if it hasn't been favorited yet
if len(user.Favorites) < 1 {
dbs.DB.Model(&user).Association("Favorites").Append(&boolToggler)
resJSON.Favorite = true
//Delete existing record if it was favorited
} else {
dbs.DB.Model(&user).Association("Favorites").Delete(&boolToggler)
resJSON.Favorite = false
}
return c.JSON(fasthttp.StatusOK, resJSON)
}
}
routes/api.go
g.POST("/favorite/users/:user_id/bool_togglers/:toggler_id", api.ToggleFavoriteToggler()) //Postscript
When I try curl, the value is toggled properly.
curl -XPOST http://localhost:8080/api/favorite/users/1/bool_togglers/1
{"UserId":1,"BoolTogglerId":1,"Favorite":false}
/go/src/app # curl -XPOST http://localhost:8080/api/favorite/users/1/bool_togglers/1
{"UserId":1,"BoolTogglerId":1,"Favorite":true}
Furthermore, when I checked the mysql table, I was able to confirm the intended behavior.
mysql> select * from user_favorite_togglers;
+---------+-----------------+
| user_id | bool_toggler_id |
+---------+-----------------+
| 1 | 1 |
+---------+-----------------+
1 row in set (0.00 sec)
//After access
mysql> select * from user_favorite_togglers;
Empty set (0.00 sec)
web/api/show_user.go
package api
import (
"github.com/labstack/echo"
"github.com/valyala/fasthttp"
"hello/models"
"hello/middlewares"
"strconv"
)
func ShowUserInfo() echo.HandlerFunc {
return func(c echo.Context) error {
type ResToggler struct {
BoolTogglerId uint
Toggler bool
}
type Response struct {
UserId uint
Name string
Favorites []ResToggler
}
dbs := c.Get("dbs").(*middlewares.DatabaseClient)
//Convert path parameters to uint
intUserId, _ := strconv.Atoi(c.Param("id"))
uintUserId := uint(intUserId)
//Enable user relations in Preload and select
user := models.User{}
dbs.DB.Preload("Favorites").Find(&user, uintUserId)
var resJSON Response
resJSON.UserId = user.ID
resJSON.Name = user.Name
for _, v := range user.Favorites {
toggler := ResToggler{
BoolTogglerId: v.ID,
Toggler: v.Toggler,
}
resJSON.Favorites = append(resJSON.Favorites, toggler)
}
return c.JSON(fasthttp.StatusOK, resJSON)
}
}
The nice thing about the Echo framework is that if you define a structure for Response, you can pass it as JSON as it is. The result returns a structure like this:
curl http://localhost:8080/api/user/1
{"UserId":1,"Name":"test_user01","Favorites":[{"BoolTogglerId":1,"Toggler":false}]}
Recommended Posts