• RESTful API设计实践


    1.通过请求类型区分CRUD

    方法 操作

    场景

    GET
    /cars
    /cars/711
    POST 创建
    /cars
    PUT 修改
    /cars/711
    /cars
    PATCH 部分修改
    /cars/711
    DELETE 删除
    /cars/711

    2.资源采用名词,且使用复数

    GET /tickets - 获取 tickets 列表
    GET /tickets/12 - 获取一个单独的 ticket
    POST /tickets - 创建一个新的 ticket
    PUT /tickets/12 - 更新 ticket #12
    PATCH /tickets/12 - 部分更新 ticket #12
    DELETE /tickets/12 - 删除 ticket #12

    3.Get方法和查询参数不应该涉及状态改变

    不要使用GET 进行状态改变,

    GET /users/711?activate 
    GET /users/711/activate

    4.使用子资源表达关系

    如果一个资源与另外一个资源有关系,使用子资源:

    GET /tickets/12/messages - 获取ticket #12下的消息列表
    GET /tickets/12/messages/5 - 获取ticket #12下的编号为5的消息
    POST /tickets/12/messages - 为ticket #12创建一个新消息
    PUT /tickets/12/messages/5 - 更新ticket #12下的编号为5的消息
    PATCH /tickets/12/messages/5 - 部分更新ticket #12下的编号为5的消息
    DELETE /tickets/12/messages/5 - 删除ticket #12下的编号为5的消息

    5.使用Http头声明序列化格式

    在客户端和服务端,双方都要知道通讯的格式,格式在HTTP-Header中指定

    Content-Type 定义请求格式
    Accept 定义系列可接受的响应格式

    6.过滤,排序,搜索设计

    最好是尽量保持基本资源URL的简洁性。 复杂结果过滤器、排序需求和高级搜索 (当限定在单一类型的资源时) ,都能够作为在基本URL之上的查询参数来轻松实现。下面让我们更详细的看一下:

    1)过滤: 对每一个字段使用一个唯一查询参数,就可以实现过滤。 例如,当通过“/tickets”终端来请求一个票据列表时,你可能想要限定只要那些在售的票。这可以通过一个像

    GET /tickets?state=open

    这样的请求来实现。这里“state”是一个实现了过滤功能的查询参数。

    2)排序: 跟过滤类似, 一个泛型参数排序可以被用来描述排序的规则. 为适应复杂排序需求,让排序参数采取逗号分隔的字段列表的形式,每一个字段前都可能有一个负号来表示按降序排序。我们看几个例子:

    GET /tickets?sort=-priority - 获取票据列表,按优先级字段降序排序
    GET /tickets?sort=-priority,created_at - 获取票据列表,按“priority”字段降序排序。在一个特定的优先级内,较早的票排在前面

    3)搜索: 有时基本的过滤不能满足需求,这时你就需要全文检索的力量。或许你已经在使用 ElasticSearch 或者其它基于 Lucene 的搜索技术。当全文检索被用作获取某种特定资源的资源实例的机制时, 它可以被暴露在API中,作为资源终端的查询参数,我们叫它“q”。搜索类查询应当被直接交给搜索引擎,并且API的产出物应当具有同样的格式,以一个普通列表作为结果。
    把这些组合在一起,我们可以创建以下一些查询:

    GET /tickets?sort=-updated_at - 获取最近更新的票
    GET /tickets?state=closed&sort=-updated_at - 获取最近更新并且状态为关闭的票。
    GET /tickets?q=return&state=open&sort=-priority,created_at - 获取优先级最高、最先创建的、状态为开放的票,并且票上有 'return' 字样。

    4)一般查询定义方式

    为了使普通用户的API使用体验更加愉快, 考虑把条件集合包装进容易访问的RESTful 路径中。比如上面的,最近关闭的票的查询可以被包装成 

    GET /tickets/recently_closed

    5)限制查询返回字段

    API的使用者并不总是需要一个资源的完整表示。选择返回字段的功能由来已久,它使得API使用者能够最小化网络阻塞,并加速他们对API的调用。
    使用一个字段查询参数,它包含一个用逗号隔开的字段列表。例如,下列请求获得的信息将刚刚足够展示一个在售票的有序列表:

    GET /tickets?fields=id,subject,customer_name,updated_at&state=open&sort=-updated_at

    6)Paging分页

    使用 limit 和offset.实现分页,缺省limit=20 和offset=0;

    GET /cars?offset=10&limit=5

    为了将总数发给客户端,使用订制的HTTP头: X-Total-Count.

    链接到下一页或上一页可以在HTTP头的link规定,遵循Link规定:

    Link: <https://blog.mwaysolutions.com/sample/api/v1/cars?offset=15&limit=5>; rel="next",
    <https://blog.mwaysolutions.com/sample/api/v1/cars?offset=50&limit=3>; rel="last",
    <https://blog.mwaysolutions.com/sample/api/v1/cars?offset=0&limit=5>; rel="first",
    <https://blog.mwaysolutions.com/sample/api/v1/cars?offset=5&limit=5>; rel="prev",

    7.更新和创建应该返回一个资源描述

    一个 PUT, POST 或者 PATCH 调用可能会对指定资源的某些字段造成更改,而这些字段本不在提供的参数之列 (例如: created_at 或 updated_at 这两个时间戳)。 为了防止API使用者为了获取更新后的资源而再次调用该API,应当使API把更新(或创建)后的资源作为response的一部分来返回。

    以一个产生创建活动的 POST 操作为例, 使用一个 HTTP 201 状态代码 然后包含一个 Location header 来指向新生资源的URL。

    8.只返回JSON

    9.字段名称书写格式统一

    选定一种方式:snake_case vs camelCase

    10.缺省情况下采用格式化形式和支持gzip

    一个提供空白符压缩输出的API,从浏览器中查看结果并不美观。虽然一些有序的查询参数(如 ?pretty=true )可以提供来使漂亮打印生效,一个默认情况下能进行漂亮打印的API更为平易近人。额外数据传输的成本是微不足道的,尤其是当你比较不执行gzip压缩的成本。
    考虑一些用例:假设分析一个API消费者正在调试并且有自己的代码来打印出从API收到的数据——默认情况下这应是可读的。或者,如果消费者抓住他们的代码生成的URL,并直接从浏览器访问它——默认情况下这应是可读的。这些都是小事情。做好小事情会使一个API能被更愉快地使用

    11.错误设计

    就像一个HTML错误页面给访问者展示了有用的错误信息一样,一个API应当以一种已知的可使用的格式来提供有用的错误信息。 错误的表示形式应当和其它任何资源没有区别,只是有一套自己的字段。
    API应当总是返回有意义的HTTP状态代码。API错误通常被分成两种类型: 代表客户端问题的400系列状态码和代表服务器问题的500系列状态码。最简情况下,API应当把便于使用的JSON格式作为400系列错误的标准化表示。如果可能(意思是,如果负载均衡和反向代理能创建自定义的错误实体), 这也适用于500系列错误代码。
    一个JSON格式的错误信息体应当为开发者提供几样东西 - 一个有用的错误信息,一个唯一的错误代码 (能够用来在文档中查询详细的错误信息) 和可能的详细描述。这样一个JSON格式的输出可能会像下面这样:

    {
    "code" : 1234,
    "message" : "Something bad happened :(",
    "description" : "More details about the error here"
    }

    对PUT, PATCH和POST请求进行错误验证将需要一个字段分解。下面可能是最好的模式:使用一个固定的顶层错误代码来验证错误,并在额外的字段中提供详细错误信息,就像这样:

    {
    "code" : 1024,
    "message" : "Validation Failed",
    "errors" : [
     {
        "code" : 5432,
        "field" : "first_name",
        "message" : "First name cannot have fancy characters"
    },
    {
        "code" : 5622,
        "field" : "password",
        "message" : "Password cannot be blank"
    }
    ]
    }

    12.HTTP状态码

    HTTP定义了一套可以从API返回的有意义的状态代码。 这些代码能够用来帮助API使用者对不同的响应做出相应处理。我已经把你必然会用到的那些列成了一个简短的清单:

    • 200 OK (成功) - 对一次成功的GET, PUT, PATCH 或 DELETE的响应。也能够用于一次未产生创建活动的POST
    • 201 Created (已创建) - 对一次导致创建活动的POST的响应。 同时结合使用一个位置头信息指向新资源的位置- Response to a POST that results in a creation. Should be combined with a Location header pointing to the location of the new resource
    • 204 No Content (没有内容) - 对一次没有返回主体信息(像一次DELETE请求)的请求的响应
    • 304 Not Modified (未修改) - 当使用HTTP缓存头信息时使用304
    • 400 Bad Request (错误的请求) - 请求是畸形的, 比如无法解析请求体
    • 401 Unauthorized (未授权) - 当没有提供或提供了无效认证细节时。如果从浏览器使用API,也可以用来触发弹出一次认证请求
    • 403 Forbidden (禁止访问) - 当认证成功但是认证用户无权访问该资源时
    • 404 Not Found (未找到) - 当一个不存在的资源被请求时
    • 405 Method Not Allowed (方法被禁止) - 当一个对认证用户禁止的HTTP方法被请求时
    • 410 Gone (已删除) - 表示资源在终端不再可用。当访问老版本API时,作为一个通用响应很有用
    • 415 Unsupported Media Type (不支持的媒体类型) - 如果请求中包含了不正确的内容类型
    • 422 Unprocessable Entity (无法处理的实体) - 出现验证错误时使用
    • 429 Too Many Requests (请求过多) - 当请求由于访问速率限制而被拒绝时

     ----------------------------------------------------------------------

    参考资料:
    1、《Best Practices for Designing a Pragmatic RESTful API
    2、《RESTful API 设计最佳实践》(对上文的译文)
    3、《Principles of good RESTful API Design

  • 相关阅读:
    linux rcu
    linux下的进程、网络、性能监控命令
    使用optimizely做A/B测试
    使用logstash收集日志的可靠性验证
    LAMP-HTTPD的安装全步骤
    Iptables Save
    linux-ftp
    远程桌面验证问题,函数错误-windows
    ESXIroot密码重置
    centos or windows 双系统
  • 原文地址:https://www.cnblogs.com/kaihe/p/4703118.html
Copyright © 2020-2023  润新知