Friday, 29 June 2018

Part 1 - REST API Best practices and implementing them with Spring Boot

This article describes the best practices of implementing REST API using Spring Boot.

Before we jump into the actual implementation, lets first understand the design principles involved in API design.


API Design principles

  1. Present APIs as products
    • APIs are not integration services that happen to use HTTP and JSON
    • They are business products that must be managed as a complete product offering
    • And although created and managed by different teams they should have a similar look and feel
  2. Design APIs with the consumer in mind
    • Develop APIs as though you consumers are your customers
    • APIs should be more developer-friendly and Easy to Consume
    • Simple to Expose to external third-parties in future
    • Don't leak internal context to the consumer
    • Make APIs easy to learn, hard to misuse, audience-oriented
  3. Prefer REST-based services over SOAP

REST API Design principles

  1. Use RESTful URIs and actions
    • /policies - refers to a policy resource collection
    • /policies/7895544 - refers to a policy resource collection
  2. Use HTTP verbs to act on you resources
    • Resources should be acted on using HTTP methods GET, PUT, POST, PATCH, DELETE for example GET /policies/789554
    • HTTP methods should perform predictable actions on the resource. For example, don't use POST to retrieve a resource, and don't use DELETE to create a resource.
  3. Nouns are good, verbs are bad
    • Resources must use plural nouns, such as accounts and not account
    • Do not use verbs in URI, /getaccount or createcar
    • The method exposing the webservice should be verb not the associated URI
  4. Use sub-resources to represent relationships
    • For e.g if a Department has many Employees and you need to get the list of employees in a department, the URI should be 
      GET /departments/  - Get all Departments
      POST /departments/  - Create a Department
      GET /departments/1234  - Get a Department
      GET /departments/1234/employees - Get all Employees in a Department
      POST /departments/1234/employees - Create an Employees in a Department
      GET /departments/1234/employees/2 - Get a Employee in a Department

  5. Version your API
    • All APIs should be versiones
    • Use only a major version number prefixed with a "v", eg /v1
  6. HATEOUS compliant
    • The API should be HATEOUS compliant. All future actions the client may take are discovered within resource representations returned from the server. The media types used for these representations, and the link relations they may contain, are standardized.
    • For e.g for a GET /departments/
    • {
      "id" : 1,
      "name" : "Head Office",
      "Address" : "In a far galazy",
      "links" : [
         {
             "rel" : "self",
             "href" : "http//abc.com/api/v1/departments/"
         },
         {
             "rel" : "find",
             "href" : "http//abc.com/api/v1/departments/{id}",
             "type" : "GET"
         },
         {
             "rel" : "delete",
             "href" : "http//abc.com/api/v1/departments/{id}",
             "type" : "DELETE"
         }
         
      }
    • As seen above the response has a link to self and also other possible resources the client can use

  7. API must be secured
    • APIs must be secured and there are no exceptions
    • OAuth2.0 can be used for securing APIs.
    • Choose the best grant type e.g authorization code/password/client credential
  8. Error Handling
    1. Use descriptive error messages and status code
    2. For e.g if the request is to find a employee and the employee id provided is not correct, return a 404 Resource Not Found status code and not a 200 OK
    3. Trap all errors and always return a valid JSON response

    4. {
          "timestamp": "2018-06-27T12:42:39.238+0000",
          "status": 400,
          "error": "Bad Request",
          "message": "Do not send ‘id’ as part of request",
          "path": "/spring-security-oauth-resource/rest/v1/employees"
      }
      
      

      Another example for multiple errors would be like below:
      {
          "status": 405,
          "timestamp": "02-07-2018 03:16:55",
          "path": "/spring-security-oauth-resource/rest/v1/departments",
          "message": "Validation failed for object='department'. Error count: 3",
          "sub_errors": [
              {
                  "field": "name",
                  "message": "name cannot be Blank"
              },
              {
                  "field": "id",
                  "rejectedValue": 1111,
                  "message": "must be null"
              },
              {
                  "field": "knownName",
                  "message": "known_name cannot be Blank"
              }
          ]
      }
      
  9. Things to avoid
    • Dont use querystring argumets to retrieve by primary key:
    • For eg : dont use /policies/?policy_number=32323
      Rather Use /policies/12333
    • Dont use mixed-case in URLs:
    • For eg : dont use /Policies/32323
      Rather Use /policies/12333

Thursday, 11 January 2018

Share the post