zoukankan      html  css  js  c++  java
  • Restful API 设计参考原则

    在项目中,需要为后台服务撰写API。刚开始接触的时候,并没有考虑太多,就想提供URL,服务端通过该URL进行查询、创建、更新等操作即可。但再对相关规范进行了解后,才发现,API的设计并没有那么简单,远远不是URL的问题,而是一个通信协议的整体架构

    1. 使用GET、POST、PUT、DELETE这几种请求模式

    请求模式也可以说是动作、数据传输方式,通常我们在web中的form有GET、POST两种,而在HTTP中,存在下发这几种。

    GET (选择):从服务器上获取一个具体的资源或者一个资源列表。 
    POST (创建): 在服务器上创建一个新的资源。
    PUT(更新):以整体的方式更新服务器上的一个资源。 
    PATCH (更新):只更新服务器上一个资源的一个属性。
    DELETE(删除):删除服务器上的一个资源。

    1.1 使用名词而不是动词

    Resource
    资源

    GET
    POST
    创建
    PUT
    修改
    DELETE
    /cars 返回 cars集合 创建新的资源 批量更新cars 删除所有cars
    /cars/711 返回特定的car 该方法不允许(405) 更新一个指定的资源 擅长指定资源

    不要使用:

    /getAllCars
    /createNewCar
    /deleteAllRedCars

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

    使用PUT, POST 和DELETE 方法 而不是 GET 方法来改变状态,不要使用GET 进行状态改变:

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

     1.3 使用复数名词

    不要混淆名词单数和复数,为了保持简单,只对所有资源使用复数。

    /cars 而不是 /car
    /users 而不是 /user
    /products 而不是 /product
    /settings 而部署 /setting

     1.4 使用子资源表达关系

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

    GET /cars/711/drivers/ 返回 car 711的所有司机
    GET /cars/711/drivers/4 返回 car 711的4号司机

    2. 为集合提供过滤 排序 选择和分页等功能

    比如在数据过多, 需要对数据进行分页请求的时候, 我们应该统一 API 请求参数. 常见的有这些.

    • limit=10 指定返回记录的数量
    • offset=10 指定返回记录的开始位置。
    • page=2&per_page=100 指定第几页,以及每页的记录数。
    • sortby=name&order=asc 指定返回结果按照哪个属性排序,以及排序顺序。
    • animal_type_id=1 指定筛选条件

    Filtering过滤:

    使用唯一的查询参数进行过滤:

    GET /cars?color=red 返回红色的cars
    GET /cars?seats<=2 返回小于两座位的cars集合

    Sorting排序:

    允许针对多个字段排序

    GET /cars?sort=-manufactorer,+model

    这是返回根据生产者降序和模型升序排列的car集合

    Field selection

    移动端能够显示其中一些字段,它们其实不需要一个资源的所有字段,给API消费者一个选择字段的能力,这会降低网络流量,提高API可用性。

    GET /cars?fields=manufacturer,model,id,color

    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",

    3. 版本化你的API

    API的开发直接关系了APP是否可以正常使用,如果原本运行正常的API,突然改动,那么之前使用这个API的APP可能无法正常运行。APP是不可能强迫用户主动升级的,因此,通过API版本来解决这个问题。也就是说,API的多个版本是同时运行的,而且都要保证可以正常使用。

    按照RESTful的规范,不同的版本也应该用相同的API URL,通过header信息来判断版本,再调用不同版本的程序进行处理。但是这明显会给开发带来巨大的成本。使得API版本变得强制性,不要发布无版本的API,使用简单数字,避免小数点如2.5.

    域名

    应该尽量将API部署在专用域名之下,如:https://api.example.com

    也可以放在主域名下:https://example.org/api/

    版本

    不同的版本,用不同的URL来提供服务,在URL中通过v1、v2来区分版本号,比如v2.api.xxx.com/user的方式,或者http://api.domain.com/v2  或者http://www.domain.com/api/v2 。

    放入到头信息的Accept中
    制定版本并在版本之间平缓过渡对于设计和维护一套API是个巨大的挑战。所以,最好在设计之初就使用一些方法来预防可能会遇到的问题。
    为了避免API的变动导致用户使用中产生意外结果或调用失败,最好强制要求所有访问都需要指定版本号。请避免提供默认版本号,一旦提供,日后想要修改它会相当困难。
    最适合放置版本号的位置URL中,或者是头信息(HTTP Headers)中在 Accept 段中使用自定义类型(content type)与其他元数据(metadata)一起提交。

    https://api.example.com/v1/
    或
    Accept: application/vnd.heroku+json; version=3

    提供 Request-Id

    为每一个请求响应包含一个Request-Id字段,并使用UUID作为该值。通过在客户端、服务器或任何支持服务上记录该值,它能主我们提供一种机制来跟踪、诊断和调试请求。

    4 .json数据类型

    • Number:整数或浮点数
    • String:字符串
    • Boolean:true 或 false
    • Array:数组包含在方括号[]中
    • Object:对象包含在大括号{}中
    • Null:空类型

    所以,传输的数据类型不能超过这六种数据类型。以前,我们曾经试过传输Date类型,它会转为类似于"2016年1月7日 09时17分42秒 GMT+08:00"这样的字符串,这在转换时会产生问题,不同的解析库解析方式可能不同,有的可能会转乱,有的可能直接异常了。要避免出错,必须做特殊处理,自己手动去做解析。为了根除这种问题,最好的解决方案是用毫秒数或者字符串表示日期。

    使用详细的错误包装错误:

    {
    
      "errors": [
    
       {
    
        "userMessage": "Sorry, the requested resource does not exist",
    
        "internalMessage": "No car found in the database",
    
        "code": 34,
    
        "more info": "http://dev.mwaysolutions.com/blog/api/v1/errors/12345"
    
       }
    
      ]
    
    }
    

    返回的数据结构

    {
        code:0,
        message: "success",
        data: { key1: value1, key2: value2, ... }
    }
    
    • code: 返回码,0表示成功,非0表示各种不同的错误
    • message: 描述信息,成功时为"success",错误时则是错误信息
    • data: 成功时返回的数据,类型为对象或数组

    data字段只在请求成功时才会有数据返回的。数据类型限定为对象或数组,当请求需要的数据为单个对象时则传回对象,当请求需要的数据是列表时,则为某个对象的数组。这里需要注意的就是,不要将data传入字符串或数字,即使请求需要的数据只有一个,比如token,那返回的data应该为:

    // 正确 data: { token: abcdedf }

    9. 使用Http状态码处理错误

    不同错误需要定义不同的返回码,属于客户端的错误和服务端的错误也要区分,比如1XX表示客户端的错误,2XX表示服务端的错误

    如果你的API没有错误处理是很难的,只是返回500和出错堆栈不一定有用

    Http状态码提供70个出错,我们只要使用10个左右:

    200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
    201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
    202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
    204 NO CONTENT - [DELETE]:用户删除数据成功。
    400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
    401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
    403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
    404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
    406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
    410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
    422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
    500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
    

    10.允许覆盖http方法

    一些代理只支持POST 和 GET方法, 为了使用这些有限方法支持RESTful API,需要一种办法覆盖http原来的方法。

    使用订制的HTTP头 X-HTTP-Method-Override 来覆盖POST 方法.

    参考:

    1. https://segmentfault.com/a/1190000008697972#articleHeader3
    2. http://blog.csdn.net/jasonhui512/article/details/53141390
    3. http://www.cnblogs.com/kuyuecs/p/5949075.html
    4. http://mclspace.com/2015/11/03/restful-note/
  • 相关阅读:
    job_queue_processes参数讲解
    Oracle trunc()函数的用法
    JSON字符串转JavaBean,net.sf.ezmorph.bean.MorphDynaBean cannot be cast to ……
    javax.swing.JList 设置分割线
    清除SVN版本控制文件
    MyEclipse SVN安装方法
    ExtJs xtype类型介绍
    Android中的“再按一次返回键退出程序”实现
    Android之NetworkOnMainThreadException异常
    HDU 3613 Best Reward
  • 原文地址:https://www.cnblogs.com/WayneZeng/p/9290798.html
Copyright © 2011-2022 走看看