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.
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.
title: My API with Types
types: # global declaration for data types
type: object # type that doesn't extend anything
title?: string # a syntax sugar for optional properties
pattern: ^[0-9()-]+$ # specialised type extending string
type: Person # a type extending another one
reports: Person # a collection of elements
enum: [ low, high ] # a enum property with predefined list of values
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.
RAML 1.0 allows providing multiple examples for valid type objects, which can be expressed in YAML format.
title: My API with Types
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.
title: Illustrating annotations
experimental: null | string
type: string # This line can be omitted as it's the default type
badge: # This annotation type allows string values, too
enum: [ low, medium, high ]
(feedbackRequested): Feedback committed!
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
Use to define some basic file-related constructs.
is: [ drm ]
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
files: !include libraries/files.raml
title: Files API
files: !include libraries/files.raml
file: !include files-resource.raml
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.
# This file is located at librarybooks.raml
title: Book Library API
- title: Introduction
content: Automated access to books
- title: Licensing
content: Please respect copyrights on our books.
description: The collection of library books
#%RAML 1.0 Overlay
usage: Spanish localization
- title: Introducción
content: El acceso automatizado a los libros
- title: Licencias
content: Por favor respeta los derechos de autor de los libros
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
RAML 1.0 tooling
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.
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.