REST 接口 原文翻译
REST 是什么?
REST 是什么?
REST是表述性状态传递的缩写(REpresentational State Transfer)。 它是分布式 超媒体系统(distributed hypermedia systems) 的体系结构风格,由Roy Fielding于2000年在他的著名论文中首次提出。
与任何其他架构风格一样,REST还具有自己的6个指导约束,如果需要将接口称为 RESTful ,则必须满足这些约束。 这些原则在下面列出。
REST指导原则
- 客户端-服务器( Client-server ) - 通过将用户接口关注点与数据存储关注点分离,我们提高了用户接口跨多个平台的可移植性,并通过简化服务器组件提高了可伸缩性。
- 无状态( Stateless ) - 客户端到服务器的每个请求都必须包含理解该请求所需的所有信息,并且不能利用服务器上存储的任何上下文。因此,会话状态完全保留在客户端上。
- 可缓存( Cacheable ) - 缓存约束要求对请求的响应中的数据被隐式或显式标记为可缓存或不可缓存。如果响应是可缓存的,则授予客户端缓存以将响应数据重新用于以后的等效请求的权限。
- 统一的接口( Uniform interface ) – 通过将通用的软件工程原理应用于组件接口,简化了整个系统架构,并提高了交互的可见性。为了获得统一的接口,需要多个体系结构约束来指导组件的行为。 REST由四个接口约束定义:资源标识;通过表述操纵资源;自我描述的信息;超媒体作为应用程序状态的引擎。
- 分层系统( Layered system ) – 分层系统风格允许通过限制组件的行为来使体系结构由层次结构层组成,从而使每个组件都无法“看到”与它们交互的最上层。
- 按需代码(可选)( Code on demand (optional) ) – REST允许通过以applets或script的形式下载并执行代码来扩展客户端功能(functionality)。通过减少预先实现的功能数量,简化了客户端。
资源( Resource )
REST中信息的关键抽象是一种 资源(Resource) 。可以命名的任何信息都可以是资源:文档或图像,临时服务,其他资源的集合,非虚拟对象(例如人)等。 REST使用资源标识符( resource identifier )来标识组件之间交互中涉及的特定资源。
资源在任何特定时间戳的状态称为资源表述。表述由数据,描述数据的元数据和超媒体链接组成,这些链接可以帮助客户端过渡到下一个所需状态。
表述的数据格式称为媒体类型。媒体类型标识一个规范,该规范定义了如何处理表述。真正的RESTful API看起来像超文本。每个可寻址的信息单元都携带一个地址,该地址可以是显式的(例如,链接和id属性),也可以是隐式的(例如,从媒体类型定义和表述结构派生)。
根据罗伊·菲尔丁(Roy Fielding)的说法:
超文本(或超媒体)是指 信息和控件的同时呈现 ,以便信息成为用户(或机器人)通过其获得选择并选择动作的能力。 请记住,在浏览器上,超文本不必是HTML(或XML或JSON)。 当机器了解数据格式和关系类型时,它们可以跟随链接。
此外, 资源表述应该是自描述性的:客户端不需要知道资源是员工(employee)还是设备(device)。 它应基于与资源关联的媒体类型进行操作。 因此,在实践中,您最终将创建许多 自定义媒体类型(custom media-types) -通常是一种与一种资源关联的媒体类型。
每种媒体类型都定义一个默认处理模型。 例如,HTML定义了超文本的呈现过程以及每个元素周围的浏览器行为。 它与资源方法GET / PUT / POST / DELETE / …无关,只是某些媒体类型元素将定义一个过程模型,就像“具有href属性的锚元素创建一个超文本链接,当选中该链接时, 在与CDATA编码的href属性相对应的URI上调用检索请求(GET)。”
资源方法(Resource Methods)
与REST相关的另一重要事项是用于执行所需转换的 资源方法(Resource Methods)。 许多人错误地将资源方法与 HTTP GET / PUT / POST / DELETE 方法相关联。
罗伊·菲尔丁(Roy Fielding)从未提及任何有关在哪种条件下使用哪种方法的建议。 他强调的只是它应该是 统一的接口(uniform interface)。 如果您决定使用HTTP POST来更新资源-而不是大多数人建议使用HTTP PUT-没关系,并且应用程序接口将是RESTful的。
理想情况下,更改资源状态所需的一切都应是该资源的API响应的一部分-包括方法以及它们将以何种状态离开表述。
一个API在被访问之前,除了初始URI(书签)和一组适合目标受众的标准媒体类型之外,应该不用提前携带其他信息。(即,期望任何可能使用API的客户端都能理解)。 从那时起,所有应用程序状态转换都必须由客户端选择服务器提供的选择来驱动,这些选择出现在接收到的表述中或由用户对这些表述的操作(manipulation)来表明(implied)。这个转变可能取决(或受其限制)于客户对媒体类型和资源通信机制的了解,两者都可以即时改进(例如,按需编码)。
[这里的失败是指带外信息(out-of-band)是驱动交互而不是超文本.]
构建RESTful API时将有益于您的另一件事是, 基于查询的API结果应该由带有摘要信息的链接列表来表述,而不是由原始资源表述的数组来表述,因为查询不能替代资源标识。
REST和HTTP不一样!
很多人喜欢将HTTP与REST进行比较。 REST和HTTP不相同。
REST != HTTP
但是,由于REST还打算使Web(互联网)更加简化和标准,因此他主张更严格地使用REST原理。这就是人们尝试将REST与网络(HTTP)进行比较的地方。罗伊·菲尔丁(Roy fieldd)在其论文中没有提及任何实现指令-包括任何协议首选项和HTTP。现在,如果您遵守REST的6项指导原则,那么您可以将您的接口称为RESTful。
简而言之,在REST体系结构风格中,数据和功能(functionality)被视为资源,并且可以使用统一资源标识符(URI)进行访问。 通过使用一组简单的,定义明确的操作对资源进行操作。 客户端和服务器通过使用标准化的接口和协议(通常为HTTP)来交换资源的表述。
资源与它们的表述(representation)解耦,因此可以以多种格式访问其内容,例如HTML,XML,纯文本,PDF,JPEG,JSON等。 有关资源的元数据可用并用于控制缓存,检测传输错误,协商适当的表述格式以及执行身份验证或访问控制。最重要的是,与资源的每次交互都是无状态的。
所有这些原则都帮助RESTful应用程序变得简单,轻巧和快速。
References:
http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
https://restfulapi.net/
REST约束
REST体系结构约束(REST Architectural Constraints)
REST代表代表性状态转移,该术语由Roy Fielding于2000年提出。它是一种 体系结构风格,用于通过HTTP设计松散耦合的应用程序,通常用于Web服务的开发中。 REST没有强制执行任何有关如何在较低级别实施的规则,它只是提出了较高级别的设计指南,让您考虑自己的实施。
在上一份工作中,我为一家大型电信公司设计了RESTful API长达两年。 在这篇文章中,除了标准的设计实践之外,我将分享我的想法。 您可能在某些方面不同意我的观点,这完全可以。 我很乐意以开放的态度与您讨论任何事情。
让我们从特定于标准设计的内容开始,以清除“ Roy Fielding”要我们构建的内容。 然后,我们将讨论我的东西,这将在您设计RESTful API时朝着更好的方向发展。
体系结构约束
REST定义了6个体系结构约束,这些约束使任何Web服务都成为真正的RESTful API。
- 统一的接口(Uniform interface)
- 客户服务器(Client–server)
- 无状态(Stateless)
- 可缓存(Cacheable)
- 分层系统(Layered system)
- 按需编码(可选)(Code on demand (optional))
统一的接口(Uniform interface)
当约束名称本身应用时,您必须为系统中暴露给API使用者的资源确定API接口,并严格遵循该接口。系统中的资源应该只有一个逻辑URI,并且应该提供一种获取相关数据或其他数据的方法。 最好将资源与网页同义。
任何单个资源都不应太大,并在其表示中包含所有内容。 只要相关,资源应包含 指向相对URI的链接(HATEOAS),以获取相关信息。
另外,整个系统上的资源表述应遵循特定的准则,例如命名约定,链接格式或数据格式(XML或/和JSON)。
所有资源都应通过通用方法(例如HTTP GET)进行访问,并使用一致的方法进行类似的修改。
一旦开发人员熟悉您的API之一,他就应该能够对其他API遵循类似的方法。
客户服务器(Client–server)
从本质上讲,这意味着客户端应用程序和服务器应用程序必须能够独立发展,而彼此之间没有任何依赖关系。 客户应该只知道资源URI,仅此而已。如今,这是web开发中的常规实践,所以对您来说不需要什么花哨的东西。保持简单。
服务器和客户端也可以独立替换和开发,只要它们之间的接口不变即可。
无状态(Stateless)
Roy fielding从HTTP获得了灵感,因此它反映了这一约束。 使所有客户端-服务器交互都变为无状态。 服务器将不存储有关客户端发出的最新HTTP请求的任何内容。 它将每个请求视为新请求。 没有会话(Session),没有历史(history)。
如果客户端应用程序需要是终端用户的有状态应用程序,其中用户登录一次,然后执行其他授权操作,那么来自客户机的每个请求都应该包含为该请求提供服务所需的所有信息——包括身份验证和授权细节。
请求之间不得在服务器上存储任何客户端上下文。 客户端负责管理应用程序的状态。
可缓存(Cacheable)
在当今世界中,缓存数据和响应在任何适用/可能的地方都至关重要。 您在此处阅读的网页也是HTML页面的缓存版本。 缓存可以减轻客户端的性能,并为客户端带来更好的性能,并为服务器提供更好的扩展性。
在REST中,缓存应在适用时应用于资源,然后这些资源必须声明自己可缓存。 可以在服务器或客户端上实现缓存。
管理良好的缓存部分或完全消除了某些客户端-服务器交互,从而进一步提高了可伸缩性和性能。
分层系统(Layered system)
REST允许您使用分层的系统架构,例如,您可以在服务器A上部署API,并在服务器B上存储数据并在服务器C中对请求进行身份验证。 客户端通常无法确定它是直接连接到最终服务器还是中间连接。
按需编码(可选)(Code on demand (optional))
好吧,这个约束是可选的。 大多数时候,您将以XML或JSON的形式发送资源的静态表示。 但是,如果需要,您可以自由返回可执行代码(return executable code)
以支持应用程序的一部分,例如,客户端可以调用您的API来获取UI小部件呈现代码。 这是允许的。
以上所有约束条件都可以帮助您构建真正的RESTful API,并且应该遵循它们。 不过,有时您可能会发现自己违反了一两个约束。 别担心; 您仍在制作RESTful API,但不是“真正的RESTful”。
请注意,上述所有约束与WWW(网络)关系最密切。 使用RESTful API,您可以对Web服务执行与对网页相同的操作。
REST资源命名指南
REST资源命名指南(REST Resource Naming Guide)
在REST中,主要数据表示称为资源。 从长远来看,拥有一个强大且一致的REST资源命名策略–无疑将证明是最佳的设计决策之一。
REST中信息的关键抽象是一种资源。 可以命名的任何信息都可以是资源:文档或图像,临时服务(例如“洛杉矶今天的天气”),其他资源的集合,非虚拟对象(例如人)等 上。 换句话说,任何可能成为作者超文本引用目标的概念都必须符合资源的定义。 资源是到一组实体的概念映射,而不是在任何特定时间点与该映射相对应的实体。
—罗伊·菲尔丁(Roy Fielding)的论文
资源可以是单例或者集合。 例如,"customers
“是一个集合资源,”customer
“是单例资源(在银行域中)。 我们可以使用URI”/customers
“标识”customers
“集合资源。 我们可以使用URI”/customers/{customerId}
“来标识单个”customer
"资源。
资源也可以包含子集合资源。 例如,可以使用URN"/customers/{customerId}/accounts
" (在银行领域中)来标识特定"customer
“的子集合资源”accounts
"。 类似地,子集合资源"accounts
“内的单例资源”account
“可以如下标识:”/customers/{customerId}/accounts/{accountId}
"。
REST API使用统一资源标识符(URI)来寻址资源。 REST API设计人员应创建URI,以将REST API的资源模型传达给潜在的客户开发人员。 正确命名资源后,API直观易用。 如果做得不好,同样的API可能会难以使用和理解。
统一接口的约束部分通过URI和HTTP动词的组合并按照标准和约定来使用来部分解决。
以下是为新API创建资源URI时应遵循的一些技巧。
REST资源命名最佳实践
使用名词来表示资源
RESTful URI应该引用作为事物(名词)的资源,而不是引用动作(动词),因为名词具有动词所没有的属性–类似于资源具有属性。 资源的一些示例是:
- 系统用户
- 用户帐号
- 网络设备等
其资源URI可以设计如下:
http://api.example.com/device-management/managed-devices
http://api.example.com/device-management/managed-devices/{device-id}
http://api.example.com/user-management/users/
http://api.example.com/user-management/users/{id}
为了更清楚,让我们将 资源原型分为四类(文档,集合,存储和控制器),然后 您始终应该将资源放在一种原型中,然后始终使用其命名约定。 为了统一起见,请抵制设计资源的诱惑,这些资源是多个原型的混合体。
- 文档(document)
文档资源是单个概念,类似于对象实例或数据库记录。 在REST中,您可以将其视为资源集合中的单个资源。 文档的状态表示形式通常包括带有值的字段以及指向其他相关资源的链接。
使用“单一”名称表示文档资源原型。
http://api.example.com/device-management/managed-devices/{device-id}
http://api.example.com/user-management/users/{id}
http://api.example.com/user-management/users/admin
- 集合(collection)
集合资源是服务器管理的资源目录。 客户可以建议将新资源添加到集合中。 但是,由集合决定是否创建新资源。 收集资源选择它要包含的内容,并确定每个包含的资源的URI。
使用“多个”名称表示收集资源原型。
http://api.example.com/device-management/managed-devices
http://api.example.com/user-management/users
http://api.example.com/user-management/users/{id}/accounts
- 储存(store)
储存是客户端管理的资源存储库。 存储资源使API客户端可以放入资源,将其撤回并决定何时删除它们。 商店永远不会生成新的URI。 取而代之的是,每个存储的资源都有一个URI,该URI是客户端最初将其放入商店时选择的。
使用“多个”名称表示商店资源原型。
http://api.example.com/cart-management/users/{id}/carts
http://api.example.com/song-management/users/{id}/playlists
- 控制器(controller)
控制器资源为过程概念建模。 控制器资源就像可执行函数一样,带有参数和返回值。 输入和输出。
使用“动词”表示控制器原型。
http://api.example.com/cart-management/users/{id}/cart/checkout
http://api.example.com/song-management/users/{id}/playlist/play
一致性是关键
使用一致的资源命名约定和URI格式,以最大程度地减少歧义并最大程度地提高可读性和可维护性。 您可以实现以下设计提示以实现一致性:
-
使用正斜杠(/)表示层次关系
URI的路径部分使用正斜杠(/)字符表示资源之间的层次关系。 例如
http://api.example.com/device-management http://api.example.com/device-management/managed-devices http://api.example.com/device-management/managed-devices/{id} http://api.example.com/device-management/managed-devices/{id}/scripts http://api.example.com/device-management/managed-devices/{id}/scripts/{id}
-
请勿在URI中使用尾部正斜杠(/)
作为URI路径中的最后一个字符,斜杠(/)不添加任何语义值,并可能引起混淆。 最好将它们完全丢弃
http://api.example.com/device-management/managed-devices/ http://api.example.com/device-management/managed-devices /*This is much better version*/
-
使用连字符(-)来提高URI的可读性
为了使您的URI易于人们扫描和解释,请使用连字符(-)来提高长路径段中名称的可读性。
http://api.example.com/inventory-management/managed-entities/{id}/install-script-location //More readable
http://api.example.com/inventory-management/managedEntities/{id}/installScriptLocation //Less readable
-
请勿使用下划线(_)
可以使用下划线代替连字符作为分隔符–但是,根据应用程序的字体,下划线(_)字符可能会在某些浏览器或屏幕中被部分遮挡或完全隐藏。
为避免这种混淆,请使用连字符(-)代替下划线(_)。
http://api.example.com/inventory-management/managed-entities/{id}/install-script-location //More readable http://api.example.com/inventory_management/managed_entities/{id}/install_script_location //More error prone
-
在URI中使用小写字母
方便时,在URI路径中应始终首选小写字母。
RFC 3986将URI定义为区分大小写,但方案(scheme)和主机组件(host components)除外。 例如
http://api.example.org/my-folder/my-doc //1 HTTP://API.EXAMPLE.ORG/my-folder/my-doc //2 http://api.example.org/My-Folder/my-doc //3
在上面的示例中,1和2相同,但3不是,因为它使用大写字母 My-Folder。
-
不要使用文件扩展名
文件扩展名看起来很糟糕,并且没有任何优势。 删除它们也会减少URI的长度。 没有理由保留它们。
除上述原因外,如果您想使用文件扩展名突出显示API的媒体类型,则应依靠通过Content-Type标头传达的媒体类型来确定如何处理正文内容。http://api.example.com/device-management/managed-devices.xml /*Do not use it*/ http://api.example.com/device-management/managed-devices /*This is correct URI*/
切勿在URI中使用CRUD函数名称
URI不应用于指示执行CRUD功能。 URI应该用于唯一标识资源,而不是对资源进行任何操作。 应该使用HTTP请求方法来指示执行了哪个CRUD功能。
HTTP GET http://api.example.com/device-management/managed-devices //Get all devices
HTTP POST http://api.example.com/device-management/managed-devices //Create new Device
HTTP GET http://api.example.com/device-management/managed-devices/{id} //Get device for given Id
HTTP PUT http://api.example.com/device-management/managed-devices/{id} //Update device for given Id
HTTP DELETE http://api.example.com/device-management/managed-devices/{id} //Delete device for given Id
使用查询组件过滤URI集合
很多时候,您会遇到一些需求,在这些需求中,您将需要根据某些资源属性对资源进行排序,过滤或限制的集合。 为此,请勿创建新的API,而应在资源收集API中启用排序,过滤和分页功能,并将输入参数作为查询参数传递。 例如
http://api.example.com/device-management/managed-devices
http://api.example.com/device-management/managed-devices?region=USA
http://api.example.com/device-management/managed-devices?region=USA&brand=XYZ
http://api.example.com/device-management/managed-devices?region=USA&brand=XYZ&sort=installation-date