Modular RAML Using Includes, Libraries, Overlays and Extensions – 使用包含物、库、覆盖物和扩展物的模块化RAML

最后修改: 2016年 2月 8日


1. Introduction


In our first two articles on RAML – the RESTful API Modeling Language – we introduced some basic syntax, including the use of data types and JSON schema, and we showed how to simplify a RAML definition by extracting common patterns into resource types and traits.

在我们的第一篇两篇关于RAML(RESTful API建模语言)的文章中,我们介绍了一些基本语法。我们介绍了一些基本语法,包括数据类型和JSON模式的使用,并展示了如何通过将常见模式提取为资源类型属性来简化RAML定义。

In this article, we show how you can break your RAML API definition into modules by making use of includes, libraries, overlays, and extensions.

在这篇文章中,我们展示了如何通过利用includeslibrariesoverlaysextensions,将RAML API定义分解成模块

2. Our API


For the purpose of this article, we shall focus on the portion of our API involving the entity type called Foo.


Here are the resources making up our API:


  • GET /api/v1/foos
  • POST /api/v1/foos
  • GET /api/v1/foos/{fooId}
  • PUT /api/v1/foos/{fooId}
  • DELETE /api/v1/foos/{fooId}

3. Includes


The purpose of an include is to modularize a complex property value in a RAML definition by placing the property value in an external file.


Our first article touched briefly on the use of includes when we were specifying data types and examples whose properties were being repeated inline throughout the API.


3.1. General Usage and Syntax


The !include tag takes a single argument: the location of the external file containing the property value. This location may be an absolute URL, a path relative to the root RAML file, or a path relative to the including file.

! include标签需要一个参数:包含属性值的外部文件的位置。这个位置可以是一个绝对的URL,一个相对于RAML根文件的路径,或者一个相对于包含文件的路径。

A location starting with a forward slash (/) indicates a path relative to the location of the root RAML file, and a location beginning without a slash is interpreted to be relative to the location of the including file.


The logical corollary to the latter is that an included file may itself contain other !include directives.


Here is an example showing all three uses of the !include tag:


#%RAML 1.0
title: Baeldung Foo REST Services API
types: !include /types/allDataTypes.raml
resourceTypes: !include allResourceTypes.raml
traits: !include

3.2. Typed Fragments


Rather than placing all the types, resource types or traits in their own respective include files, you can also use special types of includes known as typed fragments to break each of these constructs into multiple include files, specifying a different file for each type, resource type or trait.

而不是将所有的类型资源类型特质放在他们各自的include文件中。你也可以使用特殊类型的include,称为typed fragments,将这些结构分成多个include文件,为每个typeresource typetrait指定一个不同文件。

You can also use typed fragments to define user documentation items, named examples, annotations, libraries, overlays, and extensions. We will cover the use of overlays and extensions later in the article.


Although it is not required, the first line of an include file that is a typed fragment may be a RAML fragment identifier of the following format:


#%RAML 1.0 <fragment-type>

For example, the first line of a typed fragment file for a trait would be:

例如,一个typed fragment文件的第一行将是trait的。

#%RAML 1.0 Trait

If a fragment identifier is used, then the contents of the file MUST contain only valid RAML for the type of fragment being specified.


Let’s look first at a portion of the traits section of our API:


  - hasRequestItem:
          type: <<typeName>>
  - hasResponseItem:
                type: <<typeName>>
                example: !include examples/<<typeName>>.json

In order to modularize this section using typed fragments, we first rewrite the traits section as follows:


  - hasRequestItem: !include traits/hasRequestItem.raml
  - hasResponseItem: !include traits/hasResponseItem.raml

We would then write the typed fragment file hasRequestItem.raml:


#%RAML 1.0 Trait
    type: <<typeName>>

The typed fragment file hasResponseItem.raml would look like this:

typed fragment文件hasResponseItem.raml将看起来像这样。

#%RAML 1.0 Trait
          type: <<typeName>>
          example: !include /examples/<<typeName>>.json

4. Libraries


RAML libraries may be used to modularize any number and combination of data types, security schemes, resource types, traits, and annotations.

