RESTFul API 设计规范
0. API设计满足关键点
1. API命名1.1 根地址好的RESTful API要基于HTTPS来发布 API规模不大时,在域名后面增加 api 目录,如: 1.2 版本问题
https://api.trawe.cn/v1.2/users/123
{ version: "1.0",.... .... }
使用已的HTTPHeader:Accept Header:Accept: application/json+v1.2 自定义 Header: X-Api-Version: 1.2 1.3 端点设计原则1) 命名
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 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的消息 3) 对于非CRUD的操作 有很非CRUD服务,可以把这些服务看成资源,计算的结果是资源的presentation,按服务属性选择合适的HTTP方法。 1. 重新构造这个Action,使得它像一个资源的操作。 这种方法在Action不包含参数的情况下可以奏效。例如一个有效的action可以映射成布尔类型field,并且可以通过PATCH更新资源。 2. 利用RESTful原则像处理子资源一样处理它。 例如:Github的API让你通过PUT /gists/:id/star 来 star a gist ,而通过DELETE /gists/:id/star来进行 unstar 。 3. 有时候你实在是没有办法将Action映射到任何有意义的RESTful结构。 例如:多资源搜索没办法真正地映射到任何一个资源接入点。这种情况,/search 将非常有意义,虽然它不是一个名词,但是这样做没有问题,只需要从API消费者的角度做正确的事,并确保所做的一切都用文档清晰记录下来了即可。 4) 查询过滤 过滤: 对每一个字段使用一个唯一查询参数,就可以实现过滤。 例如: 当通过 对于常用的查询,有以下两种处理:
排序: 跟过滤类似,使用排序参数字段来描述排序的规则。 为适应复杂排序需求,让排序参数采取逗号分隔的字段列表的形式,每一个字段前都可能有一个负号来表示按降序排序。 例如: 排序字段前面的 +表示升序 -表示降序 默认为升序 GET /tickets?sort=-priority # 获取票据列表,按优先级字段降序排序 GET /tickets?sort=-priority,created_at # 获取票据列表,按“priority”字段降序排序。在一个特定的优先级内,较早的票排在前面。 5) 减少层级深度 6) 限制返回哪些字段 使用一个字段查询参数,它包含一个 用逗号隔开的字段列表。例如,下列请求获得的信息将刚刚足够展示一个在售票的有序列表: GET /tickets?fields=id,subject,customer_name,updated_at&state=open&sort=-updated_at 7) 关于返回结果 通常情况下只返回
8) 分页 常用的分页字段如下: limit=10:指定返回记录的数量 offset=10:指定返回记录的开始位置。 page=2&per_page=100:指定第几页,以及每页的记录数。 9) 缓存 ETag: 当产生一个请求时,包含一个HTTP 头,ETag会在里面置入一个和表达内容对应的哈希值或校验值。这个值应当跟随表达内容的变化而变化。现在,如果一个入站HTTP请求包含了一个If-None-Match头和一个匹配的ETag值,API应当返回一个304未修改状态码,而不是返回请求的资源。 Last-Modified: 基本上像ETag那样工作,不同的是它使用时间戳。在响应头中,Last-Modified包含了一个RFC 1123格式的时间戳,它使用If-Modified-Since来进行验证。注意,HTTP规范已经有了 3 种不同的可接受的日期格式 ,服务器应当准备好接收其中的任何一种。 2. HTTP方法常用: GET (选择):从服务器上获取一个具体的资源或者一个资源列表。 POST (创建): 在服务器上创建一个新的资源。 PUT (更新):以整体的方式更新服务器上的一个资源。 PATCH (更新):只更新服务器上一个资源的一个属性。 DELETE (删除):删除服务器上的一个资源。 不常用: HEAD : 获取一个资源的元数据,如数据的哈希值或最后的更新时间。 OPTIONS:获取客户端能对资源做什么操作的信息。 3. 数据报文
请求使用JSON格式时: { method: 'testMethod',// 请求方法名称 version: '1.0',// 接口版本 token: '0X十六进制',// Token sign_type: 'MD5',// 签名算法 sign: '0X十六进制',// 签名 timestamp: '12345678' // 请求的时间戳 } 响应: { code: 0,// 返回码。 -1:失败 0:成功 其它:具体业务代码 message: '处理成功',// 返回码描述信息 sign: '0X十六进制',// 签名 ... // 业务数据 } 响应数据不作多余包装,如下为错误示例: { code: 0,data: {userName: "用户名"} // 这里面的data没有业务含意,仅仅是为了包装,所以应该去掉 } 需要进行包装的情况:
4. 安全
5. 文档
6. HTTP状态代码HTTP定义了一套可以从API返回的有意义的状态代码。 这些代码能够用来帮助API使用者对不同的响应做出相应处理。 200 OK (成功) - 对一次成功的GET,PUT,PATCH 或 DELETE的响应。也能够用于一次未产生创建活动的POST 201 Created (已创建) - 对一次导致创建活动的POST的响应。 同时结合使用一个位置头信息指向新资源的位置 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 (请求过多) - 当请求由于访问速率限制而被拒绝时 7. 错误处理原则
API 可能抛出两类异常:业务异常和非业务异常。 业务异常由自己的业务代码抛出,表示一个用例的前置条件不满足、业务规则冲突等,比如参数校验不通过、权限校验失败。 非业务类异常表示不在预期内的问题,通常由类库、框架抛出,或由于自己的代码逻辑错误导致,比如数据库连接失败、空指针异常、除0错误等等。 业务类异常必须提供2种信息:
在Controller层使用统一的异常拦截器:
8. 超媒体APIRESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。 比如,当用户向api.example.com的根目录发出请求,会得到这样一个文档。 {"link": { "rel": "collection https://www.example.com/zoos","href": "https://api.example.com/zoos","title": "List of zoos","type": "application/vnd.yourformat+json" }} 上面代码表示,文档中有一个link属性,用户读取这个属性就知道下一步该调用什么API了。rel表示这个API与当前网址的关系(collection关系,并给出该collection的网址),href表示API的路径,title表示API的标题,type表示返回类型。 Hypermedia API的设计被称为HATEOAS。Github的API就是这种设计,访问api.github.com会得到一个所有可用API的网址列表。 { "current_user_url": "https://api.github.com/user","authorizations_url": "https://api.github.com/authorizations",// ... } 从上面可以看到,如果想获取当前用户的信息,应该去访问api.github.com/user,然后就得到了下面结果。 { "message": "Requires authentication","documentation_url": "https://developer.github.com/v3" } 上面代码表示,服务器给出了提示信息,以及文档的网址。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |