【 设计规范】 RESTful API详解

系列综述:
💞目的:本系列是个人整理为了学习RESTful API规范的,整理期间苛求每个知识点,平衡理解简易度与深入程度。
🥰来源:材料架构主要源于GPT进行的,每个知识点的修正和深入主要参考各平台大佬的文章,其中也可能含有少量的个人实验自证。
🤭结语:如果有帮到你的地方,就点个赞关注一下呗,谢谢🎈🎄🌷!!!



😊点此到文末惊喜↩︎


概述

基本概念

  1. REST:表述状态转移(Representational State Transfer)是一种软件架构设计风格,而不是标准,只是提供了一组设计原则和约束条件
    • 表述:是指客户端获取的资源的一种外在表示形式,包括数据描述数据的元数据
    • 状态转移:
      • 前提:客户端负责维护应用状态,而服务端维护资源状态,但每次交互是无状态的(每次请求包含请求所需所有信息)
      • 本质:会话被客户端作为应用状态进行跟踪,客户端通过HTTP协议的资源操作进行状态转移
    • RESTful:基于 REST 风格构建的网络应用程序接口(API)的约定设计规范
  2. URI统一资源标识符
    • 定义:用来标识抽象资源的字符串,通常是资源名称位置的结合(资源和URI是一对多的关系)
    • 分类
      • URL统一资源定位:用于定位资源的具体位置,并提供访问资源的方式(如协议、主机名、路径等)
      • URN统一资源名称:用于标识资源的唯一名称,与资源的位置无关,即使资源位置变化,URN 仍然有效
    • 特点:一切皆资源
      • 将网络中所有能被操作的对象都视为资源,每个资源都用唯一的 URI 来标识,方便客户端准确地定位和访问
      • 通过统一资源标识符(URI)来对资源进行定位,使用 HTTP 协议中定义的方法(如 GET、POST、PUT、DELETE 等)对这些资源进行操作,从而实现客户端与服务器之间的通信。
  3. RESTful 6 大原则(REST 架构的 6 个限制条件)
    • 接口统一(Uniform Interface):使用 HTTP 协议的标准方法(如 GET、POST、PUT等)来操作资源,请求和响应都遵循格式规范
    • 无状态(Stateless):每次请求包含所有的必要信息,服务端不会保存客户端状态
    • CS分离(C-S Separation):强调客户端与服务端分离,服务端具备独立性,从而能够应用于前端、安卓、IOS 等多种客户端设备
    • 可缓存性(Cacheability):服务端 回复是否客户端缓存的响应,从而使客户端缓存提高效率
    • 分层系统(Layered System):客户端只需按规范发送请求,无需关心中间经过的多层代理或服务
    • 资源导向(Resource-Based):将系统中的所有内容抽象为资源,每个资源有唯一的标识符(URI)
      在这里插入图片描述
  4. 传统和Restful请求方式的不同
    • 本质:通过请求方法类型表示对于请求资源的不同处理方式,从而实现同一路径的多态处理
      在这里插入图片描述

设计规范

Request设计规范

  1. Request构成
    • 请求路径:常用多个名词组成一个URL标识一个资源,注意
    • 请求行为:通常使用动词(GET、POST、PUT、DELETE等 )操作URL资源
  2. 请求路径规范
    • 基础规范:scheme "://" host ":" port "/" path [ "?" query ][ "#" fragment ]
      • scheme: 指底层用的协议,如http、https、ftp
      • host: 服务器的IP地址或者域名
      • port: 端口,http默认为80端口
      • path: 访问资源的路径,就是各种web 框架中定义的route路由
      • query: 查询字符串,为发送给服务器的参数,在这里更多发送数据分页、排序等参数。
      • fragment: 锚点,定位到页面的具体资源
    • path规范:/{版本号}/ ... /{资源集合s}/{资源id}(遵循可寻址自描述性
      • 路径反映请求含义
        • 使用小写英文名词和连字符中杠-组成
        • 通过/标识资源层级(结尾没有),不要过深且靠前的层级应该相对稳定
      • 资源集用复数:如/articles而非/article
      • 同级资源:通过,;来表示分隔表示
      • 资源格式:通过资源名后缀来区分不同的资源格式,如xml、json等
  3. 请求行为规范
HTTP Method安全性 (不修改服务器数据)幂等性(每次执行结果一致)解释示例
GET安全(读安全,写危险)幂等从服务器查询SELECT资源对象或集合获取用户列表:[GET] /v1/users
获取特定用户:[GET] /v1/users/{id}
POST非安全非幂等在服务器中创建CREATE资源,返回新资源对象新建用户:[POST] /v1/users
PUT非安全幂等用于更新UPDATE资源,返回完整资源对象更新用户:[PUT] /v1/users/{id}
DELETE非安全幂等用于删除DELETE资源,通常返回一个空文档或删除成功状态码删除用户:[DELETE] /v1/users/{id}
  1. 遵循 RESTful 分层系统架构的请求处理过程
    • 客户端发起请求:客户端根据业务需求,按照 RESTful 规范构建请求。包含资源访问的请求路径URL和合适的HTTP请求行为 ,以及其他必要的请求信息,如用户登录token和期望资源格式等
    • 代理服务器处理请求(若存在):
      • 验证请求:接收客户端发送的请求后,对请求进行身份、IP地址等合法性的检查
      • 修改请求:保持核心内容不会改变,但可能修改请求头中的部分字段,比如添加标识信息,或根据配置对请求参数进行调整等
      • 转发请求:根据配置策略,转发到负载均衡器或其他中间服务器
    • 负载均衡器进行分发(若存在):
      • 负载均衡决策:负载均衡器接收到请求后,会根据内置负载均衡算法来决定将该请求分配到哪一台资源服务器上
      • 请求分配:将请求转发到对应的资源服务器,确保各个资源服务器的负载相对均衡
    • 资源服务器处理请求
      • 解析请求:资源服务器接收到来自负载均衡器的请求后,会解析请求的资源路径和行为
      • 执行业务逻辑:根据解析出的请求内容,资源服务器执行相应的业务逻辑,如数据库操作、格式转换等
      • 生成响应:在完成对请求的处理后,资源服务器会根据处理结果生成响应信息。

Response设计规范

  1. Response构成
    • 响应状态码:用于表示请求的处理结果,通常遵循 HTTP 标准状态码。
    • 响应头(Headers):包含响应的元数据信息。
    • 响应体(Body):包含请求的详细结果或资源数据。
  2. 响应状态码设计规范
    • 2xx状态码:表示请求成功。
      • 200 OK:请求成功,返回请求的资源或操作结果。
      • 201 Created:资源创建成功,通常用于 POST 请求,返回新创建的资源。
      • 204 No Content:请求成功,但无内容返回,通常用于 DELETE 请求。
    • 4xx状态码:表示客户端错误。
      • 400 Bad Request:请求无效,通常因为请求数据格式错误。
      • 401 Unauthorized:请求未授权,用户未通过身份验证。
      • 403 Forbidden:用户无权访问该资源。
      • 404 Not Found:请求的资源不存在。
    • 5xx状态码:表示服务器错误。
      • 500 Internal Server Error:服务器内部错误,无法完成请求。
      • 503 Service Unavailable:服务器暂时无法处理请求,通常用于维护或过载状态。
  3. 响应头(Headers)设计规范
    • Content-Type:指定响应体的格式,例如:
      • application/json:表示响应体是 JSON 格式。
      • application/xml:表示响应体是 XML 格式。
      • text/plain:表示响应体是纯文本格式。
    • Location:用于 POST 请求,返回新创建资源的 URI
    • Cache-Control:指示客户端是否可以缓存响应,以及缓存的有效期。
    • ETag:用于资源版本控制,帮助客户端判断资源是否已更新。
    • 注意:响应头的格式是固定的(键值对形式),与响应体的格式无关。
  4. 响应体(Body)设计规范
    • 成功响应
      • 返回请求的资源数据(如 GET 请求)或操作结果(如 POST、PUT 请求)。
      • 通常以 JSON 格式返回,例如:
      {
        "id": 123,
        "name": "John Doe",
        "email": "john.doe@example.com",
        "createdAt": "2023-10-01T12:00:00Z"
      }
    
    • 返回错误详情,帮助客户端定位问题。
    {
      "error": {
        "code": 400,
        "message": "Invalid request: missing required field 'email'."
      }
    }
    

示例

RESTful API设计规范示例

  1. 路由器示例:/project-name/components/xxx-api/pkg/routers.go
// Gin路由器
func NewRouter() *gin.Engine {
	// 1. 初始化一个 Gin 路由器,否则无法注册路由和处理请求。
	router := gin.New()
	
	// 2. 路由分组:基于RESTful API规范将不同功能的路由聚合在一起
	rootRouter := router.Group("/")
	consoleRouter := router.Group("/apis")

	// 3. 注册中间件:将路由处理函数的重复逻辑提取到中间件处理函数中,
	// 	  如身份验证、日志记录、错误恢复等,从而避免重复实现导致的代码冗余
	router.Use(LoggerMiddleware())			// 注册全局中间件
	ErrorHandlerMiddleware(consoleRouter)	// 注册局部中间件
	ErrorHandlerMiddleware(rootRouter)

	// 4. 注册路由:
	consoleRouter.GET("/apps/v1/resPack", console.ApisAppsV1GetResPacks)           // 获取资源包列表(集合)
	consoleRouter.GET("/apps/v1/resPack/:resPackId", console.ApisAppsV1GetResPack) // 获取资源包详情(具体)
	consoleRouter.POST("/apps/v1/resPack", console.ApisAppsV1CreateResPack)        // 创建资源包
	consoleRouter.PUT("/apps/v1/resPack/:resPackId", console.ApisAppsV1UpdateResPackName) // 修改资源包名称
	consoleRouter.DELETE("/apps/v1/resPack/:resPackId", console.ApisAppsV1DeleteResPack)  // 删除资源包
	// 5. 返回路由实例
	return router
}

// 中间件函数
// 全局中间件函数
func ErrorHandlerMiddleware() gin.HandlerFunc {	// 错误处理中间件示例
	return func(c *gin.Context) {
		// 调用下一个中间件或路由处理函数
		c.Next()

		// 检查是否有错误
		if len(c.Errors) > 0 {
			c.JSON(http.StatusBadRequest, gin.H{
				"error": c.Errors.Last().Error(),
			})
		}
	}
}
// 局部中间件函数
func LoggerMiddleware() gin.HandlerFunc {	// 日志记录中间件示例
	return gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
		return fmt.Sprintf("[%s] %s %s %d %s\n",
			param.TimeStamp.Format(time.RFC3339),
			param.Method,
			param.Path,
			param.StatusCode,
			param.Latency,
		)
	})
}
  1. 路由处理函数文件:/project-name/components/xxx-api/pkg/handler/console/res_pack_handler.go
