Have you written a REST API from scratch that requires to be consumed by third party systems? How was your experience? Did you face any problems or was it a smooth transition? Were there any changes introduced in the interface after making the first release? How did you handle it?
In this brief blog I would like to share my experiences and learnings of writing a REST API in Java for third party systems.
Writing an API can be very interesting and exciting, but it also poses some challenges that must not be overlooked. I have listed some points out of my own experience below:
- Requirements
Before you start to implement the service, talk to the concerned stakeholders and try to understand the requirements and purpose of the API. If your API is going to be part of a broader business workflow, understanding it can help you to grasp the end-to-end usage quickly. Also it is equally important to understand, the end consumers of this service. Understanding the end-to-end business flow and the end-users will enable you to figure out whether there is a scope for changes going forward. If there is a scope for change in the future, consider versioning of API to avoid compatibility issues later.
Agree upon the input and output structure for the service. Examine every input parameter carefully and check if all parameters are really required to serve the purpose. Request and response can be in any agreed data format for e.g. JSON, XML, TEXT. Nowadays JSON is becoming the default standard for data transfer for REST API’s.
- Service contract and documentation
The service-contract should act as a single source of truth between the creator and consumer of the REST API. A service-contract can be created using tools that are agreed with your team members. In the past I have used WADL (Web Application Description Language) from SOAP-UI and Swagger. I personally find Swagger quite easy and lightweight to work with.
Swagger offers many interesting features. Some of the most important features are as below,
a) API documentation
b) Creation of service-contract in different file formats like JSON, YAML etc.
c) API Testing from web-browser.
The service-contract file can be created using Swagger API and maven plugin. The API consumers can then use the service-contract file to create all the dependency classes. These dependency classes can be in turn used to call the A
- Implementation
Resource and Representation lie are the core of REST, hence it is important to identify the Resources and also how to represent them.
REST uses HTTP as the underlying protocol for data transfer, hence it is recommended to use the HTTP conventions while implementing the API. Some of the points that should be considered during implementation are as mentioned below,
a) HTTP Methods
Choosing the right HTTP method. HTTP provides various methods for sending and receiving data. The most commonly used methods and their purpose are as mentioned below,
- HTTP GET -> retrieve a resource
- HTTP POST -> Create a new resource
- HTTP DELETE -> Delete a resource
- HTTP PUT -> Update complete resource
- HTTP PATCH -> Update part of the resource
b) Naming URL
Choosing the right URL for Resource and Endpoints. Some examples in line with REST naming conventions are as mentioned below,
GET /employees instead of GET /getAllEmployees (retrieving all employees)
GET /employees/1 (retrieving a specific employee with Id 1)
POST /employees instead of POST /createEmployee for creating a new Employee
DELETE /employees/1 (deleting a specific employee with Id 1)
PUT /employees/1 (Update complete employee resource with Id 1)
PATCH/employees/1 (Update part of employee resource with Id 1)
c) Request Parameters
It is recommended to receive the parameters from request in immutable objects or primitives. This helps avoids errors that could occur if somebody accidentally modifies this object while processing the request.
For e.g. in Java you can make the object or primitives as final
@POST
@Path(„/employees“)
public Response createEmployee (finalEmployeeRequestData employeeRequestData) {}
@GET
@Path(„/employees/{id}“)
public Response retreiveEmployee(@PathParam(„id“) final intid)
d) Logging parameters
All request parameters (except sensitive) must be logged in logger files. This helps in knowing what exactly was sent by the API consumer in one place, this in turn helps in analyzing and debugging issues. I have ended up saving a lot of time while analyzing production issues because of logging the input parameters.
Similarly, the response (excluding sensitive information) that is sent back to the API consumer after processing should be logged.
e) Validation
All request parameters must be validated before processing. This includes data as well as business validations.
Mandatory parameters
All mandatory parameters must be validated and if some are missing in the request, then an HTTP 400 (Bad Request) response status must be thrown.
Business Validations
Business validations are validations specific to the use case. For e.g. check if age is above 18 or check if a date falls within a period, etc.
When dealing with POST request the request parameters can be validated with java beans validations API.
f) Business Logic
The business logic must be decoupled from the Resource class. The Resource class is the entry point for the REST Service and must only deal with receiving the request and sending the appropriate response. Business logic must be delegated to the Service class.
g) Returning Response
The response should contain ideally a status and description. The status code should confine the HTTP standards for uniformity and wider acceptance amongst API consumers, while the description can be use case specific. Avoid using custom error codes and statues otherwise you would have to provide an explicit documentation as it is not universally understood.
Some commonly used HTTP statues are as mentioned below,
2XX SERIES – SUCCESS
200 (OK) – Request processed successfully and some response content sent.
201 (CREATED) – Request processed successfully and a new resource created.
204 (NO CONTENT) – Request processed successfully and no response content sent.
4XX SERIES – CLIENT
400 (BAD Request) – The parameters sent in the request body are not correct.
401 (UNAUTHORIZED) – The authentication credentials sent in the request are wrong.
403 (FORBIDDEN) – The caller does not have permission to access the resource.
404 (NOT FOUND) – The resource not found on the server.
5XX SERIES – SERVER
500 (INTERNAL SERVER ERROR) – Some error occurred during processing the request.
503 (SERVICE UNAVAILABLE) – The server cannot handle the request due to overload or due to downtime for maintenance.
4) Testing
a) Unit Testing
REST Assured is a wonderful library for testing REST API’s in Java. It enables you to assert http response statues, allows you to make assertions on contents that are delivered as part of response bodies. You can also easily send headers, path and query parameters.
Wiremock is another tool that is essentially a http mock server which helps you stub responses for particular requests. This helps testing in isolation. This is particularly helpful if your REST API is dependent on response received from another REST service for processing.
b) Manual Testing
If you would like to test the REST API manually there are a couple of tools that I found to be very useful.
Postman
Postman can be installed as a standalone client as well as a browser plugin. It offers an excellent User Interface for testing REST Endpoints manually. The UI is flexible for sending the request in various formats JSON, XML, TEXT etc. All possible headers including Authorization can be added easily.
Swagger
Swagger offers a Web UI that can be used for testing the REST API from web browser. The Web component needs to be configured within the application for accessing the Web UI.