Web API自检表 — 43项API 设计、测试、发布需要关注的原则 笔记

原文:https://mathieu.fenniak.net/the-api-checklist/

“We know there are known knowns: there are things we know we know. We also know there are known unknowns: that is to say we know there are things we know we don’t know. But there are also unknown unknowns – the ones we don’t know we don’t know.

HTTP

  • Idempotent methods 幂等方法 - GET, HEAD, PUT, DELETE, OPTIONS and TRACE are all intended to be idempotent operations; that is, “the side-effects of N > 0 identical requests is the same as for a single request.” (RFC2616 §9.1.2) GET,HEAD,PUT,DELETE,OPTIONS,TRACE应该具备请求幂等性,无论请求数多少都如同只有一次请求
  • Authentication – Most APIs will need a way to identify and authenticate the user accessing the API. HTTP provides the Authorization header (RFC2616 §14.8) for this purpose. RFC2617 specifies specific authentication schemes, including the most common, HTTP Basic authentication.
    • 为了实现更准确的HTTP认证方式,你需要实现附带WWW-Authenticate请求头部的401状态码返回
  • 201 Created – Use the “201 Created” response code to indicate that the request was processed successfully and resulted in the creation of a new resource. 201 responses can include the new resource URI in the Location header. (RFC2616 §10.2.2)
  • 202 Accepted – Use the “202 Accepted” response code to indicate that the request is valid and will be processed, but has not been completed. Typically this is used where **a processing queue might be present in the background **on the server side. (RFC2616 §10.2.3) 表明需要后续处理的请求返回
  • 4xx versus 5xx status codes – 4xx codes are intended to indicate a client-side error, and a 5xx code indicates a server-side error. (RFC2616 §6.1.1) (Edit: Read more about the difference at Is “404 Not Found” really a client error?.)
  • 410 Gone – The “410 Gone” response code is an under-utilized response code that informs the client that a resource used to be present at this URL, but no longer is. This can be used in your API to indicate deleted, archived, or expired items. (RFC2616 §10.4.11) 曾经存在现在不在啦
  • Expect: 100-Continue – If an API client is about to send a request with a large entity body, like a POST, PUT, or PATCH, they can send “Expect: 100-continue” in their HTTP headers, and wait for a “100 Continue” response before sending their entity body. This allows the API server to verify much of the validity of the request before wasting bandwidth to return an error response (such as a 401 or a 403) 虽然不常用,但是能有效提高某些场景的带宽
  • Connection Keep-Alive – Maintaining a connection with your API server for multiple API requests can be a big performance improvement. Pretty much every web server should support keep-alive connections if configured correctly. Keep-Alive 保持连接有助于降低频繁建立完整TCP连接的损耗
  • HTTP Compression – HTTP compression can be used both for response bodies (Accept-Encoding: gzip) and for request bodies (Content-Encoding: gzip) to improve the network performance of an HTTP API. 请求或者响应设置此头能有助于提高网络性能
  • HTTP Caching – Provide a Cache-Control header on your API responses. If they’re not cacheable, “Cache-Control: no-cache” will make sure proxies and browsers understand that. (RFC2616 §14.9) 如果设置成Cache型,那么刷新的时机很重要
  • Cache Validation – If you have cacheable API hits, you should provide Last-Modified or ETag headers on your responses, and then support If-Modified-Since or If-None-Match request headers for conditional requests. This will allow clients to check if their cached copy is still valid, and prevent a complete resource download when not required. If implemented properly, you can make your conditional requests more efficient than usual requests, and also save some server-side load. (RFC2616 §13.3)
  • Conditional Modifications – ETag headers can also be used to enable conditional modifications of your resources. By supplying an ETag header on your GETs, later POST, PATCH or DELETE requests can supply an If-Match header to check whether they’re updating or deleting the resource in the same state they last saw it in. (RFC2616 §14.24)
  • Absolute Redirects – It’s a little known requirement of HTTP/1.1 that redirects (eg. 201, 301, 302, 303, 307 response codes) are supposed to contain an absolute URI in the Location response header. Many clients do support relative URIs in Location, but if you want your API to be broadly compatible with many clients, you should use absolute URIs in any redirects. (RFC2616 §14.30)
  • Link Response Header – In a RESTful API, it’s often necessary to provide links to other resources even if the content-type of your response doesn’t have a natural way to provide links (for example, a PDF or image representation). RFC5988 specifies a method of providing links in a response header.
  • Canonical URLs – For resources with multiple URLs, RFC6596 defines a consistent method of providing a canonical URL link.
  • Chunked Transfer Encoding – If you have large content responses, Transfer-Encoding: Chunked is a great way to stream responses to your client. It will reduce the memory usage requirements (especially for implementing HTTP Compression) of your server and intermediate servers, as well as provide for a faster time-to-first-byte response.
  • Error Handling in Chunked Transfer Encoding – Before you go and implement chunked transfer encoding, figure out how you’re going to handle an error that occurs mid-request. Once you start streaming your response, you can’t change your HTTP status code. Typically you’d define a way of representing an error inside your content-type.
  • X-HTTP-Method-Override – Some HTTP clients can’t support anything but GET and POST;利用X-HTTP-Method-Override 头部来重写HTTP请求
  • URL Length – GET请求中 URL不能太长,超过2000字符串容易出现兼容性问题

