review

We explained that in the last issue

  • Use of gin middleware
  • Different methods for obtaining parameters on the POST and GET interfaces
  • .

Our main goal for this issue is

  • How do I build a standard Web project using GIN
  • How do I write standard APIS using GIN

Similarly, we continue with the last phase of the project

However, the branch of the project address switches to the Server branch starting from this phase. I want you to pay attention

Take a look at the directory

➜ go-gin-test tree -L 3. ├── go. Mod ├── goCopy the code

Web project

Goal:

  • We’ll use the usual onesMVCPattern to design the directory structure
  • Use the go language interface to encapsulate somebehaviororbusinessConvenient for later expansion and abstraction
  • Connecting to a Database
  • .

The directory to create

We’ll create a couple of directories

  • The API is used to write the directory of the Web interface
  • Service Is the directory for writing business logic
  • Model The directory in which the object structure is stored
  • Server is used for service management

Take a look at the directory

➜ go - gin - test git: (main) tree - L 3. ├ ─ ─ API ├ ─ ─. Mod ├ ─ ─. Sum ├ ─ ─ mian. Go ├ ─ ─ model ├ ─ ─ server ├ ─ ─ routerex │ ├ ─ ─ │ ├ ─ ├ ─ imp. Go │ ├ ─ impCopy the code
  • Let me modify itmid.goandrouter.go

The goal is to remove the previous middleware and use only cross-domain middleware

mid.go