// ApisAppsV1DeleteResPack 删除资源包
func ApisAppsV1DeleteResPack(c *gin.Context) {
	// 0. 解析请求:包括请求头、请求体、路径参数和查询参数。
	var requestHeader common.AccountHeader
	var responseMsg = consolemodel.V1RespCommonWithId{ 
		Code:    http.StatusOK,
		Message: "success",
	}
	parameters := &struct {
		ResPackId string `form:"resPackId" uri:"resPackId"`
	}{}
	// 1. 校验请求:判断请求是否有效,处理错误情况。
	if err := utils.Parse(c, &requestHeader, nil, parameters, nil); err != nil {
		responseMsg.Code = http.StatusBadRequest
		responseMsg.Message = err.Error()
	}
	// 2. 调用服务层:执行业务逻辑,如创建、删除、更新、查询等操作。
	resPackId := parameters.ResPackId 
	service := registry.GetResPackService()
	err := service.DeleteResPack(c.Request.Context(), resPackId) // NOTE: call function
	if err != nil {
		errCode := aicperror.ErrCodeInternalError.WithResult(aicperror.Wrap(err, err.Error()))
		c.Error(errCode)
		return
	}
	// 3. 返回响应:根据业务逻辑的结果,返回相应的HTTP状态码和响应体。
	responseMsg.Data.Id = resPackId
	c.JSON(http.StatusOK, responseMsg)
	// 4. 记录日志:在必要时记录操作日志,便于后续追踪和审计。
	
}
  1. 路由处理函数文件:/project-name/components/xxx-api/pkg/handler/console/res_pack_handler.go
// DeleteResPack 删除资源包
func (s *ResPackService) DeleteResPack(ctx context.Context, id string) (err error) {
	rpdao := dao.ResPackDao{}
	err = rpdao.Delete(ctx, id)
	if err != nil {
		return err
	}
	return nil
}
  1. 数据库处理文件:aicp\components\common\pkg\database\dao\res_pack_dao.go
func (s *ResPackDao) Delete(ctx context.Context, id string) (err error) {
	deleted := &models.ResPack{}
	return DB(ctx).Model(&models.ResPack{}).Where("id = ?", id).Delete(deleted).Error
}


少年,我观你骨骼清奇,颖悟绝伦,必成人中龙凤。
不如点赞·收藏·关注一波


🚩点此跳转到首行↩︎

参考博客

  1. RESTful接口实战
  2. RESTful API设计原则与规范详解
  3. 待看:MLOps 与 DevOps
  4. RESTful 架构详解
  5. 待定引用
  6. 待定引用
  7. 待定引用
  8. 待定引用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逆羽飘扬

如果有用,请支持一下。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值