Introduction to RESTful API Modeling Language (RAML)
1. Overview
RAML
is a YAML based language which is built on YAML1.2 and JSON for
describing RESTful APIs. It provides all the information necessary to
describe Restful API.
It
focuses on cleanly 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.
2. Requirement
Before
jumping to RAML. Let’s assume we have to create one web application
which is exposing CRUD Operations and couple of query parameters to
access USER resources:
·
POST /api/v1/users
·
GET /api/v1/users
·
GET /api/v1/users?username={username}
·
GET /api/v1/users/{userId}
·
PUT /api/v1/users/userId{}
·
DELETE /api/v1/users/{userId}
All
the API’s are secured via Basic Authentication and all the
communication will be done over HTTPS and all the request response
will be in JSON format.
3. Implementation
3.1 Adding Root level details
To
start with RAML, first create a file with extension .raml and at rool
level, you need to define the setting starting with RAML version.
1.
#%RAML 1.0
2.
title: REST Services API using Data Types
3.
version: v1
4.
protocols: [ HTTPS ]
5.
baseUri: http://hostname/api/{version}
6.
mediaType: application/json
#1
defines the RAML version
#2
Title of the application
#3
API versions
#4
HTTP or HTTPS channel
#5
URL of the application where ‘versions’ refers to a property
which will be replaced with #3 version.
#6
Media type for the request/response.
3.2 Add Security
Security
should also be added at the root level and as I mentioned earlier all
the API’s are secured via Basic Authentication.
-
securitySchemes:
-
basicAuth:
-
description: Basic Authnetication to authenticate API
-
type: Basic Authentication
-
describedBy:
-
headers:
-
Authorization:
-
description: Used to send the Base64-encoded "username:password" credentials
-
type: string
-
example: Authorization NTA5NjUsInN1YiI6IkJhcmNsYXlzX1BheW1lbnRfU2Vydmlj
-
responses:
-
401:
-
description: |
-
Unauthorized. Username/password is invalid
3.3 Add Data type
Once
you are done with security then starts adding all your data type. In
my case I will define it for users.
There
are multiples ways to define your type:
1.
You can create a new file users .raml and include the path over here
(Will discuss at the end of this document).
2.
Define the types after root setting using expanded syntax
3.
Or you can do it via shortcut.
-
types:
-
Users:
-
type: object
-
properties:
-
id:
-
required: true
-
type: integer
-
username:
-
required: true
-
type: string
-
roles:
-
required: false
-
type: string
Now
we will see how we can define the user using shorthand.
1.
types:
2.
Users:
3. properties:
4.
id: integer
5.
username: string
6.
roles?: string
?
-> Adding to any property declares that the field is not
mandatory.
3.4 Define Resource, method, URL parameters and query parameters
To
define a resources
/users:
To
add the method
/users:
get:
post:
To
add the URL parameters
/users:
get:
post:
/{userId}:
get:
put:
delete:
To
add the Query Parameters:
/users:
get:
description: List all users with/without filters
queryParameters:
name?:
string
roles?: string
post:
/{userId}:
get:
put:
delete:
Over
here, we have seen how we can declare the resources with VERB and how
we can define path as well as query parameters.
3.5 Request and Response Body
In
above example we have defined the users resources with POST method
but have not defined the payload. Let’s see how we can add payload,
response and Status Code to an API.
/users:
get:
description:
List all users with/without filters
queryParameters:
name?:
string
roles?:
string
post:
description:
create a new user
body:
application/json:
type:
Users
example:
{ "id" : 101, "name" : "Abdul Waheed”,
“roles”:”Admin” }
responses:
201:
body:
application/json:
type:
Users
example:
{ "id" : 101, "name" : "Abdul Waheed”,
“roles”:”Admin” }
500
:
body:
application/json:
type:
Error
example:
{ "message"
:
"
Internal
Server Error
,
"code"
:
500
}
/{userId}:
get:
put:
delete:
In
this example, We are performing POST operation where we are passing
Users object in the form of JSON and in response we are getting
STATUS code as 201 and again response type in the form of JSON.
4.
Usage of Includes in RAML
In
the above example, we just took one resouces but let’s assume you
have to create RAML for your application where you have many resouces
and each resouces have multiple consuming API.
Handling
such requirement makes our .raml file more verbose and repetetive.
Using
!include, we can externalize our duplicate lengthy code.
Eg:
we can put the data type for a Users object in the file
types/Users.raml
and
the type for an
Error object
in types/Error.raml.
Then our types
section
would look like this:
types:
Users
:
!include types/
Users
.raml
Error:
!include types/Error.raml
5.
Completing the API
After
externalizing all of the data types and examples to their files, we
can refactor our API using the include facility
-
#%RAML 1.0
-
title: REST Services API using Data Types
-
version: v1
-
protocols: [ HTTPS ]
-
baseUri: http://hostname/api/{version}
-
mediaType: application/json
-
securitySchemes:
-
basicAuth:
-
description: Basic Authnetication to authenticate API
-
type: Basic Authentication
-
describedBy:
-
headers:
-
Authorization:
-
description: Used to send the Base64-encoded "username:password" credentials
-
type: string
-
example: Authorization NTA5NjUsInN1YiI6IkJhcmNsYXlzX1BheW1lbnRfU2Vydmlj
-
responses:
-
401:
-
description: |
-
Unauthorized. Username/password is invalid
-
types:
-
Users:
-
type: object
-
properties:
-
id:
-
required: true
-
type: integer
-
username:
-
required: true
-
type: string
-
roles:
-
required: falsetype: string
-
/users:
-
get:
-
description: List all users with/without filters
-
queryParameters:
-
name?: string
-
roles?: string
-
response:
-
200:
-
body:
-
application:json
-
type: Users[]
-
example: [
-
{“id”:1,”username”:”Abdul”}
-
{“id”:2, “username”:”Waheed”}]
-
post:
-
description: create a new user
-
body:
-
application/json:
-
type: Users
-
example: { "id" : 101, "name" : "Abdul Waheed”, “roles”:”Admin” }
-
responses:
-
201:
-
body:
-
application/json:
-
type: Users
-
example: { "id" : 101, "name" : "Abdul Waheed”, “roles”:”Admin” }
-
500
:
-
body:
-
application/json:
-
type: Error
-
example: { "message"
: "
Internal Server Error
, "code"
:
500
}
-
-
/{userId}:
-
get:
-
put:
-
delete:
In
my next blog, I ll talk about different RAML tools and the difference
between SWAGGER (recently renamed to OAS) Vs RAML and which one to
prefer.