RAML, the RESTful API Modeling Language

Share this article

In a recent article I introduced Slate, a static site generator specifically designed for writing API documentation. This time around, I’m going to look at something which in many ways is even better.

But first, if you’ll indulge me for just a moment, I’d like to begin by quoting myself from that article;

[an] API is only as good as its documentation

I think it’s worth repeating, since it’s all-too-frequently overlooked, and it’s one of the motivations for this short series of articles on some of the tools out there to help you write great documentation.

Slate is a useful tool, but despite the relatively rigid structure of the pages themselves, the actual documentation is pretty freeform.

RAML (RESTful API Modeling Language) provides a structured, unambiguous format for describing a RESTful API. It allows you to describe your API; the endpoints, the HTTP methods to be used for each one, any parameters and their format, what you can expect by way of a response and more.

You can use RAML in a number of ways;

  • It can be used in the design and specification stage to describe the API you plan to build
  • You can use RAML to generate documentation
  • RAML can be used to implement interactive API consoles
  • You can test against RAML
  • It be used to generate mock API responses

In this article I’ll primarily look at generating documentation; in a later article I’ll look at how you can integrate RAML into your API testing. But first, let’s look at how to write a RAML document.

Writing RAML

The first thing to note is that RAML is a derivative of YAML. You’ll find it easier to work with RAML if you’ve written YAML before, but if you haven’t then it’s relatively straightforward, or there’s a tutorial here on Sitepoint.

Because they’re simply text files, you can of course use any text editor or IDE to create and edit them. However, a better option is to use the Anypoint platform. It provides an API editor, which allows you to edit RAML files with auto-completion, validation as-you-type and an interactive preview of some generated, interactive documentation (we’ll see how to generate that ourselves later).

To use Anypoint, you’ll first need to sign up – which is free – then add an API, then click “Define an API in API Designer”.

If you’d rather use Sublime, there’s a plugin you can use. It’s available via Package Control; simply do a search for “RAML Syntax Highlighter”.

Let’s look at the structure of a RAML file.

Basic Information

A RAML file starts with a declaration, indicating the format:

#%RAML 0.8

Typically you’d then provide some meta-information about your API, for example:

title: My Example API
version: v1

title is a required field; version is optional

You should then provide the Base URI for your API. At its simplest, it can be in the following format:

baseUri: http://api.acme.com/

You can also use URI parameters. For example it’s common practice to incorporate a version identifier into API URLs; if you’re taking that approach with yours, you can do this:

baseUri: http://api.acme.com/{version}/

We’ll look at URI parameters in more detail later on, since they become vital when describing resources. But should you need to, you can include additional parameters in your base URI. Amazon’s S3, for example, incorporates the name of the bucket you’re working with into the base URI.

You can also indicate whether your API is available over HTTPS by setting the protocols field, for example:

protocols: [ HTTP, HTTPS ]

You can specify the default media type which your API will return, for example:

mediaType: application/json

Later when we look at responses, we’ll look at how you can describe multiple response media types, and what to expect from them.

You can also incorporate additional documentation – or pages – into your RAML file. For example:

