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 的一大优势是强大的工具链支持,覆盖设计、开发、测试、文档全流程。

常用工具列表

完整工具列表见 RAML Projects

7. RAML 规范现状

RAML 1.0 RC 版于 2015 年 11 月 3 日发布,当时预计一个月内发布正式版。

其前身 RAML 0.8 发布于 2014 年秋季,目前仍有大量工具支持。

8. 延伸阅读

9. 总结

本文介绍了 RESTful API 建模语言 RAML,演示了如何使用 RAML 1.0 (RC) 编写简洁、可维护的 API 规范。

我们掌握了:

  • ✅ 基本语法和结构
  • ✅ 使用 !include 拆分文件,避免重复
  • ✅ 集成 JSON Schema 的方式
  • ✅ 丰富的工具生态,提升开发效率

随着 1.0 正式版的发布和工具链的完善,RAML 已成为 API 设计领域不可忽视的力量,值得在团队中推广使用。


原始标题:Intro to RAML - The RESTful API Modeling Language | Baeldung

« 上一篇: Java Web Weekly 49
» 下一篇: Java XML指南