Introduction to RAML – The RESTful API Modeling Language – RAML – RESTful API建模语言简介

最后修改: 2015年 12月 5日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this article, we introduce the RESTful API Modeling Language (RAML), a vendor-neutral, open-specification language built on YAML 1.2 and JSON for describing RESTful APIs.

在本文中,我们介绍了RESTful API Modeling Language (RAML),这是一种厂商中立的、开放的规范化语言,建立在YAML 1.2和JSON之上,用于描述RESTful APIs。

We’ll cover basic RAML 1.0 syntax and file structure as we demonstrate how to define a simple JSON-based API. We’ll also show how to simplify RAML file maintenance through the use of includes. And if you have legacy APIs that use JSON schema, we’ll show how to incorporate schemas into RAML.

我们将涵盖基本的RAML 1.0语法和文件结构,同时演示如何定义一个简单的基于JSON的API。我们还将展示如何通过使用includes来简化RAML文件维护。如果你有使用JSON模式的遗留API,我们将展示如何将模式纳入RAML中。

Then we’ll introduce a handful of tools that can enhance your journey into RAML, including authoring tools, documentation generators, and others.

然后,我们将介绍一些可以增强你的RAML之旅的工具,包括编写工具、文档生成器和其他工具。

Finally, we’ll wrap up by describing the current state of the RAML specification.

最后,我们将通过描述RAML规范的当前状态来进行总结。

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

2.定义你的API(创建.raml文件)

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:

我们将定义的API相当简单:给定实体类型Foo,定义基本的CRUD操作和几个查询操作。下面是我们将为我们的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).

让我们将我们的API定义为无状态,使用HTTP Basic认证,并通过HTTPS加密交付。最后,让我们选择JSON作为我们的数据传输格式(XML也被支持)。

2.1. Root-Level Settings

2.1.根级别的设置

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:

我们首先创建一个简单的文本文件,命名为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

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

注意在第3行,在”version“周围使用了大括号{ }。这就是我们告诉RAML”version”指的是一个属性,并且要被展开。因此,实际的baseUri将是。http://myapi.mysite.com/v1

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

[注意:version属性是可选的,不需要成为baseUri的一部分。]

2.2. Security

2.2.安全性

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

安全性也是在.raml文件的根层定义的。因此,让我们添加我们的HTTP基本安全方案定义。

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

2.3.数据类型

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

接下来,我们将定义我们的API将使用的数据类型。

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:

上面的例子使用扩展语法来定义我们的数据类型。RAML提供了一些语法上的快捷方式,使我们的类型定义不那么冗长。下面是使用这些快捷方式的等效数据类型部分。

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

2.4.资源

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

现在,我们将定义我们的API的顶级资源(URI)。

/foos:

2.5. URI Parameters

2.5 URI参数

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

这里,属性名称周围的大括号{ }定义了URI参数。它们代表每个URI中的占位符,并不像我们在上面的baseUri声明中看到的那样引用根级RAML文件属性。添加的行代表资源/foos/{id}/foos/name/{name}

2.6. Methods

2.6.方法

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

下一步是定义适用于每个资源的HTTP方法。

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

2.7. Query Parameters

2.7.查询参数[/strong]

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集合的方法。请注意,查询参数的定义与我们上面对数据类型使用的语法相同。

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

2.8. Responses

2.8.反应

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.

现在我们已经为我们的API定义了所有的资源,包括URI参数、HTTP方法和查询参数,是时候定义预期的响应和状态码了。响应格式通常是关于数据类型和例子的定义。

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.

为了向后兼容早期版本的RAML,可以使用JSON模式代替数据类型。我们将在第3节介绍JSON模式。

[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 operation on /foos/{id}:

让我们从对/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" }

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.

这个例子显示,通过对资源/foos/{id}执行GET请求,我们应该得到匹配的Foo,其形式为JSON对象和HTTP状态代码200。

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

下面是我们如何定义对/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" }
              ]

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.

注意在Foo类型上附加的方括号[]的使用。这展示了我们如何定义一个包含Foo对象数组的响应体,例子是一个JSON对象的数组。

2.9. Request Body

2.9.请求主体

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

接下来,我们将定义对应于每个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. Status Codes

2.10.状态代码

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.

注意在上面的例子中,当创建一个新的对象时,我们返回的HTTP状态是201。更新一个对象的PUT操作将返回HTTP状态200,利用与POST操作相同的请求和响应体。

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 the /foos/{id} resource when no resource is found with the given id:

让我们看看当没有找到给定id的资源时,我们将如何定义对/foos/{id}资源的GET请求的预期响应。

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

3. RAML With JSON Schema

3.带有JSON模式的RAML

Before data types were introduced in RAML 1.0, objects, request bodies, and response bodies were defined using JSON Schema.

在RAML 1.0中引入数据类型之前,对象、请求体和响应体是用JSON Schema定义的。

Using data types can be very powerful, but there are cases where you still want to use JSON Schema. In RAML 0.8 you defined your schemas using the root level schemas section.

使用数据类型可以非常强大,但在有些情况下你仍然想使用JSON模式。在RAML 0.8中,你使用根层的schemas部分定义你的模式。

That is still valid, but it is recommended to use the types section instead since the use of schemas may be deprecated in a future version. Both types and schemas, as well as type and schema, are synonymous.

这仍然有效,但建议使用types部分,因为schemas的使用可能在未来的版本中被废弃。typesschemas,以及typeschema,都是同义词。