documentation
	- title: Home
		content: |
			This example documentation forms part of a tutorial for a 
			[Sitepoint](https://www.sitepoint.com/) article.

Notice how you can include Markdown in your meta-information.

There are some other things you can include here, such as how security is implemented, as well as defining traits. We’ll look at these concepts a little later.

That’s much of the basic information covered, so now let’s move onto resources.

Describing Resources

Continuing at the top level of your RAML file, the next step is to outline the available resources. Here’s an example:

/albums:
	displayName: Album
/artists:
	displayName: Artist

The displayName property is optional, but can help describe what the resources represent “in real life”.

Here we’ve defined two top-level resources, (musical) albums and resources. What we haven’t yet done is described the HTTP methods which can be used to interact with them, but first let’s drill down a little and look at resource URIs and sub-resources.

Let’s suppose specific albums are represented by their ISRC (International Standard Recording Code); so let’s expand our /albums resource to describe this:

/albums:
	/{isrc}:
		uriParameters: 
      isrc:
        description: The International Standard Recording Code which uniquely identifies this album
		type: string
		pattern: ^[a-zA-Z]{2}\-[0-9a-zA-Z]{3}\-\d{2}\-\d{5}$

As you can see, URI parameters are denoted by curly brackets. The uriParameters property can be used to provide additional information about these parameters, both meta-information (in this case, a description) as well as a concrete definition of their format – in this example, the data type and a regular expression which defines the specific format.

Using nesting, we can describe sub-resources. For example, suppose we provide an endpoint to retrieve an individual album’s tracklisting:

/albums:
	/{isrc}:
		uriParameters: 
      isrc:
        description: The International Standard Recording Code which uniquely identifies this album
		type: string
		pattern: ^[a-zA-Z]{2}\-[0-9a-zA-Z]{3}\-\d{2}\-\d{5}$
		/tracks:
			displayName: Tracklisting

You can have as much nesting of resources as you wish; just use YAML-style indentation.

Now let’s move onto defining the methods one can use on these resources.

HTTP Methods

Most REST_ful_ APIs tend to implement the four most common HTTP methods; GET for retrieval, PUT for updates, POST for creation and DELETE for, well, deleting resources. Our example API is no different. So, let’s modify our albums resource to reflect this:

/albums:
	get:
		description: Retrieve a list of albums
	post:
			description: Create a new album
	/{isrc}:
		uriParameters: 
      isrc:
        description: The International Standard Recording Code which uniquely identifies this album
		type: string
		pattern: ^[a-zA-Z]{2}\-[0-9a-zA-Z]{3}\-\d{2}\-\d{5}$
		get:
			description: Retrieve the specified album
		put:
			description: Update an album		
		delete:
			description: Delete this album

Here we’re indicating that a GET request to /albums will retrieve a list of albums, and a POST to the same URI is used to create one. Drilling-down, a GET request to /albums/{isrc} will retrieve information about a specific album, specified using the URI parameter isrc. a PUT request is used to update the album, a DELETE request to delete it.

Describing Responses

Now that we’ve defined our resources and the available methods, we need to be able to describe the responses a user can expect.

In order to demonstrate this, we’ll provide some additional detail about specific albums.

In order to describe responses, we need to drill down a few more levels. First, we need to describe the possible response codes, and thereafter we need to break down responses into their components – typically, the response body – and then the possible response media types. Here’s an example to make that a little clearer:

/albums:
	/{isrc}:		
		get:
			description: Retrieve the specified album
		responses:
       200:
         body:
           application/json:
             schema: |
               { 	"$schema": "http://json-schema.org/schema",
                 	"type": "object",
                 	"description": "An album",
                 	"properties": {                    
										"title": { "type": "string" },
										"artist": { "type": "string" },
										"label": { "type": "string" },
										"year": { "type": "integer" }
									},
									"required": [ "title", "artist" ]
                }
				example: |
                { "title": "Dubnobasswithmyheadman",
									"artist": "Underworld",
									"label": "Junior Boy's Own",
									"year": 1994
                }

Here we’re demonstrating a successful response – i.e., one with an HTTP response code of 200. What we’re interested in specifically is the response body, although you can also define any response headers here too. We then drill down into the available response types; in this case, we’re just representing JSON – though you’re free to define multiple response types if your API supports them.

Once we get down to a successful response’s body, we specify two properties; schema and example.

The schema property contains a JSON schema which defines the structure of the expected JSON. I’ll be covering JSON schema in another article very soon. The example property contains just that, making it clear what sort of response someone calling your API can expect.

Query Parameters

We can define query parameters (typically for GET requests) in a very similar manner in which we defined URI parameters.

To illustrate, let’s look again at our /albums endpoint, supposing that we wanted to implement pagination; so, we probably want to provide a query parameter named page which allows the requesting party to specify which page they want to retrieve.

Here’s how we might do that:

/albums:
  get:
    description: Retrieve a list of albums
    queryParameters:
      page:
        description: Specify the page that you want to retrieve
        type: integer
        example: 1

Again, the definition of the query parameter is a mixture of meta-information – such as the description and an example – and some properties which help explicitly define what the API expects; here we’re making it clear that the page parameter should be an integer.

Request Data

Let’s revisit our “Create an album” endpoint, which you’ll recall involves making a POST request to the /albums URI.

We can expand upon this by describing the data someone is required to include, the mechanism used to provide it, and some specifics about the various fields.

Here’s an example:

/albums:
	get:
		description: Retrieve a list of albums
	post:
		description: Create a new album
	body:
		application/x-www-form-urlencoded:
			formParameters:
				isrc:
					description: The International Standard Recording Code which uniquely identifies this album
					type: string
					pattern: ^[a-zA-Z]{2}\-[0-9a-zA-Z]{3}\-\d{2}\-\d{5}$
					required: true
				name:
					description: The name of the album
					type: string
					required: true
				artist:
					description: The name of the artist
					type: string
					required: true
				label:
					description: The label it was released under
					type: string
					required: false
				year:
					description: The year the album was released
					type: integer
					required: false
					minimum: 1900
					maximum: 3000

Here we’re defining the expected request body when POSTing to this endpoint. We’re indicating that the request should be of type application/x-www-form-urlencoded.

Next, we break down the expected request body into parameters with the formParameters property. Then we list the possible fields, provide some meta-data about each one, as well as the expected type. We can also indicate which fields are required and which are optional, as well as some validation rules – in this case we use a regular expression to dictate the format of the ISRC, and some relatively sensible boundaries for the year of release.

Security

Chances are your API is secured in some way – be it using OAuth, access tokens or simply just HTTP Basic Authentication.

In RAML you can define your security schemes towards the top of your file, alongside the basic information. You’ll find some examples in the specification document, but as an example let’s look at OAuth2. Here’s what the security scheme definition might look like:

securitySchemes:
  - oauth_2_0:
      description: |
        Acme uses OAuth2 to authenticate most requests
      type: OAuth 2.0
      describedBy:
        headers:
          Authorization:
            description: |
              Used to send a valid OAuth 2 access token. Do not use
              with the "access_token" query string parameter.
            type: string
        queryParameters:
          access_token:
            description: |
              Used to send a valid OAuth 2 access token. Do not use together with
              the "Authorization" header
            type: string
        responses:
					400:
            description: |
              Bad OAuth request (e.g. wrong consumer key, bad nonce, expired
              timestamp, etc.)
          401:
            description: |
              Bad or expired token. To fix it, re-authenticate the user.          
      settings:
        authorizationUri: https://acme.com/oauth/authorize
        accessTokenUri: https://acme.com/oauth/token
        authorizationGrants: [ code, token ]

If you look through this, you’ll see it provides a number of key pieces of information;

  • The type indicates that we’re implementing OAuth 2.0
  • To authenticate, the API in question expects either an Authorization header or an access_token query parameter
  • It lists the possible responses, what they mean and how to fix them
  • The settings are specific to OAuth but nonetheless vital; it tells users how to authorize, where to obtain an access token and the OAuth grant types this API supports.

However, this simply defines the security schemes; we still need to indicate that this is what we’re using to secure our API.

One way is to add the following towards the top of your RAML file:

securedBy: [oauth_2_0]

Note that oauth_2_0 matches the element immediately beneath securitySchemes

Some APIs, however, make some endpoints publicly available, but others may be protected. You can define the security approach on a per-endpoint basis, for example:

/albums:
	get:
		securedBy: [null, oauth_2_0]
	post:
		securedBy: [oauth_2_0]

Here we’re indicating that authentication is optional for retrieving a list of albums, but that a user must be authenticated in order to create one.

Traits

You’ll probably have certain behaviors, policies or characteristics which are common across different endpoints. A good example is pagination; various collections which support pagination will no doubt use the same approach, to keep the API consistent. Or, as we’ve seen in the Security section, you may have different degrees of security, such as public or “authorization required”.

Rather than repeat the same configuration across multiple endpoints, you can define traits. By-and-large, the concept is synonymous with traits in PHP.

Here’s a simple example of creating a trait to indicate that the results from a given endpoint support simple pagination:

traits:
  - paged:
      queryParameters:
		page:
			description: Specify the page that you want to retrieve
			type: integer
			required: true
			example: 1

Now you can apply this to an endpoint using the is property, like so:

/albums:  
  get:
    is: [ paged ]

You can also pass in variables. As an example, let’s extend our paged trait to include a number of results per page. We’ll specify a maximum number of results per page, which can be overridden on a per-endpoint basis. Here’s the trait definition:

traits:
  - paged:
      queryParameters:
		page:
			description: Specify the page that you want to retrieve
			type: integer
			required: true
			example: 1
        perPage:
			type: integer
			description: The number of results per page, not to exceed <<maxPerPage>>
			maximum: <<maxPerPage>>

Notice how we can use the variable <<maxPerPage>> both as a maximum restriction, as well as substituting it into our generated documentation.

To use this, change the definition of the GET /albums endpoint to the following:

/albums:  
  get:
    is: [ paged : { maxPerPage : 50 } ]

You’ll find more examples of traits, along with resource types – which share certain characteristics with traits – in the specification. You’ll also find plenty of other documentation along with examples of some of the more complex scenarios you may need to describe. But let’s move on for now to look at some practical applications of RAML.

RAML in Practice

Now that we’ve looked at how to write a simple RAML to describe our RESTful API, it’s time to look at what we can actually do with it.

Generating API Documentation

RAML is a very detailed, unambiguous overview of an API, but it’s not terribly user-friendly for our API’s consumers.

However because it’s a well-defined, open format, there are tools which can help us use this information in a more user-friendly way. Most notably, there are tools which will take our RAML files and produce HTML-based documentation, ready to be published on the Web.

Let’s look at a few.

Converting RAML to HTML

raml2html

The raml2html tool, as the name suggests, can convert your RAML files into HTML documentation.

Here’s a screenshot of what it looks like out-of-the-box:

An Example set of documentation from the raml2html tool

To use it, first install it via npm:

npm i -g raml2html

Then, to convert a RAML file to HTML you simply do this:

raml2html api.raml > index.html

The result is a fairly reasonable set of API documentation. It has certain dependencies – such as JQuery and Bootstrap – which it pulls in from a CDN, but of course you can modify the resulting HTML as you see fit. You can create your own templates, if you prefer, and simply specify them via the command-line:

raml2html -t custom-template.handlebars -r custom-resource.handlebars -m custom-item.handlebars -i example.raml -o example.html

There’s also a Grunt plugin and a Gulp plugin to make it even easier to generate documentation.

There are certain limitations. Security information doesn’t get copied into the HTML, so if you use OAuth for example, you may need to document that separately yourself.

php-raml2html

There’s also a PHP equivalent called php-raml2html.

Here’s a screenshot of the tool’s output:

An example screenshot of documentation produced using php-raml2html

There’s also an online demo, and you’ll find the documentation here.

Personally, I prefer raml2html for two reasons. First, the default output is a little cleaner. Second, it produces static HTML – whereas php-raml2html requires PHP to run – which means it’s perfect for hosting on Github Pages or the like. However, if you’re primarily a PHP developer then you might find this tool easier to customize.

API Console

You can generate more sophisticated documentation from a RAML file using the API Console web component. The resulting HTML is similar in style to raml2html, but it has a killer feature; it provides a console which allows people to interact with your API from within the documentation. It takes care of building forms for you for any available parameters, validating them according to your definitions, as well as being able to work out how to perform authentication.

To see it in action, there are demos online for Twitter and Github. If you’ve been using the Anypoint Platform you’ll have seen it already; it’s what’s used to generate the interactive documentation in the right-hand column.

API Console is implemented using Angular, but you don’t necessarily need any experience with it in order to use it.

To get up-and-running quickly, simply follow these steps:

  1. Clone the repository: git clone git@github.com:mulesoft/api-console.git

  2. Copy the dist folder into an empty directory to hold your documentation

  3. Copy your .raml file somewhere in that folder

  4. Create an HTML file as follows:

<head>
  <link rel="stylesheet" href="dist/styles/app.css" type="text/css" />
</head>
<body ng-app="ramlConsoleApp" ng-cloak id="raml-console-unembedded">
 <raml-console src="api.raml"></raml-console>
  <script src="dist/scripts/vendor.js"></script>
  <script src="dist/scripts/app.js"></script>
</body>

Modify the src attribute of the <raml-console> directive to point to the correct file

  1. Open the file via a web server of some description; be it Apache, Ngnix or Connect

That’s all there is to it.

You can also embed the API Console in an iframe; refer to the project’s README for details.

Notebooks

API Notebooks are another way to allow people to interact with your API. You can embed runnable examples into your web pages, using RAML to describe the underlying API.

This is perhaps best illustrated with an example; click here for a demo of using an API notebook to interact with Github’s API.

You’ll probably want to start here, as this particular part of the documentation is specific to creating a Notebook which runs off RAML.

Other Tools

There are a number of other tools available to work with RAML files. For example;

You can convert RAML to Markdown format using this command-line tool.

The RAML to Wiki tool allows you to convert RAML into content suitable for a wiki within Confluence or JIRA.

You’ll find a comprehensive list of tools available for working with RAML on this Projects page.

Build your Own Tool

Because it’s an open standard, you’re free to build pretty much anything you think would be useful in order to work with RAML files.

A good place to start is probably this PHP-based RAML parser. It allows you to convert schemas into a validation object, extract a list of routes and more.

There are also parsers available for JavaScript, Java, Python and Ruby.

Conclusion

In this article I’ve taken a fairly comprehensive look at RAML, the RESTful API Modeling Language. It provides a way of describing a RESTful API in clear, comprehensive and unambiguous terms.

Perhaps the most obvious and arguably most useful use for RAML is for generating documentation. We’ve looked at a few approaches to this, most notably the API Console project, which not only generates HTML-based documentation for you, but provides an interactive console which allows readers to try out your API from within the documentation.

We’ve also looked at a range of other tools. Being a relatively new standard, expect to see plenty more in the near future.

If you’d like to find out more, I’d encourage you to read through the specification, which you’ll also find on Github.

Frequently Asked Questions (FAQs) about RAML (Restful API Modeling Language)

What is the primary use of RAML in API development?

RAML, or RESTful API Modeling Language, is primarily used to design and document APIs. It provides a structured, clear format for describing an API’s resources, methods, parameters, responses, and other attributes. This allows developers to understand and use the API more effectively. RAML also supports the creation of reusable components, which can significantly speed up the API development process.

How does RAML compare to other API description languages?

RAML is often compared to other API description languages like Swagger and API Blueprint. While all three provide similar functionality, there are some key differences. RAML, for instance, emphasizes reusability and readability, with features like resource types and traits that can be defined once and reused throughout the API. It also uses YAML, which many developers find more readable than JSON or Markdown.

Can I use RAML for testing APIs?

Yes, RAML can be used for testing APIs. By defining the expected responses for different API calls in your RAML document, you can use this as a basis for automated testing. There are several tools available that can generate tests from a RAML specification, helping to ensure that your API behaves as expected.

How can I convert between RAML and other API description formats?

There are several tools available that can convert between RAML and other API description formats like Swagger or API Blueprint. These can be useful if you need to switch between different tools or workflows that support different formats. However, keep in mind that not all features may be preserved in the conversion, as each format has its unique capabilities and limitations.

What tools support RAML?

There are many tools that support RAML, ranging from API design and documentation tools to testing and monitoring tools. Some popular choices include MuleSoft’s Anypoint Platform, which provides a comprehensive suite of tools for designing, building, and managing APIs, and API Workbench, a powerful IDE for working with RAML.

How does RAML support versioning of APIs?

RAML has built-in support for versioning of APIs. You can specify the version of your API directly in the RAML document, and use this to manage different versions of your API. This makes it easier to introduce changes without breaking existing clients.

Can I use RAML for documenting APIs?

Yes, RAML is an excellent tool for documenting APIs. It provides a structured format for describing all aspects of an API, from resources and methods to parameters and responses. This makes it easy for developers to understand how to use your API. There are also tools available that can generate user-friendly, interactive documentation from a RAML specification.

How does RAML handle security?

RAML provides several features for describing the security aspects of an API. You can specify the authentication methods supported by your API, define security schemes, and apply these to different resources or methods. This helps to ensure that the security requirements of your API are clearly communicated to developers.

Can I use RAML with JSON?

Yes, RAML is fully compatible with JSON. You can use JSON to define the body of requests and responses, and RAML provides features for describing the structure of JSON data. This allows you to leverage the power and flexibility of JSON in your API design.

What are the benefits of using RAML for API design?

Using RAML for API design offers several benefits. It provides a clear, structured format for describing your API, making it easier for developers to understand and use. It supports reusability, which can speed up the design process and ensure consistency across your API. It also integrates well with other tools, allowing you to generate documentation, tests, and even code from your RAML specification.

Lukas WhiteLukas White
View Author

Lukas is a freelance web and mobile developer based in Manchester in the North of England. He's been developing in PHP since moving away from those early days in web development of using all manner of tools such as Java Server Pages, classic ASP and XML data islands, along with JavaScript - back when it really was JavaScript and Netscape ruled the roost. When he's not developing websites and mobile applications and complaining that this was all fields, Lukas likes to cook all manner of World foods.

apiBrunoSdocumentationOOPHPPHPramlrestfulyaml
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week