package mid import ( "net/http" "github.com/gin-gonic/gin" ) func MidCors(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Headers", "*") c.Header("Access-Control-Allow-Methods", "*") c.Header("Access-Control-Allow-Credentials", If c.equest. Method == "OPTIONS" {c.abortwithStatus (http.statusnoContent)}Copy the code

router.go

Package routerex import (" example.com/m/v2/routerex/mid "" github.com/gin-gonic/gin") / / used to request address registered func RegRouter (g * gin-engine) {g1 := g.group ("/ API ") // middleware g1.use (mid.midcors)}Copy the code
  • inserverCreating a Directoryserver.gofile

server.go

package server import ( "example.com/m/v2/routerex" "github.com/gin-gonic/gin" ) func ServerStart(port string) { r := Gin.Default() Routerex.regrouter (r) r.Run(":" + port) // Listen and serve on 0.0.0.0:8080 (for Windows "localhost:8080") }Copy the code
  • Modify themain.go
Package main import "example.com/m/v2/server" // In the main file we try to have only one function and one call to avoid some unnecessary pits, Func main() {server.serverstart ("8080")}Copy the code

At this point, a rough outline of the frame has actually emerged

➜ go-gin-test git:(main) tree -L 3. ├─ API web interface ├─ go. Mod ├─ go ├── bass │ ├─ mid │ ├─ go ├─ routerCopy the code

Database link

Database links can be managed by creating a separate directory

  • We use thexormUsed as a persistence layer
  • At the same time usego-sql-driver/mysqlAs a database driver

Run the following command to import

go get github.com/go-sql-driver/mysql

go get xorm.io/xorm

➜ go-gin-test git:(Server) Qualify go github.com/go-sql-driver/mysql go: Downloading github.com/go-sql-driver/mysql v1.6.0 go: github.com/go-sql-driver/mysql upgrade => v1.6.0 ➜ go-gin-test Git :(Server) Qualify go get Xorm. IO/Xorm go: Xorm. IO /xorm upgrade => v1.0.7 ➜ go-gin-test git:(server) qualifyCopy the code

Create the db directory and db.go file

db.go

Package db import (" FMT "" Runtime /debug" // This is a required driver! _ "github.com/go-sql-driver/mysql" "xorm. IO /xorm") var MysqlDB *xorm.Engine // Can be modified to get the configuration from yaml file. Func InitDB() error {// Prevent the program from crashing defer func() {if err := recover(); err ! = nil { fmt.Println(fmt.Errorf("InitMysql:%+v", err)) fmt.Println(fmt.Errorf("%s", String (debug. The Stack ())))}} () / / remember to modify the user and password here url: = FMT. Sprintf (" % s: % s @ TCP / % s (% s: % s)? Charset =utf8&parseTime=True", "root", "jimBIR8520 ", "106.52.197.141", "7001", "ycc") err := xorm.NewEngine("mysql", url) if err ! = nil { fmt.Println(fmt.Sprintf("db init failed : %s", err.Error())) return err } MysqlDB = db fmt.Println("init db ok!" ) return nil }Copy the code

Now that our Web project has the ability to use a database, let’s try to write a business interface

Write a business interface

  • Imagine writing an interface for user registration

  • I hope you can continue to write user login and logout interface (if you have any questions can contact me through the following way, I will help you answer. QQ group :696502307 or leave a message on the official account Super Hero Jim)

  • Create a new T_USER table in the database.

Fields for the id, nick_name, user_name, PWD, create_time, does

  • inmodelnewuser.go
Package Model import "time" type TUser struct {Id int64 'xorm:" PK autoincr BIGINT(20)"' // NickName string 'xorm:"VARCHAR(255)"' // UserName UserName string 'xorm:"VARCHAR(255)"' // password Pwd string 'xorm:"VARCHAR(255)"' // whether it is deleted. Int 'xorm:"default 0 TINYINT(1)"' CreateTime time. time 'xorm:"not null comment(' CreateTime ') DATETIME"'} Func (c *TUser) Check() error {func (c *TUser) Check() error {if c. user name == "" {return Errors. New(" user name must not be empty ")} if len(c. user name) < 5 {return errors.New(" user name must be more than 4 characters ")} user := &tuser {UserName: c.UserName, } get, err := db.MysqlDB.Get(user) if err ! = nil { fmt.Println(fmt.Errorf("Check Get err : %v", Err)) return errors.New(" the server is busy please try again later ")} if get {return errors.New(" username already exists ")} if c.wd == "" {return Errors. The New (" password cannot be empty ")} the compile, err: = regexp.Com running (` ^ (. 16th {6} [^ 0-9] * [^ a-z] * [^ a-z] * [A zA - Z0-9] *) $`) if err! = nil { fmt.Println(fmt.Errorf("Check regexp err : %v", err)) return errors.New(" server busy please try again later ")} b := compile.MatchString(c.pad) if! B {return errors.New(" password invalid! Password should be 6-16 characters (can contain letters, digits, underscores) ")} return nil}Copy the code
  • inapiCreating a Directoryapi.go

Editor API. Go

package api import ( "fmt" "net/http" "time" "example.com/m/v2/db" "example.com/m/v2/model" "github.com/gin-gonic/gin" ) Func Register(c *gin.Context) {// Here I try to use json format to transfer data, usually here should be the form form submission, here is my personal preference, it is convenient, U := &model.TUser{} err := c. binjson (u) if err! = nil { fmt.Println(fmt.Errorf("Register BindJSON err : %v", err)) c.JSON(http.StatusInternalServerError, gin.H{ "msg": "Data format not correct ",}) return} err = u.heck () if err! = nil { fmt.Println(fmt.Errorf("Register Check err : %v", err)) c.JSON(http.StatusInternalServerError, gin.H{ "msg": err.Error(), }) return } u.CreateTime = time.Now() _, err = db.MysqlDB.Insert(u) if err ! = nil { fmt.Println(fmt.Errorf("Register Insert err : %v", err)) c.JSON(http.StatusInternalServerError, gin.H{ "msg": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "msg": "ok", }) }Copy the code

Edit the router.go file to register our interface

Package routerex import (" example.com/m/v2/api "" example.com/m/v2/routerex/mid" "github.com/gin-gonic/gin") / / used to request address registered Func RegRouter(g *gin.Engine) {g1 := g.group ("/ API ") // middleware g1.use (mid.midcors) g1.post ("/register", API.Copy the code
  • Same packing go build -o hello
  • run./hello
➜ go-gin-test git:(server) qualify go build-o hello ➜ go-gin-test git:(server) qualify./hello [gin-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. [GIN-debug] [WARNING] Running in "debug" mode.  Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode) [GIN-debug] POST /api/register --> example.com/m/v2/api.Register (4 handlers) init db ok! [GIN-debug] Listening and serving HTTP on :8080Copy the code

Send a POST request using Postman

You can see that our request was successful

conclusion

  • Congratulations, you have learned a standard Web engineering structure and API authoring

  • There are still a lot of things that can be optimized and improved. You can try it out

    Students who want to obtain engineering can follow the superhero Jim, send gin in the public account, obtain engineering.

    If you have any more information or suggestions, you can comment in the comments, or you can follow superhero Jim on my instagram, and I’ll get back to you as soon as I see it.

    • We suggest that you pay attention to a wave of public accounts. After the article on GIN framework is finished, we can take you to do a project together to improve your actual combat ability. The public account will be notified as soon as possible

    A preview of the next issue

    • Perfecting the Web Framework
    • Advanced gin framework
    • .