RAML 可用于模块化任何数量和组合的数据类型安全方案资源类型traits注释

4.1. Defining a Library


Although usually defined in an external file, which is then referenced as an include, a library may also be defined inline. A library contained in an external file can reference other libraries as well.


Unlike a regular include or typed fragment, a library contained in an external file must declare the top-level element names that are being defined.

与普通的includetyped fragment不同,包含在外部文件中的library必须声明正在定义的顶级元素名称。

Let’s rewrite our traits section as a library file:


#%RAML 1.0 Library
# This is the file /libraries/traits.raml
usage: This library defines some basic traits
    usage: Use this trait for resources whose request body is a single item
        type: <<typeName>>
    usage: Use this trait for resources whose response body is a single item
              type: <<typeName>>
              example: !include /examples/<<typeName>>.json

4.2. Applying a Library


Libraries are applied via the top-level uses property, the value of which is one or more objects whose property names are the library names and whose property values make up the contents of the libraries.


Once we have created the libraries for our security schemes, data types, resource types, and traits, we can apply the libraries to the root RAML file:


#%RAML 1.0
title: Baeldung Foo REST Services API
  mySecuritySchemes: !include libraries/security.raml
  myDataTypes: !include libraries/dataTypes.raml
  myResourceTypes: !include libraries/resourceTypes.raml
  myTraits: !include libraries/traits.raml

4.3. Referencing a Library


A library is referenced by concatenating the library name, a dot (.), and the name of the element (e.g. data type, resource type, trait, etc) being referenced.


You may recall from our previous article how we refactored our resource types using the traits that we had defined. The following example shows how to rewrite our “item” resource type as a library, how to include the traits library file (shown above) within the new library, and how to reference the traits by prefixing the trait names with their library name qualifier (“myTraits“):

您可能还记得我们之前的文章中,我们如何使用我们定义的traits重构我们的resource types。下面的示例展示了如何将我们的 “项目”资源类型重写为库,如何将traits文件(如上所示)包含在新的中。以及如何通过在traits名称前加上library名称限定符(”myTraits“)来引用traits

#%RAML 1.0 Library
# This is the file /libraries/resourceTypes.raml
usage: This library defines the resource types for the API
  myTraits: !include traits.raml
    usage: Use this resourceType to represent any single item
    description: A single <<typeName>>
      description: Get a <<typeName>> by <<resourcePathName>>
      is: [ myTraits.hasResponseItem, myTraits.hasNotFound ]
      description: Update a <<typeName>> by <<resourcePathName>>
      is: [ myTraits.hasRequestItem, myTraits.hasResponseItem, myTraits.hasNotFound ]
      description: Delete a <<typeName>> by <<resourcePathName>>
      is: [ myTraits.hasNotFound ]

5. Overlays and Extensions


Overlays and extensions are modules defined in external files that are used to extend an API. An overlay is used to extend non-behavioral aspects of an API, such as descriptions, usage directions, and user documentation items, whereas an extension is used to extend or override behavioral aspects of the API.


Unlike includes, which are referenced by other RAML files to be applied as if they were being coded inline, all overlay and extension files must contain a reference (via the top-level masterRef property) to its master file, which can be either a valid RAML API definition or another overlay or extension file, to which they are to be applied.

includes不同,includes被其他RAML文件引用来应用,就像它们被内联编码一样,所有的overlayextension文件必须包含对其主文件的引用(通过顶层的masterRef属性),该文件可以是一个有效的RAML API定义,或另一个overlayextension文件,它们将被应用到其中。

5.1. Definition


The first line of an overlay or extension file must be formatted as follows:


RAML 1.0 Overlay

And the first line of an overlay file must be formatted similarly:


RAML 1.0 Extension

5.2. Usage Constraints


When using a set of overlays and/or extensions, all of them must refer to the same master RAML file. In addition, RAML processing tools usually expect the root RAML file and all overlay and extension files to have a common file extension (e.g. “.raml”).


5.3. Use Cases for Overlays


The motivation behind overlays is to provide a mechanism for separating interface from implementation, thus allowing the more human-oriented parts of a RAML definition to change or grow more frequently, while the core behavioral aspects of the API remain stable.