API Design

  • Statelessness 无状态设计,千万不要在API中传递某种状态。同时注意应保证应用服务器无状态化,这样才能比较容易的无痛伸缩
  • Content Negotiation 内容协商/谈判,如果你想让你的响应有多重表现形式,那么可以HTTP请求头部选用Accept headers或者请求URL中附带不同格式声明,比如?format=json
  • URI Templates – URI Templates 是一种赋予客户端可以组合请求的方法,可以了解,但感觉不怎么能用到呢
  • Design for Intent 不要把内部的业务逻辑对象在API的设计中,API是给客户端使用的,所以应该首先满足客户端需求
  • Versioning API拆分版本,常见手段URL携带版本信息,如/v1/path ;或者请求Header 中携带不同版本头信息
  • Authorization 请记住并不是所有用户都能不做限制地访问系统的资源。
  • Bulk Operations 批量操作,客户端显然更倾向于减少请求次数下做更多的事情或者修改更多的数据。如果需要客户端迭代请求某类操作,那么这类操作就应该设计为支持批量操作的接口
  • Pagination 分页。它既能减少下发给客户端的数据,也能减少服务端的计算量。可以携带时间戳或者版本信息的分页请求,这样即使在此期间有对象发生变化,也不会在分页中产生同样的重复条目
  • Unicode 这个标配吧,使用Unicode编码,支持不同语言可能是潜在需求
  • Error Logging 请求错误日志一部分记录用户错误的处理请求,一部分处理服务端内部业务逻辑、代码异常,建议分开写。日志的作用不只是记录错误,它的基本作用是记录事件发生。

Content

  • Content Types 使用常见易于处理个请求或者响应格式能降低不必要的成本
  • HATEOAS 如果对于某些请求能返回接下来客户端能做什么并且客户端也能遵守这个约定的话,可以尽最大可能减少代码修改
  • Date/time 如果处理国际化业务时,那么时间的记录传递最好能携带时区的信息。如果统一使用UNIX TimeStamp来实现的话,可能省点心

Security

  • SSL 无论如何都应该倾向于使用基于HTTPS的API,外部的必须要使用
  • Cross-site Request Forgery (CSRF) 如果你的认证方式使用的是UI界面交互式认证的话,很容易受到CSRF攻击影响。
  • Throttling 这就是访问限制,不要使得某个API被用户“刻意“频繁访问时搞挂系统,如果超出限制,就返回个503带着Retry-After 响应头部
  • Subtle Denial of Service 不要被一些常见的巧妙的攻击搞垮系统,比如SlowlorisBillion laughs, and ReDoS 这类攻击通常都能导致一些拒绝服务攻击。

Client

  • Connection Keep-Alive HTTP请求客户端可能需要做些设置后才能开启保持链接特性
  • 401 before Authorization 有些客户端可能需要先获得一次401 Unauthorized才能再下次请求携带Auth头,这就非常恶心了

Other Stuff

  • Documentation 写接口文档虽然无聊但很重要,最好有可以运行的代码示例
  • Design with a Customer! 为API的消费者设计API
  • Feedback 为你的API使用者提供反馈渠道
  • Automated Testing 应该能够轻松地自动测试