RAML 簡介——RESTful API 建模語言

REST
Remote
0
05:12 PM · Dec 01 ,2025

1. 概述

在本文中,我們將介紹 RESTful API 建模語言 (RAML),這是一種與供應商無關、開放規範的語言,基於 YAML 1.2 和 JSON,用於描述 RESTful API。

我們將涵蓋基本的 RAML 1.0 語法和文件結構,同時演示如何定義一個簡單的基於 JSON 的 API。 我們還將展示如何通過使用 includes 來簡化 RAML 文件維護。 如果您有使用 JSON 模式的遺留 API,我們將演示如何將模式集成到 RAML 中。

然後,我們將介紹一些可以增強您進入 RAML 旅程的工具,包括作者工具、文檔生成器等。

最後,我們將總結 RAML 規範的當前狀態。

2. Defining Your API (Creating the .raml file)

The API we’ll define is fairly simple: given the entity types Foo, define basic CRUD operations and a couple of query operations. Here are the resources that we will define for our API:

  • 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}

And let’s define our API to be stateless, using HTTP Basic authentication, and to be delivered encrypted over HTTPS. Finally, let’s choose JSON for our data transport format (XML is also supported).

2.1. Root-Level Settings

We’ll start by creating a simple text file named api.raml (the .raml prefix is recommended; the name is arbitrary) and add the RAML version header on line one. At the root level of the file, we define settings that apply to the entire 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

Notice on line 3 the use of braces { } around the word “version“. This is how we tell RAML that “version” refers to a property and is to be expanded. Therefore the actual baseUri will be: http://myapi.mysite.com/v1

[Note: the version property is optional and need not be a part of the baseUri.]

2.2. Security

Security is also defined at the root level of the .raml file. So let’s add our HTTP basic security scheme definition:

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. Data Types

Next, we’ll define the data types that our API will use:

types:
  Foo:
    type: object
    properties:
      id:
        required: true
        type: integer
      name:
        required: true
        type: string
      ownerName:
        required: false
        type: string

The above example uses expanded syntax for defining our data types. RAML provides some syntactical shortcuts to make our type definitions less verbose. Here is the equivalent data types section using these shortcuts:

types:
  Foo:
    properties:
      id: integer
      name: string
      ownerName?: string
  Error:
    properties:
      code: integer
      message: string

The ‘?’ character following a property name declares that the property is not required.

2.4. Resources

Now, we’ll define the top-level resource (URI) of our API:

/foos:

2.5. URI Parameters

Next, we’ll expand the list of resources, building from our top-level resource:

/foos:
  /{id}:
  /name/{name}:

Here, the braces { } around property names define URI parameters. They represent placeholders in each URI and do not reference root-level RAML file properties as we saw above in the baseUri declaration. The added lines represent the resources //foos/{id} and //foos/name/{name}.

2.6. Methods

The next step is to define the HTTP methods that apply to each resource:

/foos:
  ...
  /{id}:
    get:
    put:
    delete:
  /name/{name}:
    get:

2.7. Query Parameters

Now we’ll define a way to query the foos collection using query parameters. Note that query parameters are defined using the same syntax that we used above for data types:

/foos:
  ...
  get:
    description: List all Foos matching query criteria, if provided;
                 otherwise list all Foos
    queryParameters:
      name?: string
      ownerName?: string

2.8. Responses

Now that we’ve defined all of the resources for our API, including URI parameters, HTTP methods, and query parameters, it is time to define the expected responses and status codes. Response formats are typically defined regarding data types and examples.

JSON schema can be used instead of data types for backward compatibility with an earlier version of RAML. We’ll introduce JSON schema in section 3.

[Note: In the code snippets below, a line containing only three dots (…) indicates that some lines are being skipped for brevity.]

Let’s start with the simple GET request on /foos/{id}:

/foos:
  ...
  /{id}:
    get:
      description: Get a Foo by id
      responses:
        200:
          body:
            application/json:
              type: Foo
              example: { "id" : 1, "name" : "First Foo" }

This example shows that by performing a GET request on the resource //foos/{id}, we should get back the matching Foo in the form of a JSON object and an HTTP status code of 200.

Here is how we’d define the GET request on the /foos resource:

/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" }
              ]

Note the use of square brackets [] appended to the Foo type. This demonstrates how we would define a response body containing an array of Foo objects, with the example being an array of JSON objects.

2.9. Request Body

Next, we’ll define the request bodies that correspond to each POST and PUT request. Let’s begin with creating a new Foo object:

/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. Status Codes

Note in the above example that when creating a new object, we return an HTTP status of 201. The PUT operation for updating an object will return an HTTP status of 200, utilizing the same request and response bodies as the POST operation.

