当前位置: 首页 > article >正文

30天学会Go--第6天 GO语言 RESTful API 学习与实践

30天学会Go–第6天 GO语言 RESTful API 学习与实践

文章目录

  • 30天学会Go--第6天 GO语言 RESTful API 学习与实践
    • 一、 RESTful API 的设计原则
      • 1.1 RESTful API 的核心概念
      • 1.2 RESTful API 的 URL 设计
      • 1.3 RESTful API 的数据格式
    • 二、 实现 RESTful API
      • 2.1 定义数据模型
      • 2.2 实现 CRUD 操作(增,删,改,查)
      • 2.3 注册路由并启动服务器
      • 3. 测试 RESTful API
        • 3.1 使用 `curl` 测试(也可以使用 Postman , 这里只做简单测试,故使用 curl)
    • 三、 总结
      • 1. `net/http` 包
        • 函数
        • 接口和方法
      • 2. `encoding/json` 包
        • 函数
        • 方法
      • 3. `strconv` 包
        • 函数
      • 4. `fmt` 包
        • 函数
      • 5. `io` 包
        • 接口

学习 RESTful API 是后端开发的重要环节,它是现代 Web 服务中最普遍的接口设计风格之一。以下将分为 学习内容实践代码 两部分,帮助你快速上手 RESTful API 的设计与实现。

go语言官方编程指南:https://pkg.go.dev/stdopen in new window

go语言的官方文档学习笔记很全,推荐去官网学习

30天学会GO–第5天 GO语言 网络编程:30天学会Go–第5天 GO语言 网络编程-CSDN博客


一、 RESTful API 的设计原则

1.1 RESTful API 的核心概念

RESTful API 是一种基于 HTTP 协议的设计风格,强调资源的表现形式和操作。以下是 RESTful 的核心概念:

  • 资源(Resource)
    • 资源是 API 的核心,例如用户(/users)、文章(/articles)。
    • 每个资源通过一个唯一的 URL 表示,例如 /users/1 表示用户 ID 为 1 的资源。
  • HTTP 方法
    • 不同的 HTTP 方法对应不同的操作:
      • GET:获取资源。
      • POST:创建资源。
      • PUT:更新资源(整体替换)。
      • PATCH:更新资源(部分更新)。
      • DELETE:删除资源。
  • 状态码(Status Code)
    • 使用 HTTP 状态码表示操作结果:
      • 200 OK:请求成功。
      • 201 Created:资源创建成功。
      • 204 No Content:删除成功,无返回内容。
      • 400 Bad Request:请求参数错误。
      • 404 Not Found:资源不存在。
      • 500 Internal Server Error:服务器内部错误。

1.2 RESTful API 的 URL 设计

URL 是 RESTful API 的入口,设计时需要遵循以下原则:

  1. 使用名词表示资源
    • 正确:/users/articles
    • 错误:/getUsers/createArticle
  2. 层次结构清晰
    • 资源的父子关系通过路径表示,例如:
      • /users/1:表示用户 ID 为 1 的用户。
      • /users/1/articles:表示用户 ID 为 1 的所有文章。
  3. 避免动词
    • 操作由 HTTP 方法决定,而不是 URL。
  4. 使用复数形式
    • 资源通常使用复数形式,例如 /users 表示用户集合。

1.3 RESTful API 的数据格式

  • 请求数据

    • URL 参数:适合传递简单的资源标识符,例如 /users/1
    • Query 参数:适合传递筛选条件或分页信息,例如 /users?age=18&page=1&size=10
    • JSON Body:适合传递复杂的数据结构,例如创建或更新资源时的数据。
  • 响应数据

    • 通常使用 JSON 格式返回数据:
      {
        "id": 1,
        "name": "John Doe",
        "email": "john.doe@example.com"
      }
      

二、 实现 RESTful API

以下是一个完整的 RESTful API 示例,使用 Go 的 net/http 包实现。

2.1 定义数据模型

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
)

