Today any real world application requires a service which is scalable to handle more and more users and is highly available. For example if a person is buying its favorite game from a popular site and after spending 20 minutes in selecting color, size and pricing, webpage fails to confirm if the shopping was success or not. How would you rate the user experience?
While in today’s world, when one talks about IoT solution, more often the focal point is what ‘things’ can be connected in the network. But what if the ‘connection’ between things is not scalable enough or not available all the time. Having a reliable connection (or set of services) is the backbone of IoT solution. For creating high available and high performance production grade applications (or services), spring boot provides number of great tools. Making use of those tools in optimized way may result in highly efficient, secure and responsive APIs
1. Health endpoint –
Having a health endpoint helps in monitoring a production ready app at anytime. This could also be in use by load balancer. Based on the health endpoint response, load balancer may be routing the user requests. So a load balancer may not act properly if health endpoints are not implemented. Adding a dependency ‘spring-boot-starter-actuator’ will provide the endpoint by default. this is how a health endpoint typically looks like-
Apart from health endpoints, there are number of similar endpoints which may provide operational information of the springboot APIs
2. Returning ‘informative’ status codes
While browsing a popular website or mobile app, many of us might have seen messages saying ‘some error occurred’ or ‘something went wrong’. This could be because the API did not return a specific response to a request. Instead if the API returned a response like ‘401 Unauthorized’ gives more info which may be lot easier to resolve for a developer. With spring boot, one may even further customize the responses so as to provide more specific information. So instead of just returning the following response codes-
200 OK
500 internal server error
Good practice would be to expand the range of response codes to include few more like-
201 – a new resource was created
400 – Bad Request
401 – Unauthorized
404 – Requested resource was not found
and many more
Even the above list is not complete and one may take advantage of ‘ResponeEntity’ like below-
return ResponseEntity.status(HttpStatus.CREATED).body(“HTTP Status will be CREATED (CODE 201)\n”)
3. Securing the API
Some of the APIs could be meant for public consumption like knowing a weather of a place. Response of these APIs do not have any private information of person or business or government. But many of the APIs would contain information which must be protected. So while creating an API, a developer needs to ensure to add appropriate authentication mechanism. Which means the url of a service/API can be known but service is available only after authenticating the client.
There are multiple ways to secure the endpoint. One simple method is to add basic authentication. More sophisticated ways like ADFS could be used for more sensitive APIs. Also one needs to implement authorization for an API because desired response could be different for different users as per roles assigned within organization.
If an API is implemented with basic authentication, while making request from postman, one needs to select ‘Authorization’ tab, then select Type as ‘Basic Auth’ and fill in Username and Password. If credentials are incorrect, API returns ‘401 unauthorized’ in the response.
4. Understanding LAZY and EAGER loading to improve performance
Knowing when to load related objects can help optimize the performance of APIs. ‘LAZY’ is more efficient and is recommended unless there is specific requirement to do EAGER.
LAZY = fetch when needed
EAGER = fetch immediately
5. Handle simultaneous requests
Most of the real-time applications have number of users simultaneously sending requests to the server. Now the challenge is to provide good user experience in such scenarios. If the request is simple GET request, it may not cause any issue as it is simply reading data from db and return success. But if the request is POST and is writing data to the DB, API may fail. Reason is that table could be auto incrementing the primary key value. So in case of multiple requests, primary key for 2 request could be same and db may likely complain about duplicate key.
To avoid such scenarios, one needs to make use of ‘synchronized’ keyword. How it works is that it serializes the multiple requests which will result in slightly degraded performance. So to have optimal solution, one needs to ensure that only minimal and relevant section of the code is ‘synchronized’
6. Connections to DB to boost performance
As spring boot does auto configuration, so it provides a default value for many of the configuration properties. Each service may have different number of concurrent users and different performance requirements, so it is important to understand the default configuration and change the configuration as per application requirement
spring.datasource.hikari.maximumPoolSize=10
spring.datasource.hikari.idleTimeout=120000
spring.datasource.hikari.connectionTimeout=120000
For example, the maximumPoolSize defines the maximum number of connections to database and default value is set to 10. While running application at peak load, if it throws errors like ‘unable to acquire JDBC connection’ then one needs to look at this property and optimize the value and retest.
7. Optimizing configuration to further boost performance
One more thing worth checking is that how string parameters are sent to server.
For example, for sql server, look at below property-
sendStringParametersAsUnicode=false;
Setting the above property is likely going to improve the performance of APIs. To understand more why such optimization is required, one can directly run the query in db and compare the timing taken by running same query through application code. If there is significant difference in timing, then this is the property to look at.
8. Adding indexing to improve performance
Since adding an index requires extra disk space, one must add indices only. Indexing enhances the performance by storing additional information which returns a much quicker response while searching. Apart from this, in general also all queries should be optimized as much as possible. Simple way of achieving is to try to run the queries directly in the database first and then select the optimized one and add to application code
9. Making use of Inspect as much as possible
For a web application, opening Inspect window can give lot of useful information about functional and performance issues. Inspect gives you information on how much times it took to get response, what parameters were sent in request body and what is complete response.
10. Other best practices
Apart the above mentioned, one needs to look at various other good practices for application development like logging of request/response objects as per requirement, exception handling (spring boot provides various annotations), use of devtools for faster development, documentation generation etc.
Well summarized Punit. Thanks for sharing.