RESTful API规范

本文详述RESTful API设计规范,涵盖HTTP方法使用、URI设计、状态码、错误处理等核心内容,确保API的一致性和易用性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

RESTful 规范指南:

1. HTTP 协议

API 与用户的通信协议, 总是使用 HTTPS 协议

 

2. 域名:

 
  
 
        
# 子域名方式:(解决跨域的问题)
    www.baidu.com
    api.baidu.com
# 存在跨域的风险
    
    
# =========================================
# URL 方式:
    www.baidu.com
    www.baidu.com/api/

 

3. 版本:

 
  
 
        
URL  : https://api.baidu.com/v1/   
# 一般情况下都放在 url 上
请求头:                           跨域时, 引发发送多次请求

 

4. 路径

视网络上的一切都为资源, 均使用名词表示(可使用复数)

 
  
 
        
https://api.baidu.com/v1/zoos
https://api.baidu.com/v1/animals
https://api.baidu.com/v1/employees

 

5. method

 
  
 
        
GET:     从服务器取出资源(一项或多项)
POST:    在服务器新建一个资源
PUT:     在服务器更新资源( 客户端提供改变后的完整资源 )
PATCH:   在服务器更新资源( 客户端提供改变的属性 )
DELETE:  在服务器删除资源

 

6. 过滤:

通过在 URL 上传参的形式传递搜索条件

 
  
 
        
https://api.baidu.com/v1/zoos?limit=10      : 指定返回记录的数量
https://api.baidu.com/v1/zoos?offset=10     : 指定返回记录的开始位置
https://api.baidu.com/v1/zoos?page=2&per_page=100  : 指定第几页, 以及每页的记录数
https://api.baidu.com/v1/zoos?sortby=name&order=asc    : 指定返回结果按照那个属性排序, 以及排序顺序
https://api.baidu.com/v1/zoos?animal_type_id = 1        : 指定筛选条件   

 

7. 状态码:

  • 常用状态码:
 
  
 
        
200  OK  一切正常 
201  OK  新资源已经被创建 
204  OK  资源删除成功
 
         
304  没有变化,客户端可以使用缓存数据
 
         
400  Bad Request  调用不合法,确切的错误应该在error payload中描述,例如:“JSON 不合法  
401  未认证,调用需要用户通过认证 
403  不允许的,服务端正常解析和请求,但是调用被回绝或者不被允许 
404  未找到,指定的资源不存在 
422  不可指定的请求体  只有服务器不能处理实体时使用,比如图像不能被格式化,或者重要字段丢失。
 
         
500  Internal Server Error  标准服务端错误,API开发人员应该尽量避开这种错误
  • 状态码和 code 结合使用
  • 全部状态码:
 
  
 
        
建议不要在回复中使用裸状态代码。REST框架包含一组命名常量,您可以使用这些常量使代码更加明显和可读。
 
         
from rest_framework import status
from rest_framework.response import Response
 
         
def empty_view(self):
    content = {'please move along': 'nothing to see here'}
    return Response(content, status=status.HTTP_404_NOT_FOUND)
 
         
 
         
# =========================================================
status下面列出了模块中包含的完整HTTP状态代码集。
 
         
该模块还包括一组辅助函数,用于测试状态代码是否在给定范围内。
 
         
from rest_framework import status
from rest_framework.test import APITestCase
 
         
class ExampleTestCase(APITestCase):
    def test_url_root(self):
        url = reverse('index')
        response = self.client.get(url)
        self.assertTrue(status.is_success(response.status_code))
有关正确使用HTTP状态代码的详细信息,请参阅RFC 2616 和RFC 6585
# =========================================================
信息 - 1xx
此类状态代码表示临时响应。默认情况下,REST框架中没有使用1xx状态代码。
 
         
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
 
         
# =========================================================
成功 - 2xx
此类状态代码表示已成功接收,理解和接受客户端的请求。
 
         
HTTP_200_OK
HTTP_201_CREATED
HTTP_202_ACCEPTED
HTTP_203_NON_AUTHORITATIVE_INFORMATION
HTTP_204_NO_CONTENT
HTTP_205_RESET_CONTENT
HTTP_206_PARTIAL_CONTENT
HTTP_207_MULTI_STATUS
 
         
# =========================================================
重定向 - 3xx
此类状态代码指示用户代理需要采取进一步操作才能完成请求。
 
         
HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT
 
         
# =========================================================
客户端错误 - 4xx
4xx类状态代码适用于客户端似乎有错误的情况。除了在响应HEAD请求时,服务器应该包括一个实体,其中包含错误情况的解释,以及它是暂时的还是永久的。
 
         
HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_402_PAYMENT_REQUIRED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_406_NOT_ACCEPTABLE
HTTP_407_PROXY_AUTHENTICATION_REQUIRED
HTTP_408_REQUEST_TIMEOUT
HTTP_409_CONFLICT
HTTP_410_GONE
HTTP_411_LENGTH_REQUIRED
HTTP_412_PRECONDITION_FAILED
HTTP_413_REQUEST_ENTITY_TOO_LARGE
HTTP_414_REQUEST_URI_TOO_LONG
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
 
         
# =========================================================
服务器错误 - 5xx
以数字“5”开头的响应状态代码表示服务器知道它已经错误或无法执行请求的情况。除了在响应HEAD请求时,服务器应该包括一个实体,其中包含错误情况的解释,以及它是暂时的还是永久的。
 
         
HTTP_500_INTERNAL_SERVER_ERROR
HTTP_501_NOT_IMPLEMENTED
HTTP_502_BAD_GATEWAY
HTTP_503_SERVICE_UNAVAILABLE
HTTP_504_GATEWAY_TIMEOUT
HTTP_505_HTTP_VERSION_NOT_SUPPORTED
HTTP_507_INSUFFICIENT_STORAGE
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED
 
         
# =========================================================
助手功能
以下辅助函数可用于标识响应代码的类别。
 
         
is_informational()  # 1xx
is_success()        # 2xx
is_redirect()       # 3xx
is_client_error()   # 4xx
is_server_error()   # 5xx

 

