PHP - - By Lukas White



[an] API is only as good as its documentation


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


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:


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:


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:

	- title: Home
		content: |
			This example documentation forms part of a tutorial for a 
			[Sitepoint]( 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:

	displayName: Album
	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:

        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:

        description: The International Standard Recording Code which uniquely identifies this album
		type: string
			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:

		description: Retrieve a list of albums
			description: Create a new album
        description: The International Standard Recording Code which uniquely identifies this album
		type: string
			description: Retrieve the specified album
			description: Update an album		
			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:

			description: Retrieve the specified album
             schema: |
               { 	"$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:

    description: Retrieve a list of albums
        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:

		description: Retrieve a list of albums
		description: Create a new album
					description: The International Standard Recording Code which uniquely identifies this album
					type: string
					required: true
					description: The name of the album
					type: string
					required: true
					description: The name of the artist
					type: string
					required: true
					description: The label it was released under
					type: string
					required: false
					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.


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:

  - oauth_2_0:
      description: |
        Acme uses OAuth2 to authenticate most requests
      type: OAuth 2.0
            description: |
              Used to send a valid OAuth 2 access token. Do not use
              with the "access_token" query string parameter.
            type: string
            description: |
              Used to send a valid OAuth 2 access token. Do not use together with
              the "Authorization" header
            type: string
            description: |
              Bad OAuth request (e.g. wrong consumer key, bad nonce, expired
              timestamp, etc.)
            description: |
              Bad or expired token. To fix it, re-authenticate the user.          
        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:

		securedBy: [null, oauth_2_0]
		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.


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:

  - paged:
			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:

    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:

  - paged:
			description: Specify the page that you want to retrieve
			type: integer
			required: true
			example: 1
			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:

    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


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.


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

  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:

  <link rel="stylesheet" href="dist/styles/app.css" type="text/css" />
<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>

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.


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.


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.


Wonderful. Slate has some drawbacks when dealing with "zig-zag", left-right alignment. Hope this is much better. Will give it a try.


Why not use OData, it is open/enterprise/......
Is the problem that it originated in Microsoft, or to abide to a predefined structure instead of doing your own version of everything -- a version that is just a little bit wrong.
(By the way, I reinvent the wheel all the time. It is the industry standard)


Not sure anyone reading this will find this helpful, but there is a "movement" among the RAML community around "generation" of anything/everything from RAML. In particular, the raml-client-generator project spun off an abstracted project called raml-generator. That project allows you to build your own nodejs module that requires raml-generator and then provide some boilerplate JS code to bootstrap your own custom generator engine. It all uses Handlebars.js internally so it's pretty robust and quick to work with. A number of us are working on SDK generators for java, ruby, python, .net, go and others (JS is already covered by the raml-client-generator project). There are server side options for JAX-RS, python, etc as well as automated test code... in the works using the same generator, and with a little work a Markdown or HTML generator could be written for help generation. In short, especially if you are looking for client side SDKs and possibly server side, you can use RAML as your single source of truth to produce the full gamut of client and server output.


@justjacksonn that sounds really interesting, thanks for the heads up. When you have something concrete, please consider getting in touch and writing about it, or just talking to me about it in depth and I'll do the writeup if you don't feel like it - I'd love to explore these concepts in a bit more depth.


Likewise, as the author of the article above I find it very interesting. When I looked at RAML for the first time, it felt like there were all sorts of possibilities for code generation, mocking, testing against and so on - so it's great to know they're being explored.