Raml best practices blog img

RAML Best Practices

It is chal­leng­ing to design a REST­ful API which fol­lows the REST prin­ci­ples and attains the max­i­mum lev­el in Richard­son matu­ri­ty mod­el for rest. Most of the enter­prise APIs do not fol­low any of the REST stan­dards or they imple­ments the min­i­mal prin­ci­ples and yet they are named REST API. Such a poor­ly designed API is an insult to be named as REST API. As a devel­op­er, please do not design such an API.

It is impor­tant to under­stand the approach of design­ing an API on a con­tract first or spec dri­ven devel­op­ment. This means that, API spec­i­fi­ca­tion is designed first before you start to code. An API is devel­oped for con­sump­tion and it will be con­sumed only if the imple­men­ta­tion adheres to the con­tract and the API with prop­er doc­u­men­ta­tion. One of the eas­i­est way to kill an API is to define an API in the code with­out con­tract and documentation.

RAML makes it eas­i­er for a devel­op­er to design and doc­u­ment an API. If you fol­low the best prac­tices, the API itself serves as a doc­u­ment for the con­sumer. It is prac­ti­cal­ly Eng­lish, if done prop­er­ly. RAML spec­i­fi­ca­tion pro­motes stan­dard­iza­tion and reusabil­i­ty by mak­ing the API mod­u­lar. You can also use and force design patterns.

Use the fol­low­ing best prac­tices to design your API when using RAML

API Lifecycle

Use Spec Dri­ven Devel­op­ment #

I can­not empha­size enough on the impor­tance of con­tract first approach which saves tons of devel­op­ment time by know­ing almost all the vari­ables before start­ing to code. This process is use­ful for both the API devel­op­er and the con­sumer. The fol­low­ing process is API life­cy­cle when doing spec dri­ven development.

  • Use Design Patterns/​Code Reuse.
  • Mock and get User Feedback.
  • Make Nec­es­sary Changes.
  • Start Cod­ing to the Spec and don’t deviate.

Think about the API #

APIs should be designed for a long term use. It is eas­i­er if you under­stand your tar­get­ed API con­sumer. So, When you design an API, think long-term at least 2 – 3 years. It is impor­tant to build an API which is stan­dard scal­able and back­ward compatible. 

When you break things, or when you break back­ward com­pat­i­bil­i­ty the API con­sumer has to fix the issue instead of build­ing fea­tures and none of the devel­op­ers like it and they are less like­ly to use the API.

If you think ver­sion­ing is a solu­tion, think again. Ver­sion­ing is a nec­es­sary evil yet it is best to avoid it. Uti­liz­ing pat­tern design and code reuse helps to ensure that your API remains uni­form across the full interface.

The best designed API has only one version.

Mod­u­lar­ize and Reuse #

Do not design to have one huge API file with every­thing in it. Use the RAML struc­tur­ing to sep­a­rate the com­mon types and mod­u­lar­ize. This cre­ates reuse­able file frag­ments which can be used lat­er. In RAML you can define traits, exam­ples, schemas in a sep­a­rate file and include it in the main API file. This makes the frag­ments reusable in a dif­fer­ent API across your orga­ni­za­tion when needed.

For exam­ple, Traits can be used to define com­mon method prop­er­ties such as query-para­me­ters and respons­es. Sep­a­rate the traits from the base RAML file.

Com­mon data types, traits, resource types, schemas, exam­ples, must be exter­nal­ized as API Frag­ments in Exchange to pro­mote reusabil­i­ty in API Design.

Mock Your API and get User Feed­back #

Anoth­er huge advan­tage of tools like RAML or Swag­ger is that they allow you to mock your API. This means that you can not only build your API in a visu­al inter­face and take advan­tage of the very same best prac­tices we uti­lize in devel­op­ment, but you can also share a mock ver­sion of your API with poten­tial clients.

Using MuleSoft’s API Design­er you can eas­i­ly turn on a mock­ing ser­vice that gives you a URL that can be shared with oth­er devel­op­ers. This allows your clients to test out” your API by mak­ing real calls as if they would from their application. 

By uti­liz­ing the exam­ple respons­es defined in the RAML file devel­op­ers can quick­ly iden­ti­fy issues and incon­sis­ten­cies, help­ing you elim­i­nate the major­i­ty of design relat­ed issues before devel­op­ment even starts.

By pass­ing along tools like the API Note­book, devel­op­ers can inter­act with your Mock API through JavaScript with­out hav­ing to code any calls them­selves, and also hav­ing the abil­i­ty to send you the spe­cif­ic use case back giv­ing you true exam­ples of what your devel­op­ers are try­ing to accomplish.

Always pro­vide mock data in your API. All the request and response should con­tain prop­er exam­ples which rep­re­sents the real busi­ness data. Sep­a­rate the mock data to an exter­nal file.

Resources and Nam­ing #

Nam­ing the resources should fol­low the gen­er­al REST API guidelines.

Use nouns in low­er­case to rep­re­sent a resource. For resources with mul­ti­ple words, use low­er­case for all the words or use ‘-’ (dash) in between the words and make it readable.


example
/books -> collection
/books/123 -> unique resource under collection

Use URI para­me­ters to get an instance resource and query para­me­ter to fil­ter the col­lec­tion resources. When deal­ing with col­lec­tion resources, imple­ment fil­ter and pag­i­na­tion by default. Define a default lim­it and off­set. Detailed dif­fer­ence and when to use URI para­me­ter and Query para­me­ter is explained in this post.



title: GitHub API
version: v3
baseUri: https://api.github.com/{version}
/users:
  get:
    description: Get a list of users
    queryParameters:
      page:
        description: Specify the page that you want to retrieve
        type:        integer
        required:    true
        example:     1
      per_page:
        description: Specify the amount of items that will be retrieved per page
        type:        integer
        minimum:     10
        maximum:     200
        default:     30
        example:     50

Use RAML inher­i­tance #

Types are sim­i­lar to Java class­es. Types bor­row addi­tion­al fea­tures from JSON Schema, XSD, and more expres­sive object ori­ent­ed lan­guages. Where ever pos­si­ble, use the RAML inher­i­tance to resuse schemas and com­mon files. Also, know when not to to inher­it schemas.



title: API with Types
types:
  User:
    type: object
    properties:
      firstname: string
      lastname:  string
      age:       number
/users/{id}:
  get:
    responses:
      200:
        body:
          application/json:
            type: User​

HTTP Codes #

Each resource should have at least one HTTP verb asso­ci­at­ed with it to rep­re­sent the action that can be per­formed on that par­tic­u­lar resource. And each method should return accu­rate HTTP code for resource-method pair. Add descrip­tion to each method.

Use the cor­rect HTTP Codes for each response


1xx: Informational
2xx: Success
3xx: Redirect
4xx: Client error
5xx: Server error

HTTP Verbs #

Use the cor­rect verbs to define the cor­rect action.


GET: For obtaining data. Idempotent

PUT (Idempotent): To update data. It will update the entire instance. Idempotent. Can be used for both creating and updating. Commonly used for updating (full updates). Always include the whole payload in the request. It’s all or nothing. PUT is not meant to be used for partial updates

PATCH (Idempotent): To update data. It will update partial data of an instance.

POST (Not idempotent): To store data.

DELETE (Idempotent): To delete an instance.

These are some of the best prac­tices I fol­low when design­ing a REST API and it is not lim­it­ed to the things men­tioned in this post.

I hope this arti­cle helped you. If you have any queries, please feel free to com­ment or con­tact me here for any help.