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 ones
MVC
Pattern to design the directory structure - Use the go language interface to encapsulate some
behavior
orbusiness
Convenient 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 it
mid.go
androuter.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
- in
server
Creating a Directoryserver.go
file
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 the
main.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 the
xorm
Used as a persistence layer - At the same time use
go-sql-driver/mysql
As 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
- in
model
newuser.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
- in
api
Creating 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
- .