`

Gin+Mysql简单的Restful风格的API

gin 
阅读更多

使用Gin的前提是安装,我们需要安装gin和mysql的驱动,具体的安装方式就不在赘述。可以参考Golang 微框架Gin简介Golang持久化

创建一个文件夹用来为项目,新建一个文件main.go:

☁  newland  tree
.
└── main.go

main.go

package main

import (
 "gopkg.in/gin-gonic/gin.v1"
 "net/http"
)

func main() {
 router := gin.Default()

 router.GET("/", func(c *gin.Context) {
  c.String(http.StatusOK, "It works")
 })

 router.Run(":8000")
}

编译运行

☁  newland  go run main.go
[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] GET    /                         --> main.main.func1 (3 handlers)
[GIN-debug] Listening and serving HTTP on :8000

访问 /即可看见我们返回的字串It works

数据库

安装完毕框架,完成一次请求响应之后。接下来就是安装数据库驱动和初始化数据相关的操作了。首先,我们需要新建数据表。一个及其简单的数据表:

CREATE TABLE `person` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(40) NOT NULL DEFAULT '',
  `last_name` varchar(40) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建数据表之后,初始化数据库连接池:

func main() {

 db, err := sql.Open("mysql", "root:@tcp(127.0.0.1:3306)/test?parseTime=true")
 defer db.Close()
 if err != nil{
  log.Fatalln(err)
 }


 db.SetMaxIdleConns(20)
 db.SetMaxOpenConns(20)

 if err := db.Ping(); err != nil{
  log.Fatalln(err)
 }

 router := gin.Default()
 router.GET("/", func(c *gin.Context) {
  c.String(http.StatusOK, "It works")
 })

 router.Run(":8000")
}

使用sql.Open方法会创建一个数据库连接池db。这个db不是数据库连接,它是一个连接池,只有当真正数据库通信的时候才创建连接。例如这里的db.Ping的操作。db.SetMaxIdleConns(20)db.SetMaxOpenConns(20)分别设置数据库的空闲连接和最大打开连接,即向Mysql服务端发出的所有连接的最大数目。

如果不设置,默认都是0,表示打开的连接没有限制。我在压测的时候,发现会存在大量的TIME_WAIT状态的连接,虽然mysql的连接数没有上升。设置了这两个参数之后,不在存在大量TIME_WAIT状态的连接了。而且qps也没有明显的变化,出于对数据库的保护,最好设置这连个参数。

CURD 增删改查

Restful的基本就是对资源的curd操作。下面开启我们的第一个api接口,增加一个资源。

func main() {

 ...

 router.POST("/person", func(c *gin.Context) {
  firstName := c.Request.FormValue("first_name")
  lastName := c.Request.FormValue("last_name")

  rs, err := db.Exec("INSERT INTO person(first_name, last_name) VALUES (?, ?)", firstName, lastName)
  if err != nil {
   log.Fatalln(err)
  }

  id, err := rs.LastInsertId()
  if err != nil {
   log.Fatalln(err)
  }
  fmt.Println("insert person Id {}", id)
  msg := fmt.Sprintf("insert successful %d", id)
  c.JSON(http.StatusOK, gin.H{
   "msg": msg,
  })
 })

 ...
}

执行非query操作,使用db的Exec方法,在mysql中使用?做占位符。最后我们把插入后的id返回给客户端。请求得到的结果如下:

☁  ~  curl -X POST http://127.0.0.1:8000/person -d "first_name=hello&last_name=world" | python -m json.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    62  100    30  100    32   5054   5391 --:--:-- --:--:-- --:--:--  6400
{
    "msg": "insert successful 1"
}

下面可以随意增加几条记录。

查询列表 Query

上面我们增加了一条记录,下面就获取这个记录,查一般有两个操作,一个是查询列表,其次就是查询具体的某一条记录。两种大同小异。

为了给查询结果绑定到golang的变量或对象,我们需要先定义一个结构来绑定对象。在main函数的上方定义Person结构:

type Person struct {
 Id        int    `json:"id" form:"id"`
 FirstName string `json:"first_name" form:"first_name"`
 LastName  string `json:"last_name" form:"last_name"`
}

然后查询我们的数据列表

 router.GET("/persons", func(c *gin.Context) {
  rows, err := db.Query("SELECT id, first_name, last_name FROM person")
  defer rows.Close()

  if err != nil {
   log.Fatalln(err)
  }

  persons := make([]Person, 0)

  for rows.Next() {
   var person Person
   rows.Scan(&person.Id, &person.FirstName, &person.LastName)
   persons = append(persons, person)
  }
  if err = rows.Err(); err != nil {
   log.Fatalln(err)
  }

  c.JSON(http.StatusOK, gin.H{
   "persons": persons,
  })

 })

读取mysql的数据需要有一个绑定的过程,db.Query方法返回一个rows对象,这个数据库连接随即也转移到这个对象,因此我们需要定义row.Close操作。然后创建一个[]Person的切片。

使用make,而不是直接使用var persons []Person的声明方式。还是有所差别的,使用make的方式,当数组切片没有元素的时候,Json会返回[]。如果直接声明,json会返回null

接下来就是使用rows对象的Next方法,遍历所查询的数据,一个个绑定到person对象上,最后append到persons切片。

☁  ~  curl  http://127.0.0.1:8000/persons | python -m json.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   113  100   113    0     0   101k      0 --:--:-- --:--:-- --:--:--  110k
{
    "persons": [
        {
            "first_name": "hello",
            "id": 1,
            "last_name": "world"
        },
        {
            "first_name": "vanyar",
            "id": 2,
            "last_name": "elves"
        }
    ]
}
查询单条记录 QueryRow

查询列表需要使用迭代rows对象,查询单个记录,就没这么麻烦了。虽然也可以迭代一条记录的结果集。因为查询单个记录的操作实在太常用了,因此golang的database/sql也专门提供了查询方法

 router.GET("/person/:id", func(c *gin.Context) {
  id := c.Param("id")
  var person Person
  err := db.QueryRow("SELECT id, first_name, last_name FROM person WHERE id=?", id).Scan(
   &person.Id, &person.FirstName, &person.LastName,
  )
  if err != nil {
   log.Println(err)
   c.JSON(http.StatusOK, gin.H{
    "person": nil,
   })
   return
  }

  c.JSON(http.StatusOK, gin.H{
   "person": person,
  })

 })

查询结果为:

☁  ~  curl  http://127.0.0.1:8000/person/1 | python -m json.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    60  100    60    0     0  20826      0 --:--:-- --:--:-- --:--:-- 30000
{
    "person": {
        "first_name": "hello",
        "id": 1,
        "first_name": "world"
    }
}

查询单个记录有一个小问题,当数据不存在的时候,同样也会抛出一个错误。粗暴的使用log退出有点不妥。返回一个nil的时候,万一真的是因为错误,比如sql错误。这种情况如何解决。还需要具体场景设计程序。

增删改查,下面进行更新的操作。前面增加记录我们使用了urlencode的方式提交,更新的api我们自动匹配绑定content-type

 router.PUT("/person/:id", func(c *gin.Context) {
  cid := c.Param("id")
  id, err := strconv.Atoi(cid)
  person := Person{Id: id}
  err = c.Bind(&person)
  if err != nil {
   log.Fatalln(err)
  }

  stmt, err := db.Prepare("UPDATE person SET first_name=?, last_name=? WHERE id=?")
  defer stmt.Close()
  if err != nil {
   log.Fatalln(err)
  }
  rs, err := stmt.Exec(person.FirstName, person.LastName, person.Id)
  if err != nil {
   log.Fatalln(err)
  }
  ra, err := rs.RowsAffected()
  if err != nil {
   log.Fatalln(err)
  }
  msg := fmt.Sprintf("Update person %d successful %d", person.Id, ra)
  c.JSON(http.StatusOK, gin.H{
   "msg": msg,
  })
 })

使用 urlencode的方式更新:

☁  ~  curl -X PUT http://127.0.0.1:8000/person/2 -d "first_name=noldor&last_name=elves" | python -m json.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    72  100    39  100    33   3921   3317 --:--:-- --:--:-- --:--:--  4333
{
    "msg": "Update person 2 successful 1"
}

使用json的方式更新:

☁  ~  curl -X PUT http://127.0.0.1:8000/person/2 -H "Content-Type: application/json"  -d '{"first_name": "vanyar", "last_name": "elves"}' | python -m json.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    85  100    39  100    46   4306   5079 --:--:-- --:--:-- --:--:--  5750
{
    "msg": "Update person 2 successful 1"
}

最后一个操作就是删除了,删除所需要的功能特性,上面的例子都覆盖了。实现删除也就特别简单了:

 router.DELETE("/person/:id", func(c *gin.Context) {
  cid := c.Param("id")
  id, err := strconv.Atoi(cid)
  if err != nil {
   log.Fatalln(err)
  }
  rs, err := db.Exec("DELETE FROM person WHERE id=?", id)
  if err != nil {
   log.Fatalln(err)
  }
  ra, err := rs.RowsAffected()
  if err != nil {
   log.Fatalln(err)
  }
  msg := fmt.Sprintf("Delete person %d successful %d", id, ra)
  c.JSON(http.StatusOK, gin.H{
   "msg": msg,
  })
 })

我们可以使用删除接口,把数据都删除了,再来验证上面post接口获取列表的时候,当记录没有的时候,切片被json序列化[]还是null

☁  ~  curl  http://127.0.0.1:8000/persons | python -m json.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    15  100    15    0     0  11363      0 --:--:-- --:--:-- --:--:-- 15000
{
    "persons": []
}

persons := make([]Person, 0)改成persons []Person。编译运行:

☁  ~  curl  http://127.0.0.1:8000/persons | python -m json.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    17  100    17    0     0  13086      0 --:--:-- --:--:-- --:--:-- 17000
{
    "persons": null
}

至此,基本的CURD操作的restful风格的API已经完成。内容其实不复杂,甚至相当简单。完整的代码可以通过GIST获取。

组织代码

实现了一个基本点restful服务,可惜我们的代码都在一个文件中。对于一个库,单文件或许很好,对于稍微大一点的项目,单文件总是有点非主流。当然,更多原因是为了程序的可读和维护,我们也需要重新组织代码,拆分模块和包。

封装模型方法

我们的handler出来函数中,对请求的出来和数据库的交互,都糅合在一起。首先我们基于创建的Person结构创建数据模型,以及模型的方法。把数据库交互拆分出来。

创建一个单例的数据库连接池对象:

var db *sql.DB

func main() {
 var err error
 db, err = sql.Open("mysql", "root:@tcp(127.0.0.1:3306)/test?parseTime=true")
 if err != nil {
  log.Fatalln(err)
 }

 defer db.Close()

 if err := db.Ping(); err != nil {
  log.Fatalln(err)
 }
 ...
}

这样在main包中,db就能随意使用了。

接下来,再把增加记录的的函数封装成Person结构的方法:

func (p *Person) AddPerson() (id int64, err error) {
 rs, err := db.Exec("INSERTs INTO person(first_name, last_name) VALUES (?, ?)", p.FirstName, p.LastName)
 if err != nil {
  return
 }
 id, err = rs.LastInsertId()
 return
}

然后handler函数也跟着修改,先创建一个Person结构的实例,然后调用其方法即可:

 router.POST("/person", func(c *gin.Context) {
  firstName := c.Request.FormValue("first_name")
  lastName := c.Request.FormValue("last_name")

  person := Person{FirstName: firstName, LastName: lastName}

  ra_rows, err := person.AddPerson()
  if err != nil {
   log.Fatalln(err)
  }
  msg := fmt.Sprintf("insert successful %d", ra_rows)
  c.JSON(http.StatusOK, gin.H{
   "msg": msg,
  })
 })

对于获取列表的模型方法和handler函数也很好改:

func (p *Person) GetPersons() (persons []Person, err error) {
 persons = make([]Person, 0)
 rows, err := db.Query("SELECT id, first_name, last_name FROM person")
 defer rows.Close()

 if err != nil {
  return
 }

 for rows.Next() {
  var person Person
  rows.Scan(&person.Id, &person.FirstName, &person.LastName)
  persons = append(persons, person)
 }
 if err = rows.Err(); err != nil {
  return
 }
 return
}

 router.POST("/person", func(c *gin.Context) {
  firstName := c.Request.FormValue("first_name")
  lastName := c.Request.FormValue("last_name")

  person := Person{FirstName: firstName, LastName: lastName}

  ra_rows, err := person.AddPerson()
  if err != nil {
   log.Fatalln(err)
  }
  msg := fmt.Sprintf("insert successful %d", ra_rows)
  c.JSON(http.StatusOK, gin.H{
   "msg": msg,
  })
 })

剩下的函数和方法就不再一一举例了。

增加记录的接口中,我们使用了客户端参数和Person创建实例,然后再调用其方法。而获取列表的接口中,我们直接声明了Person对象。两种方式都可以。

Handler函数

gin提供了router.Get(url, handler func)的格式。首先我们可以把所有的handler函数从router中提取出来。

例如把增加记录和获取列表的handle提取出来

func AddPersonApi(c *gin.Context) {
 firstName := c.Request.FormValue("first_name")
 lastName := c.Request.FormValue("last_name")

 person := Person{FirstName: firstName, LastName: lastName}

 ra_rows, err := person.AddPerson()
 if err != nil {
  log.Fatalln(err)
 }
 msg := fmt.Sprintf("insert successful %d", ra_rows)
 c.JSON(http.StatusOK, gin.H{
  "msg": msg,
 })
}

func main(){
 ...
 router.POST("/person", AddPersonApi)
 ... 
}

把modle和handler抽出来之后,我们的代码结构变得更加清晰,具体可以参考这个GIST

组织项目

经过上面的model和handler的分离,代码结构变得更加清晰,可是我们还是单文件。下一步将进行封装不同的包。

数据库处理

在项目根目录创建下面三个文件夹,apisdatabasesmodels,并在文件夹内创建文件。此时我们的目录结果如下:

☁  newland  tree
.
├── apis
│   └── person.go
├── database
│   └── mysql.go
├── main.go
├── models
│   └── person.go
└── router.go

apis文件夹存放我们的handler函数,models文件夹用来存放我们的数据模型。

myql.go的包代码如下:

package database

import (
 "database/sql"
 _ "github.com/go-sql-driver/mysql"
 "log"
)

var SqlDB *sql.DB

func init() {
 var err error
 SqlDB, err = sql.Open("mysql", "root:@tcp(127.0.0.1:3306)/test?parseTime=true")
 if err != nil {
  log.Fatal(err.Error())
 }
 err = SqlDB.Ping()
 if err != nil {
  log.Fatal(err.Error())
 }
}

因为我们需要在别的地方使用SqlDB这个变量,因此依照golang的习惯,变量名必须大写开头。

数据model封装

修改models文件夹下的person.go,把对应的Person结构及其方法移到这里:

package models

import (
 "log"
 db "newland/database"
)

type Person struct {
 Id        int    `json:"id" form:"id"`
 FirstName string `json:"first_name" form:"first_name"`
 LastName  string `json:"last_name" form:"last_name"`
}

func (p *Person) AddPerson() (id int64, err error) {
 rs, err := db.SqlDB.Exec("INSERT INTO person(first_name, last_name) VALUES (?, ?)", p.FirstName, p.LastName)
 if err != nil {
  return
 }
 id, err = rs.LastInsertId()
 return
}

func (p *Person) GetPersons() (persons []Person, err error) {
 persons = make([]Person, 0)
 rows, err := db.SqlDB.Query("SELECT id, first_name, last_name FROM person")
 defer rows.Close()

 if err != nil {
  return
 }

 for rows.Next() {
  var person Person
  rows.Scan(&person.Id, &person.FirstName, &person.LastName)
  persons = append(persons, person)
 }
 if err = rows.Err(); err != nil {
  return
 }
 return
}

....

handler

然后把具体的handler函数封装到api包中,因为handler函数要操作数据库,所以会引用model包

package apis

import (
 "net/http"
 "log"
 "fmt"
 "strconv"
 "gopkg.in/gin-gonic/gin.v1"
 . "newland/models"
)

func IndexApi(c *gin.Context) {
 c.String(http.StatusOK, "It works")
}

func AddPersonApi(c *gin.Context) {
 firstName := c.Request.FormValue("first_name")
 lastName := c.Request.FormValue("last_name")

 p := Person{FirstName: firstName, LastName: lastName}

 ra, err := p.AddPerson()
 if err != nil {
  log.Fatalln(err)
 }
 msg := fmt.Sprintf("insert successful %d", ra)
 c.JSON(http.StatusOK, gin.H{
  "msg": msg,
 })
}

...

路由

最后就是把路由抽离出来,修改router.go,我们在路由文件中封装路由函数

package main

import (
 "gopkg.in/gin-gonic/gin.v1"
 . "newland/apis"
)

func initRouter() *gin.Engine {
 router := gin.Default()

 router.GET("/", IndexApi)

 router.POST("/person", AddPersonApi)

 router.GET("/persons", GetPersonsApi)

 router.GET("/person/:id", GetPersonApi)

 router.PUT("/person/:id", ModPersonApi)

 router.DELETE("/person/:id", DelPersonApi)

 return router
}

app入口

最后就是main函数的app入口,将路由导入,同时我们要在main函数结束的时候,关闭全局的数据库连接池:

main.go

package main

import (
 db "newland/database"
)

func main() {
 defer db.SqlDB.Close()
 router := initRouter()
 router.Run(":8000")
}

至此,我们就把简单程序进行了更好的组织。当然,golang的程序组织依包为基础,不拘泥,根据具体的应用场景可以组织。

此时运行项目,不能像之前简单的使用go run main.go,因为包main包含main.go和router.go的文件,因此需要运行go run *.go命令编译运行。如果是最终编译二进制项目,则运行go build -o app

总结

通过上述的实践,我们了解了Gin框架创建基本的的restful服务。并且了解了如何组织golang的代码包。我们讨论了很多内容,但是唯独缺少测试。测试很重要,考察一个框架或者三方包的时候,是否有测试文件以及测试覆盖率是一个重要的参考。因为测试的内容很多,我们这里就不做单独的测试介绍。后面会结合gofight给gin的api增加测试代码。

此外,更多的内容,可以阅读别人优秀的开源项目,学习并实践,以提升自己的编码能力。

本文来自:简书

感谢作者:人世间

查看原文:Gin实战:Gin+Mysql简单的Restful风格的API

 

https://studygolang.com/articles/9630

分享到:
评论

相关推荐

    基于 gin+gorm+redis+mysql 读写分离的心理咨询系统源码.zip

    Gin是Go语言的一个轻量级Web框架,它提供了快速开发RESTful API的能力。Gin使用中间件来处理HTTP请求,具备路由管理、错误处理、JSON响应等功能。在本项目中,Gin用于构建HTTP服务器,处理来自客户端的请求,并将...

    Go-easy-gin一套基于Gin框架的MVC脚手架

    4. **Restful API 示例**:内置的示例代码可以帮助开发者理解如何使用Gin框架创建RESTful风格的API接口,涵盖CRUD(创建、读取、更新、删除)操作。 三、快速构建Go Web工程 使用"Go-easy-gin",你可以按照以下...

    Python-Ginbro以最快的方式将MySQL数据库转换为RESTfulgolangAPI应用

    Ginbro是一个高效且便捷的Python工具,专门设计用于帮助开发者快速将MySQL数据库转化为RESTful风格的Golang API应用程序。这个工具结合了Python的易用性和Golang的高性能,使得在后端服务开发中能够节省大量时间和...

    Go-gen-将数据库转换为gorm结构体和RESTfulapi

    GORM是一个优秀的Go语言数据库 ORM 库,它提供了简单易用的API来处理SQL,支持SQLite、MySQL、PostgreSQL和SQL Server等数据库。通过GORM,我们可以在Go中直接操作数据库对象,避免编写大量的SQL语句。 RESTful API...

    基于Gin框架开发的脚手架工具,便于使用Go快速开发接口,集成数据库、日志、配置等开源库,开箱即用.zip

    Gin框架基于Martini框架进行优化,提供了更强大的路由功能和中间件管理,使得Go语言在构建RESTful API时更加得心应手。 在标题中提到的“基于Gin框架开发的脚手架工具”,意味着这个项目提供了一个快速搭建Go应用的...

    Gobarber-api

    "GoBarber-api" 是一个基于Go语言开发的RESTful API服务,主要用于构建一个预约理发师的在线平台。在这个项目中,开发者可以学习到如何利用Go语言的强大功能来设计和实现一个完整的后端系统,包括用户管理、预约、...

    Newsfeeder:使用Go和Gin构建的REST API,用于将文章存储在新闻源中

    【Newsfeeder:Go与Gin构建的RESTful API实现新闻源管理】 Newsfeeder是一个用Go编程语言和Gin框架构建的RESTful API服务,主要用于处理新闻源中的文章存储和检索。Go语言以其高性能、并发支持和简洁的语法而闻名,...

    Go-Go-Social-Blogging-App一个利用Golang和MySQL开发的社交博客应用程序

    - **RESTful API**:项目可能遵循RESTful架构风格,提供清晰、可预测的HTTP端点,用于客户端(如移动应用或Web前端)与服务端通信。 7. **错误处理与日志记录** - **错误处理**:良好的错误处理机制能确保程序在...

    go-fly:开源客服系统GO语言开发GO-FLY,免费客服系统golang的开源实时客户聊天

    使用gin http框架实现restful风格的API和模板包的模板语法进行展示界面 2.使用jwt-go配合gin中间件实现无状态的jwt登陆认证 3.数据库实现的rbac权限配合gin中间件实现权限控制 4.通过cobra进行命令行参数解析和执行...

    开源项目-sauerbraten-crudapi.zip

    开源项目"Sauerbraten-crudapi"是一个使用Golang语言实现的RESTful风格API,它为开发者提供了一种高效、简洁的方式来创建、读取、更新和删除(CRUD)数据。Golang,又称为Go语言,是Google推出的一种静态类型、编译...

    核酸采样点一站查毕业论文 go+微信小程序

    2. **相关开发技术概述**:这里介绍了用于项目开发的各种技术,包括Go语言、Gin框架、RESTful架构风格、MySQL数据库以及微信小程序的开发规范和技术。 3. **相关技术及需求分析**:在需求分析基础上,确定了设计...

    开源项目-AlexanderChen1989-xrest.zip

    RESTful API则是遵循REST(Representational State Transfer,表述性状态转移)原则的API设计风格,通过HTTP方法(如GET、POST、PUT、DELETE)来操作资源。 在Go语言中,`context.Context`是处理并发和请求生命周期...

    bookstore_users-api:用户API

    REST(Representational State Transfer)是一种网络应用程序的设计风格和开发方式,基于HTTP协议,使得客户端和服务器之间的交互变得简单。用户API可能提供了创建、读取、更新和删除(CRUD)用户信息的端点,例如...

    zendea:使用Go语言编写的免费,开放源代码,自托管的论坛软件官方QQ群:656868

    基于Go语言开发,提供Restful风格接口。 技术栈 gin () Go web 框架 JWT () JWT Middleware for Gin framework gorm () Go 语言 orm 框架 frontend 前端页面渲染服务,基于nuxt.js实现。 技术栈 Nuxt

    bookstore_items-api:书店物品

    总结来说,【bookstore_items-api】是一个使用Go语言开发的书店物品管理API,涵盖了Go语言的并发特性、RESTful API设计原则、Web开发框架、数据库操作、错误处理、日志记录、身份验证等多个重要知识点。通过这个项目...

    devbook-api

    2. **RESTful API 设计**: REST(Representational State Transfer)是一种架构风格,用于构建 Web 服务。API 常常遵循 RESTful 原则,提供 CRUD(创建、读取、更新、删除)操作。HTTP 方法如 GET、POST、PUT、...

    hyperschedule-api-go:Go中的超调度API

    1. API设计原则:遵循RESTful架构风格,通过HTTP方法(GET、POST、PUT、DELETE)来操作资源,使用JSON作为数据交换格式。 2. 路由处理:使用Go的第三方库如Gin或Echo,定义路由规则来处理不同的HTTP请求。 3. 数据...

    goblog博客系统源代码 一个基于golang开发的博客系统

    7. **RESTful API**: goblog可能采用了RESTful架构设计API,使博客系统可以通过HTTP协议提供服务,便于与其他系统集成,同时提高接口的可理解性和可维护性。 8. **版本控制**: 开源项目通常使用Git进行版本控制...

    开源项目-kennygrant-gohackernews.zip

    5. **RESTful API设计**:项目遵循RESTful架构风格,通过HTTP方法(GET、POST、PUT、DELETE等)来操作资源,实现客户端与服务器的通信。 6. **JSON序列化与反序列化**:由于Web API通常使用JSON格式传输数据,项目...

Global site tag (gtag.js) - Google Analytics