A common use case for overlays is to provide user documentation and other descriptive elements in multiple languages. Let’s rewrite the title of our API and add some user documentation items:


#%RAML 1.0
title: API for REST Services used in the RAML tutorials on
  - title: Overview
  - content: |
      This document defines the interface for the REST services
      used in the popular RAML Tutorial series at
  - title: Copyright
  - content: Copyright 2016 by All rights reserved.

Here is how we would define a Spanish language overlay for this section:


#%RAML 1.0 Overlay
# File located at (archivo situado en):
# /overlays/es_ES/documentationItems.raml
masterRef: /api.raml
usage: |
  To provide user documentation and other descriptive text in Spanish
  (Para proporcionar la documentación del usuario y otro texto descriptivo
  en español)
title: |
  API para servicios REST utilizados en los tutoriales RAML
  - title: Descripción general
  - content: |
      Este documento define la interfaz para los servicios REST
      utilizados en la popular serie de RAML Tutorial en
  - title: Derechos de autor
  - content: |
      Derechos de autor 2016 por
      Todos los derechos reservados.

Another common use case for overlays is to externalize annotation metadata, which essentially are a way of adding non-standard constructs to an API in order to provide hooks for RAML processors such as testing and monitoring tools.


5.4. Use Cases for Extensions


As you may infer from the name, extensions are used to extend an API by adding new behaviors and/or modifying existing behaviors of an API. An analogy from the object-oriented programming world would be a subclass extending a superclass, where the subclass can add new methods and/or override existing methods. An extension may also extend an API’s non-functional aspects.


An extension might be used, for example, to define additional resources that are exposed only to a select set of users, such as administrators or users having been assigned a particular role. An extension could also be used to add features for a newer version of an API.


Below is an extension that overrides the version of our API and adds resources that were unavailable in the previous version:


#%RAML 1.0 Extension
# File located at:
# /extensions/en_US/additionalResources.raml
masterRef: /api.raml
usage: This extension defines additional resources for version 2 of the API.
version: v2
      description: |
        Get the foo that is related to the bar having barId = {barId}
      typeName: Foo
        barId?: integer
        typeName: Foo
        is: [ hasResponseItem ]

And here is a Spanish-language overlay for that extension:


#%RAML 1.0 Overlay
# Archivo situado en:
# /overlays/es_ES/additionalResources.raml
masterRef: /api.raml
usage: |
  Se trata de un español demasiado que describe los recursos adicionales
  para la versión 2 del API.
version: v2
      description: |
        Obtener el foo que se relaciona con el bar tomando barId = {barId}

It is worth noting here that although we used an overlay for the Spanish-language overrides in this example because it does not modify any behaviors of the API, we could just as easily have defined this module to be an extension. And it may be more appropriately defined as an extension, given that its purpose is to override properties found in the English-language extension above it.


6. Conclusion


In this tutorial, we have introduced several techniques to make a RAML API definition more modular by separating common constructs into external files.

在本教程中,我们介绍了几种技术,通过将常见的构造分离到外部文件中,使RAML API定义更加模块化。

First, we showed how the include feature in RAML can be used to refactor individual, complex property values into reusable external file modules known as typed fragments. Next, we demonstrated a way of using the include feature to externalize certain sets of elements into reusable libraries. Finally, we extended some behavioral and non-behavioral aspects of an API through the use of overlays and extensions.

首先,我们展示了RAML中的include特性如何被用来重构单个复杂的属性值,使之成为可重用的外部文件模块,即typed fragments。接下来,我们展示了一种使用include功能的方法,将某些元素集外化为可重用的libraries。最后,我们通过使用overlaysextensions来扩展API的一些行为和非行为方面。

To learn even more about RAML modularization techniques, please visit the RAML 1.0 spec.

要了解有关RAML模块化技术的更多信息,请访问RAML 1.0规范

You can view the full implementation of the API definition used for this tutorial in the github project.


Next »

Define Custom RAML Properties Using Annotations

« Previous

Eliminate Redundancies in RAML with Resource Types and Traits