当前位置: 首页 > Linux

微服务指南北上(三):RestfulAPI设计简介

时间:2023-04-06 23:07:10 Linux

API的定义取决于选择的IPC通信方式。如果是消息机制(比如AMQP或者STOMP),API由消息通道(channel)和消息类型组成;如果使用HTTP机制,则是基于request/response(url调用http),这里先简单介绍一下RestfulAPI的定义。设计原则域名尽量将API部署在专用域名下,如:https://api.example.com也可以放在主域名下:https://example.org/api/version放在Accept头信息中间制作版本,版本之间平滑过渡,对于设计和维护一套API来说是一个巨大的挑战。因此,最好在设计之初就使用一些方法,以防止可能遇到的问题。为避免API变更导致意外结果或调用失败,最好强制所有访问都要求指定版本号。请避免提供默认版本号,一旦提供,以后将很难更改。最适合放置版本号的地方是在URL中,或者在Accept部分的头部信息(HTTPHeaders)中与其他元数据(metadata)一起提交的自定义类型(contenttype)。https://api.example.com/v1/或接受:application/vnd.heroku+json;version=3提供Request-Id为每个请求响应包含一个Request-Id字段,并使用UUID作为值。它通过在客户端、服务器或任何支持服务上记录此值,为我们提供了一种跟踪、诊断和调试请求的机制。路径资源名称在RESTful架构中,每一个URL都代表一个资源(resource),所以URL中不能有动词,只能有名词,使用的名词往往对应数据库的表名。一般来说,数据库中的表是同类记录的“集合”,所以API中的名词也应该使用复数形式。比如有一个提供动物园信息的API,包括各种动物和员工的信息,那么它的路径应该设计成这样。https://api.example.com/v1/zooshttps://api.example.com/v1/animalshttps://api.example.com/v1/employees动作(Actions)好结束不需要特别说明对于资源,但在特殊情况下,有必要为某些资源指定行为。为了描述清楚,在行为前加一个标准动作:/resources/:resource/actions/:action如:/runs/{run_id}/actions/stop路径和属性名与域名命名规则一致,使用小写字母并使用-分隔路径名,例如:service-api.com/usersservice-api.com/app-setups属性也使用小写字母,但属性名必须用下划线分隔,以省略Javascript中的引号。例如:service_class:"first"支持方便的不带id的间接引用。在某些情况下,用户不方便提供ID来定位资源。比如一个用户想获取他的应用在Heroku平台上的信息,但是这个应用的唯一标识是UUID。在这种情况下,您应该支持通过名称和ID访问的接口,例如:$curlhttps://service.com/apps/{app_id_or_name}$curlhttps://service.com/apps/97addcf0-c182$curlhttps://service.com/apps/www-prod不要只接受名称的使用而放弃id的使用。最小化路径嵌套在一些具有嵌套父子路径关系的资源数据模块中,路径可能有很深的嵌套关系,例如:/orgs/{org_id}/apps/{app_id}/dynos/{dyno_id}建议在根路径下指定资源,限制路径的嵌套深度。使用嵌套范围内的资源。在上面的例子中,dyno属于app,app属于org,可以表示为:/orgs/{org_id}/orgs/{org_id}/apps/apps/{app_id}/apps/{app_id}/dynos/dynos/{dyno_id}HTTPverbs对资源的具体操作类型用HTTPverbs表示。常用的HTTP动词包括以下五个(对应的SQL命令在括号中):GET(SELECT):从服务器获取资源(一项或多项)。POST(CREATE):在服务器上创建一个新的资源。PUT(UPDATE):更新服务器上的资源(客户端提供改变后的完整资源)。PATCH(UPDATE):更新服务器上的资源(客户端提供更改的属性)。删除(DELETE):从服务器中删除一个资源。一些例子:GET/zoos:列出所有动物园POST/zoos:创建一个新动物园GET/zoos/ID:获取指定动物园的信息PUT/zoos/ID:更新指定动物园的信息(提供所有动物园信息)zooInformation)PATCH/zoos/ID:Updateinformationofaspecifiedzoo(providesomeinformationaboutthezoo)DELETE/zoos/ID:删除一个动物园GET/zoos/ID/animals:列出指定动物园的所有动物DELETE/zoos/ID/animals/ID:删除指定动物园的指定动物过滤信息。如果记录很多,服务器不可能全部返回给用户。API应提供参数并过滤返回的结果。以下是一些常用参数:?limit=10:指定返回的记录数?offset=10:指定返回记录的起始位置。?page=2&per_page=100:指定页码和每页记录数。?sortby=name&order=asc:指定返回结果按哪个属性排序,以及排序顺序。?animal_type_id=1:指定过滤条件参数的设计允许冗余,即API路径和URL参数允许偶尔重复。例如,GET/zoo/ID/animals与GET/animals?zoo_id=ID具有相同的含义。响应(Responses)状态码服务器返回给用户的状态码和提示信息,常见的如下(方括号中是状态码对应的HTTP动词):200OK-[GET]:服务器成功返回用户请求的数据,操作是幂等的(Idempotent)。201CREATED-[POST/PUT/PATCH]:??用户成功创建或修改数据。202Accepted-[*]:表示请求已进入后台队列(异步任务)204NOCONTENT-[DELETE]:用户删除数据成功。400INVALIDREQUEST-[POST/PUT/PATCH]:??用户发送的请求有错误,服务器没有创建或修改数据。这个操作是幂等的。401Unauthorized-[*]:表示用户没有权限(错误的令牌、用户名、密码)。403Forbidden-[*]表示用户已获得授权(与401错误相反),但访问被禁止。404NOTFOUND-[*]:用户发送的请求是针对一条不存在的记录,服务器没有进行任何操作,是幂等的。406NotAcceptable-[GET]:用户请求的格式不可用(比如用户请求JSON格式,但只请求XML格式)。410Gone-[GET]:用户请求的资源被永久删除,不会再次获取。422无法处理的实体-[POST/PUT/PATCH]创建对象时发生验证错误。500INTERNALSERVERERROR-[*]:服务器发生错误,用户将无法确定请求是否成功。默认情况下,提供资源的(UU)ID会为每个资源提供一个id属性。除非您有更好的理由,否则请使用UUID。不要使用在服务器或资源上不是全局唯一的标识符,尤其是自动递增的ID。生成8-4-4-4-12格式的小写UUID,例如:"id":"01234567-89ab-cdef-0123-456789abcdef"提供标准时间戳为资源提供默认的创建时间created_at和更新时间updated_at,例如:{..."created_at":"2012-01-01T12:00:00Z","updated_at":"2012-01-01T13:00:00Z",...}使用UTC(协调世界时)时间,格式化withISO8601接收和返回时只能使用UTC格式(ISO8601格式的数据)或者使用时间戳,例如:"finished_at":"2012-01-01T12:00:00Z"or"timestamp":"1472486035"错误处理如果状态码是4xx,应该给用户返回一条错误信息。一般来说,error作为返回信息中的键名,错误信息作为键值。{error:"InvalidAPIkey"}返回结果针对不同的操作,服务器返回给用户的结果应满足以下规范。GET/collection:返回资源对象的列表(数组)GET/collection/resource:返回单个资源对象POST/collection:返回新生成的资源对象PUT/collection/resource:返回完整的资源对象PATCH/collection/resource:returnsCompleteresourceobjectDELETE/collection/resource:返回一个空文档以确保响应JSON并最小化它。目前,为了确保响应最小化,一般使用json字符串,请求中额外的空格会增加响应大小,现在很多HTTP客户端的两个端点都会自行输出人类可读格式(“prettify”)的JSON.因此最好将响应JSON保持在最低限度,例如:{"beta":false,"email":"alice@heroku.com","id":"01234567-89ab-cdef-0123-456789abcdef""last_login":"2012-01-01T12:00:00Z","created_at":"2012-01-01T12:00:00Z","updated_at":"2012-01-01T12:00:00Z"}代替其中:{"beta":false,"email":"alice@heroku.com","id":"01234567-89ab-cdef-0123-456789abcdef","last_login":"2012-01-01T12:00:00Z","created_at":"2012-01-01T12:00:00Z","updated_at":"2012-01-01T12:00:00Z"}超媒体APIRESTfulAPI最好实现超媒体,即提供链接在返回的结果中连接到其他API方法可以让用户在不检查文档的情况下知道下一步要做什么。例如,当用户向api.example.com的根目录发出请求时,会得到这样一个文件。{"link":{"rel":"collectionhttps://www.example.com/zoos","href":"https://api.example.com/zoos","title":"列表zoos","type":"application/vnd.yourformat+json"}}上面的代码表示文档中有一个link属性,用户读到这个属性就知道接下来要调用什么API了。rel表示本API与当前URL的关系(集合关系,给出集合的URL),href表示API的路径,title表示API的标题,type表示返回类型。HypermediaAPI的设计被称为HATEOAS。Github的API就是这样设计的。访问api.github.com将获得所有可用API的URL列表。{"current_user_url":"https://api.github.com/user","authorizations_url":"https://api.github.com/authorizations",//...}从上面可以看出,如果想获取当前用户的信息,应该访问api.github.com/user,然后会得到如下结果。{"message":"Requiresauthentication","documentation_url":"https://developer.github.com/v3"}以上代码表示服务器给出提示信息和文档的URL。参考文章github的RestfulInterfaceRestfulAPI设计原理及案例修正http-api-designbyLiuYingguang@火蜜工作室OpenBI交流群:495266201MicroService微服务交流群:217722918邮箱:liuyg#liuyingguang.cn博主主页(==Prevent爬虫==):http://blog.liuyingguang.cnOpenBI问答社区:http://www.openbi.tk