Here is how you would define the Foo object type at the root level of the .raml file using JSON schema:

下面是你如何使用JSON模式在.raml文件的根层定义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" ]
    }

And here is how you would reference the schema in the GET /foos/{id} resource definition:

以下是你如何在GET /foos/{id}资源定义中引用该模式。

/foos:
  ...
  /{id}:
    get:
      description: Get a Foo by its id
      responses:
        200:
          body:
            application/json:
              type: foo
              ...

4. Refactoring With Includes

4.用包含物进行重构

As we can see from the above sections, our API is getting rather verbose and repetitive.

从上面几节可以看出,我们的API已经变得相当冗长和重复了。

The RAML specification provides an include mechanism that allows us to externalize repeated and lengthy sections of code.

RAML规范提供了一个包含机制,允许我们将重复和冗长的代码部分外部化。

We can refactor our API definition using includes, making it more concise and less likely to contain the types of errors that result from the “copy/paste/fix everywhere” methodology.

我们可以使用 “包含 “来重构我们的API定义,使其更加简洁,并且不太可能包含 “复制/粘贴/到处修补 “方法所导致的错误类型。

For example, we can put the data type for a Foo object in the file types/Foo.raml and the type for an Error object in types/Error.raml. Then our types section would look like this:

例如,我们可以把Foo对象的数据类型放在types/Foo.raml文件中,把Error对象的类型放在types/Error.raml中。那么我们的types部分将看起来像这样。

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

And if we use JSON schema instead, our types section might look like this:

而如果我们使用JSON模式,我们的types部分可能看起来像这样。

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

5. Completing the API

5.完成API

After externalizing all of the data types and examples to their files, we can refactor our API using the include facility:

在将所有的数据类型和例子外部化到它们的文件中后,我们可以使用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 Tools

6.RAML工具

One of the great things about RAML is the tool support.

RAML的好处之一是对工具的支持。

There are tools for parsing, validating, and authoring RAML APIs; tools for client code generation; tools for generating API documentation in HTML and PDF formats; and tools that assist us with testing against a RAML API specification.

有用于解析、验证和编写RAML API的工具;用于客户端代码生成的工具;用于生成HTML和PDF格式的API文档的工具;以及帮助我们针对RAML API规范进行测试的工具。

There is even a tool that will convert a Swagger JSON API into RAML.

甚至有一个工具可以将Swagger JSON API转换为RAML。

Here is a sampling of available tools:

以下是现有工具的一个样本。

  • API Designer – a web-based tool geared towards rapid and efficient API design
  • API Workbench – an IDE for designing, building, testing, and documenting RESTful APIs that supports both RAML 0.8 and 1.0
  • RAML Cop – a tool for validating RAML files
  • RAML for JAX-RS – a set of tools for generating a skeleton of Java + JAX-RS application code from a RAML spec, or for generating a RAML spec from an existing JAX-RS application
  • RAML Sublime Plugin – a syntax highlighter plugin for the Sublime text editor
  • RAML to HTML – a tool for generating HTML documentation from RAML
  • raml2pdf – a tool for generating PDF documentation from RAML
  • RAML2Wiki – a tool for generating Wiki documentation (using Confluence/JIRA markup)
  • SoapUI RAML Plugin – a RAML plugin for the popular SoapUI functional API testing suite
  • Vigia – an integration test suite capable of generating test cases based on a RAML definition

For a complete listing of RAML tools and related projects, visit the RAML Projects page.

有关RAML工具和相关项目的完整清单,请访问RAML项目页面。

7. The Current State of RAML

7.RAML的现状

The RAML 1.0 (RC) specification gained release-candidate status on November 3, 2015, and at the time of this writing, version 1.0 was expected to be finalized within the month.

2015年11月3日,RAML 1.0(RC)规范获得了发布候选状态,在撰写本文时,1.0版本预计将在本月内完成。

Its predecessor, RAML 0.8 was originally released in the Fall of 2014 and is still supported by a myriad of tools.

它的前身RAML 0.8最初是在2014年秋季发布的,现在仍然被无数的工具所支持。

8. Further Reading

8.进一步阅读

Here are some links that we may find useful along our journey with RAML.

以下是我们在使用RAML的过程中可能发现的一些有用的链接。

9. Conclusion

9.结论

This article introduced the RESTful API Modeling Language (RAML). We demonstrated some basic syntax for writing a simple API specification using the RAML 1.0 (RC) spec.

本文介绍了RESTful API建模语言(RAML)。我们演示了使用RAML 1.0(RC)规范编写简单API规范的一些基本语法。

And we saw ways to make our definitions more concise by using syntactical shortcuts and externalizing examples, data types, and schemas into ‘include’ files.

我们还看到了通过使用语法捷径和将例子、数据类型和模式外化到’include’文件来使我们的定义更加简洁的方法。

Then we introduced a collection of powerful tools that work with the RAML spec to assist with everyday API design, development, testing, and documentation tasks.

然后,我们介绍了一系列强大的工具,它们与RAML规范一起工作,协助日常的API设计、开发、测试和文档工作。

With the upcoming official release of version 1.0 of the spec, coupled with the overwhelming support of tools developers, it looks like RAML is here to stay.

随着1.0版规范的即将正式发布,再加上工具开发者的压倒性支持,看起来RAML将继续存在。

Next »

Eliminate Redundancies in RAML with Resource Types and Traits