Open Credo

November 25, 2015 | Microservices

RAML 1.0 promotes reusability and standardisation

In May a 1.0 release of RAML (RESTful API Markup Language) has been announced delivering a few much welcome additions in the RAML 1.0 specification. This major release marks an important milestone in the evolution of RAML and indicates the team behind the specification is confident this release delivers the comprehensive set of tools for developing RESTful APIs. I’ve been using RAML 0.8 for several months now and have enjoyed the simplicity and productivity it offers for designing and documenting APIs. I must say I’m quite pleased with the changes introduced in the new release and would like to review those I consider particularly useful.

WRITTEN BY

Rafal Gancarz

Rafal Gancarz

RAML 1.0 promotes reusability and standardisation

Update: This blog post was originally published after RAML 1.0 RC1 has been released. Subsequently, RC2 of RAML 1.0 specification has been released in early May 2016, bringing quite a few changes compared to RC1. RC2 turned out to be the final RC and RAML 1.0 GA version of the specification was announced mid May. This blog post has now been updated to be in line with GA version of RAML 1.0.

RAML 1.0 released

A bit about RAML

RAML is a YAML 1.2 based language that can be used to document RESTful web service APIs and is intended to be used with design-first (or contract-first) approach towards API development compared to Swagger that is largely considered to be more suited for code driven (contract last) approach, where API documentation is generated based on annotated source code. This is perhaps attributed more to the tooling and established practices rather than any other reason – Swagger can be used for design-first API development too, especially since version 2.0 introduced YAML format support which made working with Swagger API specs somewhat easier.

An excellent post Documenting REST APIs – a tooling review by my fellow OC consultant Stephen Judd provides a comparison between a number of API documentation tools, including RAML, Swagger among others.

RAML native data types

Definitely the most substantial new capability that RAML 1.0 provides is the native support for defining data types. API authors will no longer need to embed or reference XML or JSON schema documents in RAML API specifications (although they still can). Frankly, I was never too keen on using XML or even JSON schema to define data types. Somehow the idea of mixing up different markup languages seems awkward and counterproductive so I quite often preferred to provide examples of JSON messages expected in the request or the response. Now I can’t really use this an excuse and perhaps will need to be more disciplined about defining data types from the outset, which will definitely reduce the the level of duplication and allow using API specifications for validating and stubbing. There is a place for examples in API specs of course but maybe not as a replacement for defining data types properly.

RAML data type definitions allow the same degree of flexibility as XML or JSON schema but certainly without the overhead and context switching between different markup languages. The example below illustrates pretty well how data types can be defined using RAML 1.0, including a few syntactic sugars that would make the markup more concise.

#%RAML 1.0 
title: My API with Types
mediaType: application/json
types: # global declaration for data types
  Person:
    type: object # type that doesn't extend anything
    properties:
      firstname: string
      lastname:  string
      title?:    string # a syntax sugar for optional properties
  Phone:
    pattern: ^[0-9()-]+$ # specialised type extending string
  Manager:
    type: Person # a type extending another one
    properties:
      reports: Person[] # a collection of elements
      phone:  Phone
  Admin:
    type: Person
    properties:
      clearanceLevel:
        enum: [ low, high ] # a enum property with predefined list of values
  AlertableAdmin:
    type: Admin
    properties:
      phone: Phone
  Alertable: Manager | AlertableAdmin # union type combining two types

Data types defined in the API specification can be used in message bodies, URI parameters, headers and query parameters.

/admins/{adminId}:
  get:
    responses:
      200:
        body:
          application/json:
            type: Admin

Enhanced examples

RAML 1.0 allows providing multiple examples for valid type objects, which can be expressed in YAML format.

#%RAML 1.0 
title: My API with Types
mediaType: application/json
types:
  Person:
    type: object
    properties:
      firstname: string
      lastname:  string
      title?:    string
    examples:
      with_title:
        firstname: Rafal
        lastname: Gancarz
        title: Mr
      without_title:
        firstname: Rafal
        lastname: Gancarz