8. 错误处理

状态码是 4xx 时, 应返回错误信息, error 当作 key

 
  
 
        
{
    error: 'Invalid API key'
}

 

9. 返回结果

针对不同操作, 服务器向用户返回的结果应该符合以下规范:

 
  
 
        
GET /collection: 返回资源对象的列表 (数组)
GET /collection/resource: 返回单个资源对象
POST /collection: 返回新生成的资源对象
PUT /collection/resource:  返回完整的资源对象
PATCH /collection/resource: 返回完整的资源对象
DELETE /collection/resource: 返回一个空文档

 

Restful API 的设计规范–进阶篇 原文链接

 

本文总结了 RESTful API 设计相关的一些原则,只覆盖了常见的场景。有些规则只是针对自己项目而言,并非其他做法都是错误的。

1. URI

URI 表示资源,资源一般对应服务器端领域模型中的实体类。 URI规范

  • 不用大写;
  • 用中杠-而不用下杠_;
  • 参数列表要encode;
  • URI中的名词表示资源集合,使用复数形式;

资源集合与单个资源 资源集合:

 
  
 
        
    /zoos //所有动物园
    /zoos/1/animals //id为1的动物园内的所有动物

单个资源:

 
  
 
        
    /zoos/1 //id为1的动物园
    /zoos/1;2;3 //id为1,2,3的动物园

避免层级过深的URI /在URI中表示层级,用于按实体关联关系进行对象导航,一般跟进id导航; 过深的导航容易导致url膨胀,不易维护,如 GET /zoos/1/areas/3/animals/4,尽量使用查询参数代替路径中的实体导航,如GET /animals?zoo=1&area=3;

对Composite资源的访问 服务器端的组合实体必须在uri中通过父实体的id导航访问。

组合实体不是first-class的实体,它的生命周期完全依赖父实体,无法独立存在,在实现上通常是对数据库表中某些列的抽象,不直接对应表,也无id。一个常见的例子是 User — Address,Address是对User表中zipCode/country/city三个字段的简单抽象,无法独立于User存在。必须通过User索引到Address:GET /user/1/addresses


2. Request

HTTP方法 通过标准HTTP方法对资源CRUD: GET: 查询

 
  
 
        
    GET /zoos
    GET /zoos/1
    GET /zoos/1/employees

POST: 创建单个资源。POST一般向“资源集合”型URI发起; ··· javaascipt

 
  
 
        
POST /animals //新增动物
POST /zoos/1/employees //id为1的动物园的所有员工

PUT:更新单个资源(全量),客户端提供完整的更新后的资源。与之对应的是 PATCH,PATCH 负责部分更新,客户端提供要更新的那些字段。PUT/PATCH一般向“单个资源”型uri发起

 
  
 
        
    PUT /animals/1
    PUT /zoos/1

DELETE:删除

 
  
 
        
    DELETE /zoos/1/employees/2
    DELETE /zoos/1/employees/2;4;5
    DELETE /zoos/1/animals  //删除id为1的动物园内的所有动物

HEAD / OPTION 用的不多,就不多解释了。

安全性与幂等性 安全性:不会改变资源状态,可以理解为只读的; 幂等性:执行1次和执行N次,对资源状态改变的效果是等价的。 图片描述

安全性和幂等性均不保证反复请求能拿到相同的response。以 DELETE 为例,第一次DELETE返回200表示删除成功,第二次返回404提示资源不存在,这是允许的。

复杂查询 查询可以捎带以下参数: 图片描述

Bookmarker 经常使用的、复杂的查询标签化,降低维护成本。 如:

 
  
 
        
GET /trades?status=closed&sort=created,desc

快捷方式:

 
  
 
        
    GET /trades#recently-closed
    // 或者
    GET /trades/recently-closed

