RESTful API
EST stands for Representational State Transfer (English: Representational State Transfer, REST for short). It is a design and development method for network applications, which can reduce the complexity of development and improve the scalability of the system. (Quoted from Baidu Encyclopedia).
HTTP Method
- As early as version 0.9 of HTTP, there was only one GET method, which was an idempotent method used to obtain resources on the server;
- In HTTP version 1.0, the HEAD and POST methods were added. The POST method is commonly used, which is generally used to submit a resource to the server.
- In the HTTP 1.1 version, several methods were added. There are 9 in total.
Their role: - GET method can request a representation of a specified resource. The request using GET should only be used to obtain data.
- HEAD The method is used to request a response that is the same as the response of a GET request, but there is no response body.
- POST The method is used to submit an entity to a specified resource, which usually causes state changes or side effects on the server.
- PUT method is used to request the payload to replace all current representations of the target resource.
- DELETE The method is used to delete the specified resource.
- CONNECT The method is used to establish a tunnel to the server identified by the target resource.
- OPTIONS The method is used to describe the communication options of the target resource.
- TRACE method is used to perform a message loopback test along the path to the target resource.
- PATCH method is used to apply partial modifications to the resource.
In RESTful API, the following five HTTP methods are mainly used:
- GET means to read the resources on the server;
- POST, which means to create a resource on the server;
- PUT means to update or replace the resources on the server;
- DELETE, which means to delete resources on the server;
- PATCH, which means to update/modify a part of the resource.
A simple RESTful API
Golang provides a built-in net/http package to process these HTTP requests, which makes it easier to develop an HTTP service.
Example:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/users",handleUsers)
http.ListenAndServe(":8080", nil)
}
func handleUsers(w http.ResponseWriter, r *http.Request){
fmt.Fprintln(w,"ID:1,Name:张三")
fmt.Fprintln(w,"ID:2,Name:李四")
fmt.Fprintln(w,"ID:3,Name:王五")
}
After running the program, enter http://localhost:8080/users, to see the following content information:
ID:1,Name:张三
ID:2,Name:李四
ID:3,Name:王五
In the example, not only GET can be used to access, but POST, PUT, etc. can also be used. Next, the example will be improved to make it conform to the RESTful API specification:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/users",handleUsers)
http.ListenAndServe(":8080", nil)
}
func handleUsers(w http.ResponseWriter, r *http.Request){
switch r.Method {
case "GET":
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w,"ID:1,Name:张三")
fmt.Fprintln(w,"ID:2,Name:李四")
fmt.Fprintln(w,"ID:3,Name:王五")
default:
w.WriteHeader(http.StatusNotFound)
fmt.Fprintln(w,"not found")
}
}
We have added to the handleUsers function that the information of all users can be obtained only when the GET method is used. In other cases, not found is returned.
RESTful JSON API
In the project interface, data will be transmitted in json format in most cases, and the example is modified again to make it return the content in json format:
package main
import (
"encoding/json"
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/users",handleUsers)
http.ListenAndServe(":8080", nil)
}
//数据源,模拟MySQL中的数据
var users = []User{
{ID: 1,Name: "张三"},
{ID: 2,Name: "李四"},
{ID: 3,Name: "王五"},
}
func handleUsers(w http.ResponseWriter, r *http.Request){
switch r.Method {
case "GET":
users,err:=json.Marshal(users)
if err!=nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprint(w,"{\"message\": \""+err.Error()+"\"}")
}else {
w.WriteHeader(http.StatusOK)
w.Write(users)
}
default:
w.WriteHeader(http.StatusNotFound)
fmt.Fprint(w,"{\"message\": \"not found\"}")
}
}
//用户
type User struct {
ID int
Name string
}
operation result:
[{"ID":1,"Name":"张三"},{"ID":2,"Name":"李四"},{"ID":3,"Name":"王五"}]
This time, we created a new User structure, used the users slice to store all users, and then converted it into a JSON array in the handleUsers function to return.
Gin framework
Above we are using the net/http package that comes with the Go language. The writing method is relatively simple, but it also has many shortcomings:
- It is not possible to individually register specific processing functions for the request method (POST, GET, etc.);
- Does not support Path variable parameters;
- The Path cannot be calibrated automatically;
- General performance, insufficient scalability;
- ……
Based on the above shortcomings, we can use other Golang web frameworks, such as the Gin framework we will introduce today.
Introduce the Gin framework
The Gin framework is an open source web framework on Github. It encapsulates many functions required for web development and has very high performance, making it easy to write RESTful APIs.
The Gin framework is actually a module, which can be introduced using the Go Mod method:
- Download and install the Gin framework
go get -u github.com/gin-gonic/gin
- Import and use in Go language code
import "github.com/gin-gonic/gin"
Use Gin framework
We use the Gin framework to rewrite the above example:
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/users", listUser)
r.Run(":8080")
}
func listUser(c *gin.Context) {
c.JSON(200, users)
}
//数据源,模拟MySQL中的数据
var users = []User{
{ID: 1, Name: "张三"},
{ID: 2, Name: "李四"},
{ID: 3, Name: "王五"},
}
//用户
type User struct {
ID int
Name string
}
Compared with the net/http package, the code of the Gin framework is very simple. You can create a service that only processes the HTTP GET method through the GET method, and use the c.JSON method to output data in JSON format.
Start the HTTP service through the Run method and monitor port 8080. Run this Gin example, enter http://localhost:8080/users in the browser, you can see that the effect is the same as that achieved
Get a user
To obtain a user's information, we use the GET method, and the designed URL format is:http://localhost:8080/users/1
The number 1 in the url is the user id, we get a specified user by id:
func main() {
//省略其它没有改动过的代码
r.GET("/users/:id", getUser)
}
func getUser(c *gin.Context) {
id := c.Param("id")
var user User
found := false
//类似于数据库的SQL查询
for _, u := range users {
if strings.EqualFold(id, strconv.Itoa(u.ID)) {
user = u
found = true
break
}
}
if found {
c.JSON(200, user)
} else {
c.JSON(404, gin.H{
"message": "用户不存在",
})
}
}
In the Gin framework, a colon is used in the path to indicate the Path parameter, such as :id in the example, and then the ID value of the user who needs to be queried is obtained through c.Param("id").
Run the example, visit the address http://localhost:8080/users/1
, you can get the user with ID 1: {"ID":1,"Name":"Zhang San"}
Add a new user
The URL format of a new user is:http://localhost:8080/users
Send data to this URL to add a new user.
func main() {
//省略其它没有改动过的代码
r.POST("/users", createUser)
}
func createUser(c *gin.Context) {
name := c.DefaultPostForm("name", "")
if name != "" {
u := User{ID: len(users) + 1, Name: name}
users = append(users, u)
c.JSON(http.StatusCreated,u)
} else {
c.JSON(http.StatusOK, gin.H{
"message": "请输入用户名称",
})
}
}
The logic of adding a user is to obtain the name value uploaded by the client, then generate a User user, and finally store it in the users collection.
We use the curl command to send a new user request:
curl -X POST -d 'name=无尘' http://localhost:8080/users
{"ID":4,"Name":"无尘"}
It can be seen that the new user is successfully added, and the newly added user and the assigned ID are returned.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。