API介绍6:API设计

本章是我们的API之旅的转折点。我们已经结束了基础部分的浏览,准备来看看之前的概念如何与构建API结合起来。在这一章,我们通过设计一个API来讨论API的各个组件。

组织数据

国家地理杂志2011年估计,美国人拍摄了800亿张照片。这么多的照片,你可以想象人们会使用各种不同的方法来组织他们电脑上的照片。一些人会选择全部丢在一个文件夹里。另一些人会细心的将照片放到不同的文件夹,这些文件夹根据年,月和事件的层次关系进行组织。

公司在构建API的时候也会进行类似的考虑。就像我们在第一章提到的,API的目的是让电脑方便的处理公司的数据。处于易用性的考虑,公司可能会决定对所有的数据使用同一个URL,然后让它可以进行搜索(类似于将所有照片放在同一个文件夹里)。另一些公司可能决定数据的每一部分有自己的URL,组织成一个层次关系(就像使用目录和子目录来管理照片)。每一个公司在业界已有的最佳实践的指导下,根据自己的情况选择最合适的方式来组织自己的API。

从架构风格开始

当讨论API的时候,你可能会听到他们谈论“soap”和“rest”,或许你会奇怪这些软件开发者是在工作还是在计划度假。事实上这是两个基于web的API的最常用的架构的名字。SOAP(首字母的缩写)是一个基于XML的设计,它的请求和响应有标准的格式。REST代表表述性状态传递,是一种更开放的方式,它提供了很多约定,但也给API的设计者留了很多自己做决定的空间。

纵观本课程,你可能已经注意到我们更倾向于REST API。这种偏好很大程度上是由于REST那惊人的占有率。这并不是说SOAP不好,它也有自己的优势。然而,我们讨论的焦点仍会保持在REST上,因为你遇到的API很可能是REST类型的。在接下来的部分,我们将谈论构成REST API的组件。

我们的第一个资源

回到第二章,我们谈论过一点资源。回忆一下,资源就是API中的名词(顾客和披萨)。这些是我们希望可以通过我们的API进行处理的东西。

为了感受公司如何设计一个API,我们从披萨店开始试试手。我们将从增加订披萨的功能开始。

为了让客户端可以和我们讨论披萨,我们需要做这些事情:

  • 确定哪些资源是可访问的
  • 为这些资源分配URL
  • 确定允许客户端对这些资源进行哪些操作
  • 估计每个动作需要数据的哪些部分,这些数据应该采用什么格式

第一个任务挑选资源就有些难度。解决这个问题的一个方法是逐步深入了解一个典型的交互需要涉及哪些资源。对于披萨店来说,我们可能会有一个菜单。菜单上是各种披萨。当顾客希望我们为他们做一个披萨的时候,他们下一个订单。在这个背景下,菜单、披萨、顾客和订单听起来都是备选的资源。让我们从订单开始。

下一个步骤是为资源分配URL。可选的方案有很多,幸运的是REST的规定可以提供一些指导。在一个典型的REST API中,一个资源会有两个分配给它的URL模式。第一个是资源名字的复数形式,比如 /orders。第二个是资源名字的复数加上一个唯一的标识符来指定一个资源,比如/orders/<order_id>,其中<order_id>是某一个订单的唯一标识符。这两种URL模式构成了我们的API将会支持的第一个终端。叫它们终端仅仅是因为他们处在一个URL的末尾,比如在 http://example.com/<endpoint_goes_here> 。

既然我们挑选了资源,也为它们分配了URL,我们就需要决定客户端可以执行哪些动作。根据REST的规则,我们说复数终端(/orders)是为了列出所有存在的订单和创建新的订单。带有唯一标识符的复数终端(/orders/<order_id>),是为了获取、更新或者取消某个特定的订单。客户端通过请求中适当的HTTP动词 (GET, POST, PUT 或者DELETE)告诉服务器要执行哪个动作。

总体来说,现在我们的API看起来是这样的:

HTTP动词 终端 动作
GET /orders 列出已有的订单
POST /orders 添加一个新的订单
GET /orders/1 获取订单 #1的详情
GET /orders/2 获取订单 #2的详情
PUT /orders/1 更新订单 #1
DELETE /orders/1 取消订单 #1

有了对于订单终端的详实的动作,最后要做的就是决定客户端和服务器之间要交换哪些数据。借用第3章披萨店的例子,我们可以说一个订单需要外壳类型和配料。我们还需要选择一个客户端和服务器之间传递信息的数据格式。XML和JSON都是很好的选择,但是对于可读性的考虑,我们会选择JSON。

到这个时候,你可以松口气了,我们已经设计了一个实用的API。下面是客户端和服务器使用这个API进行交互的例子:

客户端和服务器使用我们的API进行交互的例子

把资源联系在一起

我们的披萨店的API看起来不错,订单前所未有的多。事实上,生意确实不错,我们决定开始追踪顾客的订单来估计顾客的忠诚度。一个简单的方式是增加一个新的顾客资源。

和订单资源一样,我们的顾客资源需要一些终端。根据规定, /customers和/customers/<id>非常合适。我们将会跳过细节,但是我们要说我们决定了对于每个终端来说哪些动作是有意义的,以及哪些数据代表了一个顾客。假设我们已经完成了这些,我们就遇到了一个有趣的问题:我们怎么把顾客和订单联系起来呢?

REST的实践者们在如何解决联系资源的问题上发生了分歧。一些人认为这种层次结构需要增长,增加终端,比如/customers/5/orders作为订单的所有顾客#5,/customers/5/orders/3作为顾客#5的第三个订单。另一些人认为应该在资源的数据中增加联系的细节来保持结构的扁平。在这种模型下,创建一个订单需要跟订单细节一个传递一个customer_id字段。这两种方案都在使用,所以都需要了解。

API设计中联系数据的两种方式

由于系统中数据的增长,列举所有订单的终端就变得不切实际了。假设我们的披萨店有三百万已完成的订单,你想找出有多少用意大利辣香肠作为配料。向/orders发送一个 GET 请求,并且获取全部的三百万订单就不太合适了。幸好,REST有一个实用的方法在数据中进行搜索。

URL还有另一个我们还没有提到过的组成部分,查询字符串。查询就是搜索,字符串就是文本。查询字符串是URL末尾传递东西到API的少量文本。比如这个URL中问号后面的所有东西都是查询字符串 http://example.com/orders?key=value

REST API使用查询字符串来定义查询的细节。这些细节被称为查询参数。API决定它接受哪些参数,以及为了使查询有效应该为这些参数使用的准确的名字。我们的披萨店API允许客户端使用这个URL来按照配料进行查询: http://example.com/orders?topping=pepperoni 。客户端可以包含多个查询参数,只要将这些参数一个接一个的列出来,中间用and符号(“&”)分隔。比如 http://example.com/orders?topping=pepperoni&crust=thin

查询字符串的另一个用途是限制每个请求返回的数据的数量。通常,API会将结果分组(每组100或500条记录),每次返回一组。这种分割数据的处理就是我们知道的分页(类似于书的分页)。为了允许客户端访问数据的任一页,API会支持一个查询参数,这个参数允许客户端指定它想获取数据的哪一页。在披萨店API中,我们通过允许客户端指定两个参数:page和size来支持分页。如果客户端发送这样的请求 GET /orders?page=2&size=200 我们就知道他们需要结果的第二页,煤业包含200条记录,也就是订单201-400。

译自

Chapter 6: API Design

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容