7 Simple Steps to Write a Better API Using Spring Boot that You Should Know
Why no one taught me that?
Hi there! I hope that you are having a great day, today we will talk about some advice that I consider essentials when programming a Spring Boot application. All of them are based on my experience working with that and are subjective of course, let’s go for it.
1. Organize the project properly
This sounds a little obvious but not less important, maintaining a great structure is a big thing to have in mind. Keep things organized is very helpful for us but it is super helpful when new people enter the project, the learning process will be much easier if things are where they should be.
2. Use @RestController
If you are starting with Spring Boot I’m sure that you know the @Controller annotation from where you were studying it in a course, it is totally fine but I recommend you to use the @RestController alternative. This annotation will wrap all the responses that the controller returns into ResponseEntity objects.
The endpoint definition looks very clean this way, you can specify the HTTP code returned with another annotation and a lot of more details if you want.
3. Use Optional as a return parameter if necessary on the repositories, entities and models.
This is very helpful to avoid NullPointerExceptions and much more easy to see when a property or a method call can be null. If you are using Spring Boot 2+ you probably saw that the default implementations of JpaRepository returns Optionals, you also can do it with your custom queries just like that:
This is a huge improvement, we can get the result and throw an exception or use a default value very easily using the Optional tools.
Also, another thing that I recommend very much is to return Optionals on the getters of your models or your entities if the attributes can be null, just to be sure that the person that codes with that later is treating the value as it should be. With collections I prefer to return an empty list, so the person that uses it doesn’t have to unwrap the optional, just use the list normally. This simple approach can save us a lot of time in the future, I’m used to doing it this way:
You can read a little more about optionals in my last article here if you want :)
4. Use dependency injection in constructor, avoid dependency injection on fields
You can see @Autowired annotation everywhere but using this is not a good practice. Here you have a couple of reasons why:
- Hidden dependencies: if someone wants to create an object from a class that uses field-based dependency injection they couldn’t do it properly because the @Autowired annotated variable is not required by the constructor and it will be null. Using dependency injection through the constructor we can clearly see what is needed to create an object.
- Can’t define autowired fields as final because the dependency injector container has to modify it after the instance is created.
5. Keep models and entities separate
Never return an entity outside the API. Sometimes you have to return the exact data that is declared in the entity, you are tired and decide to return the entity… Two months later you have to change the database definition and now this affects your entire application, all 3 layers (Reposity, Service and Controller). Maintain separate the models that we return outside the API and entities of the database allow us to have more control in that kind of situation, so even if the data that you have to return is the same as the entity’s (for the moment), create a model, just in case.
6. Validate the attributes of the models and entities with annotations
Don’t mess up your beautiful code with validations please, you can easily annotate the attributes of your models to accept only data that fulfill all your requirements. I’ll show you an example:
You can use the same approach to validate your entities and your application will be free of validations in the business layer. You can even create your own annotations for custom validations, I always use one to avoid null values inside of lists, just like this:
7. Use @ControllerAdvice to control exceptions
Managing exceptions with Spring Boot is a very easy task, just throw the exceptions to the controller level and the @ControllerAdvice will do the rest.
Using the @ControllerAdvice you only have to catch the exceptions that you want and specify the response that you want to return in every case. This can be complemented with a good exception hierarchy and you will have a great exception management.
I hope that you enjoyed reading! If you want to read further about the terms that I used here I’ll give you some links to great tutorials: