RAML的全称是[RESTful API建模语言](http://raml.org/spec.html),这是一种基于[YAML](http://yaml.org/)格式的新规范,因此机器与人类都能够轻易地理解其中的内容。但RAML的目的不仅仅在于创建更易于理解的规范(你可以将这一工作指派给文档团队,他们会做得更好)而已。RAML的设计者[Uri Sarid](https://twitter.com/usarid)希望使用者能够打破固有的思维,在开始编写代码之前以一种全新的方式对API进行建模。 [TOC] [Roy Fielding](http://roy.gbiv.com/)博士在他的博客[Untangled](http://roy.gbiv.com/untangled/)中指出,现在的人们总有一种倾向,他们只考虑短期的设计,目光只能看到我们所知的、我们目前所想的内容。 REST风格的发明者Roy Fielding表示:“很不幸,人们很善于处理短期的设计,但对于长期的设计通常就束手无策了。” 设计API的一大挑战在于,API通常都会存在较长的一段时间,有可能会存在数年之久。毕竟,API的设计需要开发者投入大量的精力,但同样对于客户来说也是一种极大的投入,因为客户也依赖于这些API,需要基于它们进行开发。从2009年起,Uri开始思考如何解决API的长期设计的挑战,他希望能够找到一种工具,让设计者只需几行代码就能够对API进行建模(或设计),然后快速地生成一个原型,让全球的开发者都能够尝试你的原型并提供反馈。在2013年,随着RAML 0.8的发布,他的梦想终于变成了现实。 自那时起,人们对于RAML的兴趣就在不断地升温。无论是大型企业还是小公司,他们都开始意识到了RAML所带来的益处:包括以一种人类可读的格式设计API、在设计时就看到这些API将怎样工作、并且能够为API创建一个活动的、全功能的示例,让开发者能够简单地通过点击按键,对这个API发起实际的调用。 [![](https://box.kancloud.cn/2015-09-12_55f434c323d71.png)](https://box.kancloud.cn/2015-09-12_55f434c323d71.png) > **提示** > 所有的RAML工具都是开源的,可以从[http://RAML.org/projects](http://raml.org/projects)免费下载。我的雇主MuleSoft还提供了这些工具的免费托管版本,你可以从[AnyPoint Platform for APIs](http://anypoint.mulesoft.com/apiplatform/)平台试用这些工具。 ## API契约的设计周期 但是,仅仅简单地创建一个原型是不够的。MuleSoft创建了一种API契约设计周期图,这一设计的前提在于API不仅仅是机器之间的一种契约,同样也是提供商与用户之间的一种契约。 ![](https://box.kancloud.cn/2015-09-12_55f434c45d699.png) 这也意味着,在设计与创建原型之后,开发API的公司需要找到一种方式以共享他们的API,并从使用者那里获取反馈。这些有价值的反馈能够让公司找到设计中的缺陷,例如数据或结构中的不一致性,以及API中的一些令人困惑之处。在这一阶段及时发现设计中的问题非常关键,因为一旦你的API发布之后需要修改,那么在大多数情况下都会破坏向后兼容性,而这将影响API的使用。 提示 这一周期同样也是[规范驱动开发](http://www.mikestowe.com/2014/11/what-is-spec-driven-development.php)(Spec Driven Development)过程的基础。 ### API Console与API Notebook 为了实现这一设计周期,又出现了两种工具:即API Console与API Notebook。API Console与其它API控制台的作用很相似,例如Mashery的[IO Docs](http://www.mashery.com/product/io-docs)与[Swagger](http://swagger.io/),它提供了一个可进行文档工作的交互式环境,让开发者输入数据和发起调用请求。这意味着开发者在设计API原型的同时,也能够快速地看到可用的资源与方法,并且立即进行测试,以获得第一时间的验证结果。同时,一旦你的API发布之后,除了静态文档之外,你也能够发布交互式的文档,让开发者在一个相当简单的界面中试用这些API,并对API调用进行调试。 另一方面,[API Notebook](http://apinotebook.com/)的交互性与探索性更进一步,它能够让开发者使用JavaScript去调用你的(以及其他人的)API。在API Notebook中还能够对数据进行各种操作,通过实际应用中的用例观察它的运作。也就是说,开发者能够通过用例测试他们的原型,所需的只是编写几行JavaScript而已。 举例来说,在下面这张截图中,用户能够连接到[Instagram的API](https://instagram.com/developer/),通过OAuth进行验证,并尝试搜索带有“kitten”这个标签的图片,一步一步完成设计过程。 (点击放大图像) [![](https://box.kancloud.cn/2015-09-12_55f434c9622be.png)](https://box.kancloud.cn/2015-09-12_55f434c9622be.png) 但作为一个RAML工具,API Notebook真正强大的地方在于你可以为API的使用者创建用例,让他们自己进行走察。此外,你所创建的用例场景可以用于原型的设计以及发布于生产环境的API,并且你的调用者也能够通过markdown语法创建自己的Notebook。这样一来,你的使用者就能够共享bug与用例的信息,以获得更好的反馈与支持,并且无需共享任何私有的代码,也无需走查整个应用程序。 这个特性很简单,但它却让你的使用者不必将大量的精力用于寻找问题的根源,同时也让你的支持团队能够快速地重现这些错误,而无需猜测这些问题是否是由客户端代码所引起的。 等到你收集了这些反馈之后,就能够对你的设计进行调整,并决定该设计是否已经可以在生产环境中应用了。它的另一个益处在于,当你的API已经准备好上线时,你就能够在生产环境中使用这两个优秀的工具了,正如上文所说的那样。 为了帮助你的API顺利上线,可以在社区中找到许多其它实用的工具,包括用于生成API的相应代码以及对API进行测试的工具,例如[Abao](https://github.com/cybertk/abao)。除了API Console与the API Notebook之外,还有大量的工具能够帮助你进行文档化工作,包括[RAML to HTML](https://github.com/kevinrenskers/raml2html),它能够生成一个单一的HTML文件(与API console相类似)作为文档。以及[使用PHP的RAML2HTML](http://www.mikestowe.com/2014/05/raml-2-html.php)工具,这个脚本能够创建一个完整的、多页面的文档网站: (点击放大图像) [![](https://box.kancloud.cn/2015-09-12_55f434cbe6a91.png)](https://box.kancloud.cn/2015-09-12_55f434cbe6a91.png) 这个脚本可以进行充分的自定义,可以修改全局的模板甚至是内容块,以满足你对于文档的需求。 此外,还有许多工具能够对RAML进行解析,可以将你的API规范整合到你的自定义应用中,而不关心你的应用是用Ruby、PHP、JavaScript、.NET、Python还是Java编写的。 ## 人类可读 由于RAML被设计为一种人类可读的格式,因此通过它开始设计一个全新的API或定义一个现有的API都非常简单。虽然你可以在任意一种编辑器中创建RAML,但最方便的方式还是使用在线的API设计器,或是专门为[Sublime](https://github.com/mulesoft/raml-sublime-plugin)或[Visual Studio](https://github.com/mulesoft-labs/raml-dotnet-tools)等IDE所设计的插件(两者都可以在[RAML.org/projects](http://raml.org/projects)中找到),你可以在设计过程中充分利用它们的工具提示、自动完成以及实时校验功能,这使得整个过程更加简便。 开始设计时,首先创建一个包含以下内容的RAML文件: ~~~ #%RAML 0.8 title: This is My API baseUri: http://api.domain.com version: 1 ~~~ 在以上代码中,我们首先声明这是一个RAML规范,它对应RAML 0.8(版本1很快就会发布了),并声明API的标题、基本URI、以及这个API的版本号(这个示例中的API是版本1)。 在RAML中声明资源非常简单,只需使用/resourceName格式。而添加方法也同样便捷,只需引用相应的HTTP谓词即可: ~~~ #%RAML 0.8 title: This is My API baseUri: http://api.domain.com version: 1 /resource1: get: description: This gets the collection of resource1 post: description: This adds a new item to the collection ~~~ RAML让你能够定义多种相应,返回不同的状态码、头信息以及响应体。例如: ~~~ #%RAML 0.8 title: This is My API baseUri: http://api.domain.com version: 1 /resource1: get: responses: 200: headers: cache-control: example: | public, no-cache, no-store body: application/json: example: | {"name":"Michael Stowe"} application/xml: example: | <name>Michael Stowe</name> 400: #... 401: #... ~~~ RAML本身还有大量的其它特性,让你通过schema与参数定义完整的API。它还允许你使用资源嵌套(与Saas中进行CSS嵌套的方法相近)、文件引用(可以引用多个文件,以保持规范的易读性和易组织性),甚至是变量或属性的设置,从而在整个规范中保持一致性。 举例来说,你可以在规范中按以下方式利用这些特性: ~~~ #%RAML 0.8 title: This is My API baseUri: http://api.domain.com version: 1 /resource1: get: responses: 200: body: application/json: schema: | { "type": "object", "$schema": "http://json-schema.org/draft-03/schema", "id": "http://jsonschema.net", "required": true, "properties": { "firstName": { "type": "string", "required": true }, "lastName": { "type": "string", "required": true, "minLength": 3, "maxLength": 36 } } } /sub-resource: get: queryParameters: firstName: description: "the user’s first name" example: John required: true type: string ~~~ ## 对开发者十分友好 RAML的优点不仅在于简单的格式与丰富的工具,它还能够让开发者应用编码的最佳实践,例如模式与重用代码。这不仅能够极大地减少开发者的工作,还能够促使API在不同的资源与方法中保持统一性。虽然你总是能够抽象出一套schema,以保持规范的良好组织,或是通过“!include”命令引入schema、示例与其它RAML代码片段,但RAML还提供了两个额外的实用与独特的模板特性:即traits与resourceTypes。 ### 通过traits定义通用属性 RAML的traits特性允许你为方法(GET、PUT、POST、PATCH、DELETE等等)定义通用的属性(或traits),例如它们是否可过滤、可搜索或是可分页。 在创建trait时,你实际上是创建了一份模板,它能够通过接受参数为方法提供属性,只需几行代码就能够完成。同时为你所需的trait提供了最大程度的灵活性与自定义能力: ~~~ traits: -searchable: queryParameters: query: description: | JSON array [{"field1","value1","operator1"},…] <<description> example: | <<example>> /people: get: is: [searchable: {description: "search by location name", example: "[\"firstName\"\,\"Michael\",\"like\"]"}] ~~~ ### 通过ResourceTypes为资源定义模板 此外,与traits相似,resourceTypes也允许你为资源本身创建模板,以此调用通用的方法与响应。打个比方,对于Collection这种资源类型来说,你可能会大量用到POST与GET方法,并且通常会返回200、201或400等状态码。只要将它定义为一种resourceType,你就能够通过两行代码就完成调用,而无需为你所创建的每种资源都加入相同的方法与状态码。 ~~~ resourceTypes: - collection: description: Collection of available <<resourcePathName>> get: description: Get a list of <<resourcePathName>>. responses: 200: body: application/json: example: | <<responseVariable>> 400: #... 401: #... /people: type: collection: responseVariable: | { "name" : "Michael Stowe", "company" : "MuleSoft", } ~~~ 你甚至可以在resourceTypes中定义可选的方法,只需为该方法加上一个问号(?)即可。这种可选方法只有在定义了该方法的资源中才会被引入,这就为你赋予了更大的灵活性。 提示 RAML允许你创建任意数目的resourceTypes和traits。不过,如果你发现你所定义的resourceTypes超过两种(collection与item),那么你可能要评估一下你的API,以确保对这些resourceTypes的使用方式是一致的。你可以在[RAML 200教程](http://raml.org/docs-200.html)中了解到更多的知识。 ### 自动生成SDK RAML还可以通过其它工具为开发者节省宝贵的时间与资源,比方说可以通过[APImatic.io](https://apimatic.io/)等提供者为用户提供自动生成多种语言的SDK的能力。使用APImatic.io无需手动编写这些SDK,也不必依赖于社区保持它们的更新,它可以让你简单的导入RAML规范,随后生成面向Java、Python、PHP、Ruby、AngularJS、iOS和 Windows等平台和语言的SDK。 ### 超越代码 RAML正逐渐成为API规范方面的领头人之一,与Swagger和API Blueprint并驾齐驱。现如今已有越来越多的API方案提供者支持这一格式了(包括管理与工具等方面)。 为了加快发展的脚步,同时确保规范的完整性,在RAML于2013年问世的同时,一个由API领域驱动的工作小组也一并成立了。该工作小组将负责指正RAML的发展方向,确保它将继续遵循最佳实践,并符合业界的需求。目前,该工作小组由来自MuleSoft、AngularJS、Intuit、Airware、PayPal、API Science、Akana和Cisco的代表所组成。 RAML的出现不过一年多的时间,目前1.0版本的工作还在进行之中,新版本的目标是提供更多的功能,并且更好地满足业界的需求,同时推进API的最佳实践。当然,它也面临着一些挑战,包括如何定义与描述超媒体,这一点在所有的主要规范中都被提及。 ## 如何为克服这些挑战作出贡献 开源社区的优点就体现在这里,新的点子总是能够找到立足之处。每个有志之士都可以通过访问[RAML.org](http://raml.org/)加入这一项目,并且在[GitHub](https://github.com/raml-org/raml-spec)上贡献独创的工具,或是创建规范的分支。毕竟,RAML的强大之处不仅仅在于目前它所实现的部分,即通过一个单一数据源,通过可视化的方式进行API的设计、创建原型、构建、共享以及进行文档化,而在于它将如何对未来产生持续性的影响。 ## 关于作者 ![](https://box.kancloud.cn/2015-09-12_55f434cda4d46.jpg) **Michael Stowe****是一位****RAML****的**忠实支持者,他在创建应用方面已有超过10年的经验,所涉及的领域包括法规实施、非盈利项目、工业,并且加入了多个开源项目。他目前在MuleSoft担任开发者管理经理,作为工作的一部分,他经常在各种技术型会议上进行RAML以及API设计方面的演讲,包括API Con、API Strategy and Design以及API World等等。由Michael所编著的一本关于REST API设计的书籍即将面世。你可以通过@mikegstowe关注他的Twitter,了解他的最新帖子。你也可以通过[http://www.mikestowe.com](http://www.mikestowe.com/)观看他所做的演讲,并了解他的技术思想。 **查看英文原文:**[The Power of RAML](http://www.infoq.com/articles/power-of-raml)