RAML 1.0 annotations

Annotations in RAML 1.0 provide the mechanism to extend the specification with additional metadata that is not included in the standard RAML spec. Any annotations used in the API specification document need to be declared upfront in a global annotationTypes attribute. Annotations may be completely ignored by RAML processors that don’t understand them as they are not aimed to alter the core API specification. They can however be used to supplement the API specification with additional metadata used for specific purposes like documentation enhancements, testing, monitoring, etc.

#%RAML 1.0
title: Illustrating annotations
mediaType: application/json
annotationTypes:
  deprecated: null
  experimental: null | string
  feedbackRequested: string?
  testHarness:
    type: string # This line can be omitted as it's the default type
  badge:         # This annotation type allows string values, too
  clearanceLevel:
    properties:
      level:
        enum: [ low, medium, high ]
        required: true
      signature:
        pattern: "\\d{3}-\\w{12}"
        required: true
/groups:
  (experimental):
  (feedbackRequested):
/users:
  (testHarness): usersTest
  (badge): tested.gif
  (clearanceLevel):
    level: high
    signature: 230-ghtwvfrs1itr
  get:
    (deprecated):
    (experimental):
    (feedbackRequested): Feedback committed!
    responses:
      200:

Libraries

RAML 1.0 specification provides a wide range of mechanisms supporting modularisation and reuse of API specification elements. RAML libraries are the main way to package up reusable modules bringing together data types, resource types, traits, security schemes and annotations types. By externalising commonly used API specification elements it becomes less of a challenge to manage and standardise large portfolios of REST APIs.

#%RAML 1.0 Library
# This file is located at libraries/files.raml
usage: |
  Use to define some basic file-related constructs.
types:
  File:
    properties:
      name:
      length:
        type: integer
traits:
  drm:
    headers:
      drm-key:
resourceTypes:
  file:
    get:
      is: [ drm ]
      responses:
        201:
          body:
            application/json:
              type: file-type.File
    put:
      is: [ drm ]

Once the library is defined in a separate library specification file with #%RAML 1.0 Library header indicating it’s a RAML library spec, it can be used in an API specification or another RAML fragment, for instance a one declaring resource types (note #%RAML 1.0 ResourceType header).

#%RAML 1.0 ResourceType 
# This file is located at files-resource.raml 
uses:
  files: !include libraries/files.raml
get:
  is: files.drm
  responses:
    200:
      body:
        application/json:
          type: files.file-type.File
#%RAML 1.0 
title: Files API
uses:
  files: !include libraries/files.raml
resourceTypes:
  file: !include files-resource.raml
/files:
  type: file

RAML libraries utilise and extend the existing set of RAML includes and provide ways to organise various types of RAML elements into cohesive, reusable modules.

Overlays and extensions

The last new feature introduced in RAML 1.0 I want to cover allows to override or add properties of RAML API definition. The purpose of these two customisation mechanisms is mostly to augment or supplement a specific RAML document  and the target document needs to be explicitly specified using extends property. Although overlays and extensions are somewhat similar there is a crucial difference between these two customisation types – overlays are not allowed to change any of the functional aspects of the target RAML document they customise (like resources, methods, parameters, bodies, responses, etc.) whereas extensions can introduce functional changes to the API specification.

The main use cases for RAML overlays are to provide ways to adapt RAML documents to different audiences or add additional content that can be used by API tooling (for testing, monitoring, discovery, etc.). The key is to separate the core functional part of the API specification that is relevant to the API clients from any maintenance/documentation aspects that may be changed at a different pace (most likely more frequently) than the API contract itself. The example below demonstrates how an overlay can be used to provide the Spanish translation for the API documentation.

#%RAML 1.0 
# This file is located at librarybooks.raml 
title: Book Library API
documentation:
  - title: Introduction
    content: Automated access to books
  - title: Licensing
    content: Please respect copyrights on our books.
