Designing APIs With RAML
An API designed with RAML will define basic CRUD operations for the customer entity, as well as a couple of query operations.
Join the DZone community and get the full member experience.
Join For FreeSo, you are thinking about writing an API for your company and you stumble upon RAML. Today, I will be giving you an introduction to RAML basics. For more detailed info, you can check out the RAML documentation. I will be using the latest version of RAML (1.0) in my design below.
What Is RAML?
RAML stands for RESTful API Modeling Language. It's a way of describing practically RESTful APIs in a way that's highly readable by both humans and computers. It is a vendor-neutral, open-specification language built on YAML 1.2 and JSON for describing RESTful APIs.
I say "practically RESTful" because, in the real world, very few APIs today actually obey all of the constraints of REST. RAML isn't strict for now — it focuses on clearly describing resources, methods, parameters, responses, media types, and other HTTP constructs that form the basis for modern APIs that obey many, though perhaps not all, RESTful constraints.
Creating RAML for Your API
I will be creating the API for the customer. This API will define basic CRUD operations for the customer entity, as well as a few query operations. Below is the list of resources we will be defining for our API:
GET
/api/v1/customer.POST
/api/v1/customer.GET
/api/v1/customer/{id}.PUT
/api/v1/customer/{id}.DELETE
/api/v1/customer/{id}.GET
/api/v1/customer/name/{name}.GET
/api/v1/customer?name={name}&role={role}.
Let’s define our API to be stateless, using HTTP basic authentication, and to be delivered encrypted over HTTPS. Finally, let’s choose JSON for our data transport format (XML is also supported).
Setting the Root of RAML
At the root level, all the settings that we do get applied to the entire API. Let's start by creating a simple text file and naming it cutomerAPI.raml
. It is suggested to prefix it .raml
as it will be used later by tools that we will be using to generate the actual implementation of APIs. You can name the file anything you like.
On Line 5, the braces { }
around version
tell RAML that “version
” refers to a property and is to be expanded. Therefore, the actual baseUri
will be http://company.domain.com/api/{version}.
Note: The version property is optional and need not be a part of the baseUri
.
Setting Security of API
Security is also defined at the root level of the .raml
file. So, let’s add our HTTP basic security scheme definition:
Setting Data Types of API
For our entity customer, let's define the data type, i.e., the properties of our customer:
The ?
character following a property name declares that the property is not required.
Resources Definition
Our top-level resource is going to be the customer:
URI Parameters
Expand the list of resources, building from our top-level resource:
Here, the braces { }
around property names define URI parameters. They represent placeholders in each URI and do not reference root-level RAML file properties as we saw above in thebaseUri
declaration. The added lines represent the resources /customer/{id}
and /customer/name/{name}
.
Methods
The next step is to define the HTTP methods that apply to each resource:
Query Parameters
Now, we’ll define a way to query the customer collection using query parameters. Note that query parameters are defined using the same syntax that we used above for data types:
Responses for Resources
Now that we have defined all of the resources for our API — including URI parameters, HTTP methods, and query parameters — it is time to define the expected responses and status codes. Response formats are typically defined in terms of data types and examples.
This example shows that by performing a GET
request on the resource /customer/{id}
, we should get back the matching customer in the form of a JSON object and an HTTP status code of 200.
Here is how we would define the GET
request on the /customerresource
:
The use of square brackets []
appended to the customer type demonstrates how we would define a response body containing an array of customer objects, with the example being an array of JSON objects.
Request Body
Next, we will define the request bodies that correspond to each POST
and PUT
request. Let’s begin with creating a new customer object:
Status Codes
Note in the above example that when creating a new object, we return an HTTP status of 201. The PUT
operation for updating an object will return an HTTP status of 200, utilizing the same request and response bodies as the POST
operation.
In addition to the expected responses and status codes that we return when a request is successful, we can define the kind of responses and status codes to expect when an error occurs.
Let’s see how we would define the expected response for the GET
request on the /customer/{id}
resource when no resource is found with the given ID:
Includes in RAML
As we go on with the design, our API will start getting repetitive and we will be writing and copying many things again and again. To overcome this issue RAML provides a mechanism to do include in your API by taking out examples, schema, security, etc. to separates file and then using include to put them in place. We can refactor our API definition using includes, making it more concise and less likely to contain the types of errors that result from the “copy/paste/fix everywhere” methodology.
For example, we can put the data type for a customer object in the file types /customer.raml
and the type for an Error object in types /error.raml
. Our types section will look like this:
Tools Used to Design
I am using the Anypoint platform by Mulesoft to edit and develop my RAML.
You can get the details of RAML here.
In the second part of this blog, I will be writing the implementation of using the customer RAML to create real APIs using Mulesoft Anypoint Studio along with more tools and references.
I hope I was able to give a basic idea about RAML and its usage. We have just touched the surface of the great ability of RAML to define APIs.
Opinions expressed by DZone contributors are their own.
Comments