type User struct {
	ID    int    `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
}

var users = []User{
	{ID: 1, Name: "Alice", Email: "alice@example.com"},
	{ID: 2, Name: "Bob", Email: "bob@example.com"},
}

解读

  1. 定义用户结构体

    • User是一个结构体,表示用户资源。

      • ID:用户的唯一标识符,类型为整数。
      • Name:用户的名称,类型为字符串。
      • Email:用户的电子邮件地址,类型为字符串。
    • JSON 标签:

      • 每个字段后面的反引号部分(如 json:"id")是 JSON 的字段名标签。
        • 当将 User 转换为 JSON 时,字段名会使用标签中指定的名称。
  2. 初始化用户数据

    • 定义了一个全局变量 users,类型为 []User(用户切片)。

      • 模拟了一个简单的“数据库”,存储了两个用户的初始数据:
        • 用户 ID 为 1,名字为 “Alice”,邮箱为 “alice@example.com”。
        • 用户 ID 为 2,名字为 “Bob”,邮箱为 “bob@example.com”。
    • 在实际开发中,这些数据通常存储在数据库中,而不是直接写在代码里。


2.2 实现 CRUD 操作(增,删,改,查)

GET 请求:获取所有用户

func getUsers(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(users)
}

功能

  • 提供一个接口,返回所有用户的数据。
  • 数据以 JSON 格式返回。

解读

  1. 设置响应头部:
    • w.Header().Set("Content-Type", "application/json")
      • 设置响应的 Content-Typeapplication/json,告诉客户端返回的数据是 JSON 格式。
  2. 编码 JSON 并写入响应:
    • json.NewEncoder(w).Encode(users)
      • 使用 json.NewEncoder 将全局变量 users(用户列表)编码为 JSON 格式,并写入 http.ResponseWriter,发送给客户端。

GET 请求:获取单个用户

func getUser(w http.ResponseWriter, r *http.Request) {
	id, err := strconv.Atoi(r.URL.Query().Get("id"))
	if err != nil {
		http.Error(w, "Invalid user ID", http.StatusBadRequest)
		return
	}

	for _, user := range users {
		if user.ID == id {
			w.Header().Set("Content-Type", "application/json")
			json.NewEncoder(w).Encode(user)
			return
		}
	}

	http.Error(w, "User not found", http.StatusNotFound)
}

功能

  • 根据用户 ID 查询单个用户。
  • 如果用户存在,返回用户数据;否则返回 404 Not Found

解读

  1. 获取用户 ID:
    • r.URL.Query().Get("id")
      • 从 URL 查询参数中获取 id 的值。
      • 例如,/users?id=1 中的 id=1
    • strconv.Atoi
      • 将字符串形式的 ID 转换为整数,方便后续比较。
    • 错误处理:
      • 如果 id 无法转换为整数,返回 400 Bad Request
  2. 查找用户:
    • 遍历 users 列表,查找与 id 匹配的用户。
    • 如果找到用户,编码为 JSON 并返回。
  3. 用户未找到:
    • 如果遍历结束后仍未找到用户,返回 404 Not Found

POST 请求:创建用户

func createUser(w http.ResponseWriter, r *http.Request) {
	var newUser User
	err := json.NewDecoder(r.Body).Decode(&newUser)
	if err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	newUser.ID = len(users) + 1
	users = append(users, newUser)

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(newUser)
}

功能

  • 创建一个新用户。
  • 从请求的 JSON 数据中解析用户信息,并将其添加到用户列表中。

解读

  1. 解析请求体:
    • json.NewDecoder(r.Body).Decode(&newUser)
      • 从请求体中读取 JSON 数据,并解析为 User 结构体。
    • 错误处理:
      • 如果解析失败(例如请求体不是有效的 JSON 格式),返回 400 Bad Request
  2. 分配新用户 ID:
    • newUser.ID = len(users) + 1
      • 新用户的 ID 是当前用户列表长度加 1。
      • 这是一个简单的 ID 分配方式,实际项目中通常由数据库生成唯一 ID。
  3. 添加到用户列表:
    • users = append(users, newUser)
      • 将新用户追加到全局变量 users 列表中。
  4. 返回响应:
    • 设置 Content-Typeapplication/json
    • 返回状态码 201 Created,表示资源创建成功。
    • 返回新创建的用户数据。

PUT 请求:更新用户

func updateUser(w http.ResponseWriter, r *http.Request) {
	id, err := strconv.Atoi(r.URL.Query().Get("id"))
	if err != nil {
		http.Error(w, "Invalid user ID", http.StatusBadRequest)
		return
	}

	var updatedUser User
	err = json.NewDecoder(r.Body).Decode(&updatedUser)
	if err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	for i, user := range users {
		if user.ID == id {
			users[i].Name = updatedUser.Name
			users[i].Email = updatedUser.Email

			w.Header().Set("Content-Type", "application/json")
			json.NewEncoder(w).Encode(users[i])
			return
		}
	}

	http.Error(w, "User not found", http.StatusNotFound)
}

功能

  • 根据用户 ID 更新用户信息。
  • 如果用户存在,更新其数据;否则返回 404 Not Found

解读

  1. 获取用户 ID:
    • getUser,从查询参数中获取用户 ID,并转换为整数。
  2. 解析请求体:
    • 使用 json.NewDecoder 解析请求体中的 JSON 数据。
    • 错误处理:
      • 如果请求体不是有效的 JSON 格式,返回 400 Bad Request
  3. 查找并更新用户:
    • 遍历 users 列表,查找与 id 匹配的用户。
    • 如果找到用户,更新其 NameEmail
  4. 返回响应:
    • 如果更新成功,返回状态码 200 OK 和更新后的用户数据。
    • 如果用户未找到,返回 404 Not Found

DELETE 请求:删除用户

func deleteUser(w http.ResponseWriter, r *http.Request) {
	id, err := strconv.Atoi(r.URL.Query().Get("id"))
	if err != nil {
		http.Error(w, "Invalid user ID", http.StatusBadRequest)
		return
	}

	for i, user := range users {
		if user.ID == id {
			users = append(users[:i], users[i+1:]...)
			w.WriteHeader(http.StatusNoContent)
			return
		}
	}

	http.Error(w, "User not found", http.StatusNotFound)
}

功能

  • 根据用户 ID 删除用户。
  • 如果用户存在,删除用户并返回 204 No Content;否则返回 404 Not Found

解读

  1. 获取用户 ID:
    • getUser,从查询参数中获取用户 ID,并转换为整数。
  2. 查找并删除用户:
    • 遍历 users 列表,查找与 id 匹配的用户。
    • 如果找到用户,使用切片操作删除用户:
      • users = append(users[:i], users[i+1:]...)
        • 创建一个新的切片,跳过索引为 i 的用户。
  3. 返回响应:
    • 如果删除成功,返回状态码 204 No Content,表示删除完成且无返回内容。
    • 如果用户未找到,返回 404 Not Found

2.3 注册路由并启动服务器

func main() {
	http.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case http.MethodGet:
			if r.URL.Query().Get("id") != "" {
				getUser(w, r)
			} else {
				getUsers(w, r)
			}
		case http.MethodPost:
			createUser(w, r)
		case http.MethodPut:
			updateUser(w, r)
		case http.MethodDelete:
			deleteUser(w, r)
		default:
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		}
	})

	fmt.Println("Server is running on http://localhost:8080")
	http.ListenAndServe(":8080", nil)
}

功能

  • 注册路由 /users,根据 HTTP 方法调用不同的处理函数。
  • 启动 HTTP 服务器,监听 8080 端口。

解读

  1. 路由注册:

    • 使用 http.HandleFunc 注册路由 /users

    • 根据r.Method

      (HTTP 方法)分发到不同的处理函数:

      • GET:调用 getUsergetUsers
      • POST:调用 createUser
      • PUT:调用 updateUser
      • DELETE:调用 deleteUser
    • 如果方法不被支持,返回 405 Method Not Allowed

  2. 启动服务器:

    • http.ListenAndServe(":8080", nil)
      • 启动 HTTP 服务器,监听 8080 端口。
      • 第二个参数为 nil,表示使用默认的多路复用器。

3. 测试 RESTful API

3.1 使用 curl 测试(也可以使用 Postman , 这里只做简单测试,故使用 curl)
  • 获取所有用户

    curl -X GET http://localhost:8080/users
    
  • 获取单个用户

    curl -X GET "http://localhost:8080/users?id=1"
    
  • 创建用户

    curl -X POST -H "Content-Type: application/json" -d '{"name":"Charlie", "email":"charlie@example.com"}' http://localhost:8080/users
    
  • 更新用户

    curl -X PUT -H "Content-Type: application/json" -d '{"name":"Updated Name", "email":"updated@example.com"}' "http://localhost:8080/users?id=1"
    
  • 删除用户

    curl -X DELETE "http://localhost:8080/users?id=1"
    

三、 总结

在上述 RESTful API 实现中,我们使用了 Go 的标准库 net/httpencoding/json,还有一些辅助包如 strconv

这些函数和方法共同构成了一个完整的 RESTful API 服务的基础工具集。通过这些工具,你可以高效地处理 HTTP 请求和响应,以及 JSON 数据的序列化和反序列化。

以下是每个包中用到的函数和方法的列表(想要深入了解请移步官网):

包名函数/方法
net/httphttp.HandleFunchttp.ListenAndServehttp.Errorw.Header().Setw.WriteHeaderr.Methodr.URL.Query().Get
encoding/jsonjson.NewEncoderjson.NewDecoderEncodeDecode
strconvstrconv.Atoi
fmtfmt.Println
ioio.Readerio.Writer

1. net/http

net/http 是 Go 标准库中用于构建 HTTP 服务的核心包。以下是我们使用的函数和方法:

函数
  • http.HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))

    • 功能:注册路由和对应的处理函数。
    • 示例:http.HandleFunc("/users", handler)
  • http.ListenAndServe(addr string, handler http.Handler) error

    • 功能:启动 HTTP 服务器,监听指定的地址和端口。
    • 示例:http.ListenAndServe(":8080", nil)
  • http.Error(w http.ResponseWriter, error string, code int)

    • 功能:快速返回带有状态码的错误响应。
    • 示例:http.Error(w, "Invalid user ID", http.StatusBadRequest)
接口和方法
  • http.ResponseWriter

    • 用于构建 HTTP 响应。
    • 方法:
      • Header() http.Header
        • 功能:设置响应头。
        • 示例:w.Header().Set("Content-Type", "application/json")
      • Write([]byte)
        • 功能:将字节数据写入响应体。
      • WriteHeader(statusCode int)
        • 功能:设置 HTTP 状态码。
        • 示例:w.WriteHeader(http.StatusCreated)
  • http.Request

    • 表示 HTTP 请求。
    • 属性和方法:
      • Method string
        • 功能:获取请求的 HTTP 方法(如 GETPOST)。
        • 示例:r.Method
      • URL.Query() url.Values
        • 功能:获取 URL 中的查询参数。
        • 示例:r.URL.Query().Get("id")
      • Body io.ReadCloser
        • 功能:读取请求体。
        • 示例:json.NewDecoder(r.Body).Decode(&newUser)

2. encoding/json

encoding/json 是 Go 标准库中用于处理 JSON 数据的包。以下是我们使用的函数和方法:

函数
  • json.NewEncoder(w io.Writer)

    • 功能:创建一个 JSON 编码器,将数据编码为 JSON 格式并写入 io.Writer
    • 示例:json.NewEncoder(w).Encode(users)
  • json.NewDecoder(r io.Reader)

    • 功能:创建一个 JSON 解码器,从 io.Reader 中读取并解析 JSON 数据。
    • 示例:json.NewDecoder(r.Body).Decode(&newUser)
方法
  • Encode(v interface{}) error

    • 功能:将 Go 数据结构编码为 JSON 格式并写入 io.Writer
    • 示例:json.NewEncoder(w).Encode(users)
  • Decode(v interface{}) error

    • 功能:将 JSON 数据解码到指定的 Go 数据结构。
    • 示例:json.NewDecoder(r.Body).Decode(&newUser)

3. strconv

strconv 是 Go 标准库中用于字符串和基本数据类型之间转换的包。以下是我们使用的函数:

函数
  • strconv.Atoi(s string) (int, error)
    • 功能:将字符串转换为整数。
    • 示例:id, err := strconv.Atoi(r.URL.Query().Get("id"))

4. fmt

fmt 是 Go 标准库中用于格式化 I/O 的包。以下是我们使用的函数:

函数
  • fmt.Println(a ...interface{}) (n int, err error)
    • 功能:打印一行内容到标准输出。
    • 示例:fmt.Println("Server is running on http://localhost:8080")

5. io

io 是 Go 标准库中处理流式数据的包。以下是我们间接使用的接口:

接口
  • io.Reader

    • 功能:表示可以读取数据的对象。
    • 示例:r.Body 实现了 io.Reader 接口,用于读取 HTTP 请求体。
  • io.Writer

    • 功能:表示可以写入数据的对象。
    • 示例:whttp.ResponseWriter)实现了 io.Writer 接口,用于写入 HTTP 响应。


http://www.kler.cn/a/428903.html

相关文章:

  • 封装Redis工具类
  • 基于Python的心电图报告解析与心电吸引子绘制
  • 深度学习:大模型Decoding+MindSpore NLP分布式推理详解
  • FastADMIN实现网站启动时执行程序的方法
  • 登录校验Cookie、Session、JWT
  • 21天学通C++——11多态(引入多态的目的)
  • Tomcat(基础篇)
  • <router-view> 中key和name属性的用法详解以及案例
  • 试题转excel;pdf转excel;试卷转Excel,word试题转excel
  • 力扣 对称二叉树-101
  • 如何利用Python爬虫获得商品类目
  • ARM寄存器简介
  • 基于单片机的书写坐姿规范提醒器设计(论文+源码)
  • 粉丝生产力与开源 AI 智能名片 2+1 链动模式商城小程序的融合创新与价值拓展
  • PyTorch 本地安装指南:全面支持 macOS 、 Linux 和 Windows 系统
  • wazuh-modules-sca
  • 麒麟 V10 系统(arm64/aarch64)离线安装 docker 和 docker-compose
  • 使用trace-cmd跟踪Linux内核函数:一次愉快的内核探险
  • BurpSuite-7(自动化漏扫)
  • Redis的五种数据类型(Set、Zset)
  • K8s面试系列:K8s常用 API 资源总结速记
  • Redis过期删除(淘汰)策略概念和理解,以及key已过期内存未释放的处理方式
  • Unity控制物体材质球的改变
  • 解决流网络中不存在s~u~t路径的节点的最大流问题
  • 分享一个开源的网络加速器
  • Vue Web开发(三)