1. 概述
本文将带你入门 RESTful API Modeling Language(RAML),这是一种厂商中立、开放规范的 API 描述语言,基于 YAML 1.2 和 JSON,专为描述 RESTful API 而设计。
我们将从 RAML 1.0 的基本语法和文件结构讲起,通过定义一个简单的 JSON 接口来演示其使用方式。你将学会如何利用 includes 机制简化 RAML 文件的维护,提升可读性和可维护性。如果你的旧系统使用了 JSON Schema,我们也会展示如何将其无缝集成到 RAML 中。
接着,我们会介绍一系列能极大提升开发效率的 RAML 工具,包括编辑器、文档生成器、代码生成器等。
最后,我们会简要说明 RAML 规范的当前发展状态,帮助你判断是否值得在项目中引入。
2. 定义你的 API(创建 .raml 文件)
我们将定义一个简单的 API:围绕实体 Foo 实现基本的 CRUD 操作和几个查询接口。具体包括以下接口:
GET /api/v1/foos
POST /api/v1/foos
GET /api/v1/foos/{id}
PUT /api/v1/foos/{id}
DELETE /api/v1/foos/{id}
GET /api/v1/foos/name/{name}
GET /api/v1/foos?name={name}&ownerName={ownerName}
该 API 设计为无状态,使用 HTTP Basic 认证,并通过 HTTPS 加密传输。数据格式选用 JSON(RAML 也支持 XML)。
2.1. 根级别配置
首先创建一个名为 api.raml
的文本文件(推荐使用 .raml
后缀,文件名可自定义),并在第一行声明 RAML 版本。根级别定义适用于整个 API 的全局配置:
#%RAML 1.0
title: Baeldung Foo REST Services API using Data Types
version: v1
protocols: [ HTTPS ]
baseUri: http://myapi.mysite.com/api/{version}
mediaType: application/json
注意第 3 行 baseUri
中的 {version}
,大括号表示这是一个变量引用,会自动替换为同名属性的值。最终生成的 baseUri 为:http://myapi.mysite.com/api/v1
⚠️
version
属性是可选的,不一定非要出现在baseUri
中。
2.2. 安全认证
安全机制同样在根级别定义。我们添加 HTTP Basic 认证方案:
securitySchemes:
basicAuth:
description: Each request must contain the headers necessary for
basic authentication
type: Basic Authentication
describedBy:
headers:
Authorization:
description: Used to send the Base64-encoded "username:password"
credentials
type: string
responses:
401:
description: |
Unauthorized. Either the provided username and password
combination is invalid, or the user is not allowed to access
the content provided by the requested URL.
2.3. 数据类型
接下来定义 API 使用的数据类型:
types:
Foo:
type: object
properties:
id:
required: true
type: integer
name:
required: true
type: string
ownerName:
required: false
type: string
上面是标准写法。RAML 提供了更简洁的语法糖,让定义更轻量:
types:
Foo:
properties:
id: integer
name: string
ownerName?: string
Error:
properties:
code: integer
message: string
✅ 小技巧:属性名后加 ?
表示该字段可选,简单粗暴。
2.4. 资源
定义 API 的顶级资源(URI):
/foos:
2.5. URI 参数
扩展资源路径,定义包含路径参数的子资源:
/foos:
/{id}:
/name/{name}:
✅ {}
中的内容是 URI 参数占位符,与前面 baseUri
中的变量引用不同,这里只是声明路径参数。
2.6. 方法
为每个资源定义支持的 HTTP 方法:
/foos:
get:
post:
/{id}:
get:
put:
delete:
/name/{name}:
get:
2.7. 查询参数
定义 /foos
接口的查询参数,语法与数据类型定义一致:
/foos:
get:
description: List all Foos matching query criteria, if provided;
otherwise list all Foos
queryParameters:
name?: string
ownerName?: string
2.8. 响应
定义接口的响应结构和状态码。响应体通常关联数据类型并提供示例。
⚠️ RAML 1.0 支持 JSON Schema,用于兼容旧版本或特定场景,我们稍后会讲。
先看 /foos/{id}
的 GET 接口:
/foos:
...
/{id}:
get:
description: Get a Foo by id
responses:
200:
body:
application/json:
type: Foo
example: { "id" : 1, "name" : "First Foo" }
再看 /foos
的 GET 接口,返回数组:
/foos:
get:
description: List all Foos matching query criteria, if provided;
otherwise list all Foos
queryParameters:
name?: string
ownerName?: string
responses:
200:
body:
application/json:
type: Foo[]
example: |
[
{ "id" : 1, "name" : "First Foo" },
{ "id" : 2, "name" : "Second Foo" }
]
✅ Foo[]
表示返回 Foo 对象的数组,example 用多行字符串表示 JSON 数组。
2.9. 请求体
为 POST 和 PUT 接口定义请求体。以创建 Foo 为例:
/foos:
...
post:
description: Create a new Foo
body:
application/json:
type: Foo
example: { "id" : 5, "name" : "Another foo" }
responses:
201:
body:
application/json:
type: Foo
example: { "id" : 5, "name" : "Another foo" }
2.10. 状态码
创建资源返回 201 Created
,更新返回 200 OK
。同时也要定义错误响应,例如资源未找到:
404:
body:
application/json:
type: Error
example: { "message" : "Not found", "code" : 1001 }
3. RAML 与 JSON Schema
在 RAML 1.0 引入 data types
之前,对象和请求/响应体都用 JSON Schema 定义。
虽然 types
更强大,但有些场景仍需使用 JSON Schema(如遗留系统集成)。
RAML 0.8 使用 schemas
根节点,现在推荐使用 types
,因为 schemas
可能在未来版本被废弃。两者功能等价。
使用 JSON Schema 定义 Foo 类型:
types:
foo: |
{ "$schema": "http://json-schema.org/schema",
"type": "object",
"description": "Foo details",
"properties": {
"id": { "type": integer },
"name": { "type": "string" },
"ownerName": { "type": "string" }
},
"required": [ "id", "name" ]
}
在接口中引用该 Schema:
/foos:
...
/{id}:
get:
description: Get a Foo by its id
responses:
200:
body:
application/json:
type: foo
...
4. 使用 Includes 进行重构
从上面例子可以看出,API 定义可能变得冗长且重复。
RAML 提供了 !include
机制,可以把重复或复杂的部分抽离到独立文件,避免“复制粘贴改多处”的踩坑模式。
例如,将数据类型拆分到单独文件:
types:
Foo: !include types/Foo.raml
Error: !include types/Error.raml
如果使用 JSON Schema:
types:
foo: !include schemas/foo.json
error: !include schemas/error.json
5. 完整的 API 定义
将数据类型和示例全部外置后,主 RAML 文件变得非常清爽:
#%RAML 1.0
title: Baeldung Foo REST Services API
version: v1
protocols: [ HTTPS ]
baseUri: http://rest-api.baeldung.com/api/{version}
mediaType: application/json
securedBy: basicAuth
securitySchemes:
basicAuth:
description: Each request must contain the headers necessary for
basic authentication
type: Basic Authentication
describedBy:
headers:
Authorization:
description: Used to send the Base64 encoded "username:password"
credentials
type: string
responses:
401:
description: |
Unauthorized. Either the provided username and password
combination is invalid, or the user is not allowed to access
the content provided by the requested URL.
types:
Foo: !include types/Foo.raml
Error: !include types/Error.raml
/foos:
get:
description: List all Foos matching query criteria, if provided;
otherwise list all Foos
queryParameters:
name?: string
ownerName?: string
responses:
200:
body:
application/json:
type: Foo[]
example: !include examples/Foos.json
post:
description: Create a new Foo
body:
application/json:
type: Foo
example: !include examples/Foo.json
responses:
201:
body:
application/json:
type: Foo
example: !include examples/Foo.json
/{id}:
get:
description: Get a Foo by id
responses:
200:
body:
application/json:
type: Foo
example: !include examples/Foo.json
404:
body:
application/json:
type: Error
example: !include examples/Error.json
put:
description: Update a Foo by id
body:
application/json:
type: Foo
example: !include examples/Foo.json
responses:
200:
body:
application/json:
type: Foo
example: !include examples/Foo.json
404:
body:
application/json:
type: Error
example: !include examples/Error.json
delete:
description: Delete a Foo by id
responses:
204:
404:
body:
application/json:
type: Error
example: !include examples/Error.json
/name/{name}:
get:
description: List all Foos with a certain name
responses:
200:
body:
application/json:
type: Foo[]
example: !include examples/Foos.json
6. RAML 工具生态
RAML 的一大优势是强大的工具链支持,覆盖设计、开发、测试、文档全流程。
常用工具列表
- ✅ API Designer:基于 Web 的快速 API 设计工具
- ✅ API Workbench:支持 RAML 0.8/1.0 的 IDE 插件(Atom)
- ✅ RAML Cop:RAML 文件校验工具
- ✅ RAML for JAX-RS:Java 骨架代码生成 / 反向生成 RAML
- ✅ RAML Sublime Plugin:Sublime Text 语法高亮
- ✅ RAML to HTML:生成 HTML 文档
- ✅ raml2pdf:生成 PDF 文档
- ✅ RAML2Wiki:生成 Confluence/JIRA Wiki 文档
- ✅ SoapUI RAML Plugin:SoapUI 的 RAML 插件,用于接口测试
- ✅ Vigia:基于 RAML 生成集成测试用例
完整工具列表见 RAML Projects。
7. RAML 规范现状
RAML 1.0 RC 版于 2015 年 11 月 3 日发布,当时预计一个月内发布正式版。
其前身 RAML 0.8 发布于 2014 年秋季,目前仍有大量工具支持。
8. 延伸阅读
- RAML.org – RAML 官方网站
- json-schema.org – JSON Schema 官方站
- Understanding JSON Schema – JSON Schema 详解
- Wikipedia RAML Page – 维基百科条目
9. 总结
本文介绍了 RESTful API 建模语言 RAML,演示了如何使用 RAML 1.0 (RC) 编写简洁、可维护的 API 规范。
我们掌握了:
- ✅ 基本语法和结构
- ✅ 使用
!include
拆分文件,避免重复 - ✅ 集成 JSON Schema 的方式
- ✅ 丰富的工具生态,提升开发效率
随着 1.0 正式版的发布和工具链的完善,RAML 已成为 API 设计领域不可忽视的力量,值得在团队中推广使用。