/books:
  description: The collection of library books
  get:
#%RAML 1.0 Overlay 
usage: Spanish localization
extends: librarybooks.raml
documentation:
  - title: Introducción
    content: El acceso automatizado a los libros
  - title: Licencias
    content: Por favor respeta los derechos de autor de los libros
/books:
  description: La colección de libros de la biblioteca

RAML extensions, unlike overlays, can modify the functional elements of the RAML API specification they are referring to. Some use cases for using extensions may include creating API specification variants targeted at different user roles or integration models as well as specifying some deployment specific properties that should not be the part of the functional API contract. The example below shows how an extension can be used for specifying the base URI of the API.

#%RAML 1.0 Extension 
usage: The location of the public instance of the Piedmont library API
extends: librarybooks.raml
baseUri: http://api.piedmont-library.com

RAML 1.0 tooling

The new version of RAML specification was announced with the immediate availability of parser libraries for Javascript and Java. Both of these parsers can work with new RAML 1.0 version as well as old 0.8 version. As the most open-source and commercial tools still need to release support for RAML 1.0 specification, the RAML workgroup has been working on the authoring tool for new RAML version alongside the work to finalise the spec itself. The result of this effort is a plugin for Atom IDE called APIWorkbench that for the time being I would consider the best authoring tool for RAML 1.0 documents if you care about realtime validation, autocompletion and type hints (RAML being a YAML based format is easy enough to be used in any text editor of course). No doubt other editors and IDEs will over time offer RAML 1.0 support.

Of course there is still some way to go on the tooling side of the RAML ecosystem as very few tools support RAML 1.0 and I would say overall the tooling needs to improve to take full advantage of the RAML spec (especially the latest additions on RAML 1.0, like annotations and overlays that have been introduced to be used specifically by the API related tooling). I’ve been using raml2html with RAML 0.8 for a while as means of generating user-friendly API documentation and now with RAML 1.0 (which I want to use mostly for much better native data type definition support) I’ve lost the ability to generate HTML documentation. APIWorkbench helps a lot but I would rather use tools to generate API documentation in HTML. In fact I believe it’s the tooling that will decide if RAML will be able to compete with Swagger or other API definition formats for the supremacy in this area.

Update: Since publishing my original blog post, couple more tools have started supporting RAML 1.0. Most notably MuleSoft’s API Designer (part of AnyPoint platform) now seems to be able to handle RAML 1.0 API specifications. For those, looking for a replacement for raml2html tool (mentioned above), there is ramlo API documentation generator which also supports 1.0 version.

Final thoughts

I consider RAML 1.0 a major milestone in the evolution of RAML specification and certainly appreciate the effort that went into developing this specification. Compared to 0.8 version it provides a mature and comprehensive specification format with a lot of use cases addressed in the core spec and built-in extensibility mechanisms for anything unforeseen by the creators of the spec.

In principle, I believe that contract first API design is (and has always been) the superior approach for any external (third-party) API development and RAML 1.0 offers a rich and easy to use API definition language that promotes reusability and modularisation. In that regard, RAML 1.0 seems to have an upper hand over its competitors, so if the tooling support improves over the next few months, I hope to be using RAML 1.0 for some time to come.

Update: Unfortunately, the tooling hasn’t been able to keep up with the changes to RAML specification quickly enough and I didn’t have a choice but to switch over to using Swagger 2.0 in YAML format. I would have preferred to use RAML 1.0 for its concise syntax and superior support for reusability and modularisation but the lack of decent and freely available tooling made it impossible to produce API specifications that could be easily shared and explored, both internally and externally. Time will tell if I will be able to move back to using RAML 1.0.

 

This blog is written exclusively by the OpenCredo team. We do not accept external contributions.

RETURN TO BLOG

SHARE

Twitter LinkedIn Facebook Email

SIMILAR POSTS

Blog