Format 只用以下常见的3种body format:

  1. Content-Type: application/json
 
  
 
        
    POST /v1/animal HTTP/1.1
    Host: api.example.org
    Accept: application/json
    Content-Type: application/json
    Content-Length: 24
 
         
    {   
      "name": "Gir",
      "animalType": "12"
    }
  1. Content-Type: application/x-www-form-urlencoded (浏览器POST表单用的格式)
 
  
 
        
    POST /login HTTP/1.1
    Host: example.com
    Content-Length: 31
    Accept: text/html
    Content-Type: application/x-www-form-urlencoded
    
    username=root&password=Zion0101
  1. Content-Type: multipart/form-data; boundary=—-RANDOM_jDMUxq4Ot5 (表单有文件上传时的格式)

Content Negotiation 资源可以有多种表示方式,如json、xml、pdf、excel等等,客户端可以指定自己期望的格式,通常有两种方式:

  1. http header Accept
 
  
 
        
Accept:application/xml;q=0.6,application/atom+xml;q=1.0

q为各项格式的偏好程度

  1. url中加文件后缀:/zoo/1.json

3. Response

  1. 不要包装

    response 的 body 直接就是数据,不要做多余的包装。错误示例:

 
  
 
        
    {
        "success":true,
        "data":{"id":1,"name":"xiaotuan"},
    }
  1. 各HTTP方法成功处理后的数据格式: 图片描述
  2. json格式的约定: 时间用长整形(毫秒数),客户端自己按需解析(moment.js) 不传null字段

分页response

 
  
 
        
    {
        "paging":{"limit":10,"offset":0,"total":729},
        "data":[{},{},{}...]
    }

4. 错误处理

  1. 不要发生了错误但给2xx响应,客户端可能会缓存成功的http请求;
  2. 正确设置http状态码,不要自定义;
  3. Response body 提供 1) 错误的代码(日志/问题追查);2) 错误的描述文本(展示给用户)。

对第三点的实现稍微多说一点: Java 服务器端一般用异常表示 RESTful API 的错误。API 可能抛出两类异常:业务异常和非业务异常。业务异常由自己的业务代码抛出,表示一个用例的前置条件不满足、业务规则冲突等,比如参数校验不通过、权限校验失败。非业务类异常表示不在预期内的问题,通常由类库、框架抛出,或由于自己的代码逻辑错误导致,比如数据库连接失败、空指针异常、除0错误等等。 业务类异常必须提供2种信息:

  1. 如果抛出该类异常,HTTP 响应状态码应该设成什么;
  2. 异常的文本描述;

在Controller层使用统一的异常拦截器:

  1. 设置 HTTP 响应状态码:对业务类异常,用它指定的 HTTP code;对非业务类异常,统一500;
  2. Response Body 的错误码:异常类名
  3. Response Body 的错误描述:对业务类异常,用它指定的错误文本;对非业务类异常,线上可以统一文案如“服务器端错误,请稍后再试”,开发或测试环境中用异常的 stacktrace,服务器端提供该行为的开关。

常用的http状态码及使用场景:图片描述


5. 服务型资源

除了资源简单的CRUD,服务器端经常还会提供其他服务,这些服务无法直接用上面提到的URI映射。如:

  1. 按关键字搜索;
  2. 计算地球上两点间的距离;
  3. 批量向用户推送消息;

可以把这些服务看成资源,计算的结果是资源的presentation,按服务属性选择合适的HTTP方法。 例如:

 
  
 
        
    GET /search?q=filter?category=file  搜索
    GET /distance-calc?lats=47.480&lngs=-122.389&late=37.108&lnge=-122.448
    POST /batch-publish-msg
    [{"from":0,"to":1,"text":"abc"},{},{}...]

6. 异步任务

对耗时的异步任务,服务器端接受客户端传递的参数后,应返回创建成功的任务资源,其中包含了任务的执行状态。客户端可以轮训该任务获得最新的执行进度。

 
  
 
        
    // 提交任务:
    POST /batch-publish-msg
    [{"from":0,"to":1,"text":"abc"},{},{}...]
    
    // 返回:
    {"taskId":3,"createBy":"Anonymous","status":"running"}
    
    GET /task/3
    {"taskId":3,"createBy":"Anonymous","status":"success"}

如果任务的执行状态包括较多信息,可以把“执行状态”抽象成组合资源,客户端查询该状态资源了解任务的执行情况。

 
  
 
        
    提交任务:
    POST /batch-publish-msg
    [{"from":0,"to":1,"text":"abc"},{},{}...]
    
    返回:
    {"taskId":3,"createBy":"Anonymous"}
    
    GET /task/3/status
    {"progress":"50%","total":18,"success":8,"fail":1}

7. API演进

版本 常见的三种方式:

  1. 在uri中放版本信息:GET /v1/users/1
  2. Accept Header:Accept: application/json+v1
  3. 自定义 Header:X-Api-Version: 1

用第一种,虽然没有那么优雅,但最明显最方便。

URI失效 随着系统发展,总有一些API失效或者迁移,对失效的API,返回404 not found 或 410 gone;对迁移的API,返回 301 重定向。


转载于:https://www.cnblogs.com/amou/p/9625368.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值