In addition to the expected responses and status codes that we return when a request is successful, we can define the kind of response and a status code to expect when an error occurs.

Let’s see how we would define the expected response for the GET request on /foos/{id} when no resource is found with the given id:

        404:
          body:
            application/json:
              type: Error
              example: { "message" : "Not found", "code" : 1001 }

3. RAML 與 JSON Schema在 RAML 1.0 中引入數據類型之前,對象、請求體和響應體都使用 JSON Schema 進行定義。

使用數據類型非常強大,但仍然存在一些需要使用 JSON Schema 的情況。在 RAML 0.8 中,您使用頂層schemas部分定義您的 schema。

這仍然有效,但建議使用types部分,因為在未來版本中,使用schemas可能被棄用。typesschemastypeschema 都是同義詞。

以下是如何在 .raml 文件的頂層使用 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" ]
    }

以下是如何在 GET /foos/{id} 資源定義中引用 schema 的示例:

/foos:
  ...
  /{id}:
    get:
      description: 獲取一個 Foo 對象,通過其 id
      responses:
        200:
          body:
            application/json:
              type: foo
              ...

4. 使用包含文件進行重構如前文所述,我們的API變得越來越冗長且重複。

RAML規範提供了一個包含機制,允許我們外部化重複且冗長的代碼片段。

我們可以使用包含文件來重構我們的API定義,使其更簡潔,並降低由於“複製/粘貼/在所有地方修復”方法所導致的一類錯誤。

例如,我們可以將Foo對象的數據類型放在types/Foo.raml文件中,將Error對象的數據類型放在types/Error.raml文件中。 那麼我們的types部分將如下所示:

types:
  Foo: !include types/Foo.raml
  Error: !include types/Error.raml

如果使用JSON Schema,那麼我們的types部分可能如下所示:

types:
  foo: !include schemas/foo.json
  error: !include schemas/error.json

5. 完成 API

外部化所有數據類型和示例到其文件後,我們可以使用 include 功能來重構我們的 API。

#%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 API 的工具;有用於生成客户端代碼的工具;有用於生成 HTML 和 PDF 格式的 API 文檔工具;以及有幫助我們測試與 RAML API 規範的工具。

甚至有一個工具可以將 Swagger JSON API 轉換為 RAML。

以下是一些可用的工具示例:

  • API Designer – 一個面向快速高效 API 設計的基於 Web 的工具
  • API Workbench – 一個用於設計、構建、測試和文檔化 RESTful API 的 IDE,支持 RAML 0.8 和 1.0
  • RAML Cop – 一個用於驗證 RAML 文件工具
  • RAML for JAX-RS – 一組從 RAML 規範生成 Java + JAX-RS 應用程序代碼的骨架工具,或從現有 JAX-RS 應用程序生成 RAML 規範的工具
  • RAML Sublime Plugin – Sublime text 編輯器中的語法高亮插件
  • RAML to HTML – 一個用於從 RAML 生成 HTML 文檔的工具
  • raml2pdf – 一個用於從 RAML 生成 PDF 文檔的工具
  • RAML2Wiki – 一個用於生成 Wiki 文檔的工具(使用 Confluence/JIRA 標記)
  • SoapUI RAML Plugin – 一個 RAML 插件,用於流行的 SoapUI 功能 API 測試套件
  • Vigia – 一個能夠基於 RAML 定義生成測試用例的集成測試套件

要查看 RAML 工具和相關項目的完整列表,請訪問 RAML 項目 頁面。

7. 當前的 RAML 狀態

RAML 1.0 (RC) 規範於 2015 年 11 月 3 日獲得候選發佈狀態,在此撰寫時,預計 1.0 版本將在本月完成最終定稿。

它的前身,RAML 0.8 於 2014 年秋季首次發佈,並且仍然被眾多工具支持。

8. 進一步閲讀

以下是一些在學習 RAML 過程中可能對我們有用的鏈接。

9. 結論

本文介紹了 RESTful API 建模語言 (RAML)。我們演示了使用 RAML 1.0 (RC) 規範編寫簡單 API 規範的基本語法。

我們還看到了通過使用語法快捷方式和將示例、數據類型和模式外部化到“include”文件來使定義更簡潔的方法。

然後,我們介紹了可以與 RAML 規範一起使用,以協助日常 API 設計、開發、測試和文檔任務的一系列強大工具。

隨着規範 1.0 正式發佈的計劃,以及開發者工具的支持,RAML 似乎已經確立了地位。

下一條 »
使用資源類型和特性消除 RAML 中的冗餘
user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.