What Is A Controller Anyways? 🧐
It acts as the entry point to our backend application from the outside world.
By outside world I mean
- Frontend applications that run on browsers.
- Other backend applications that run on servers.
How It's Done?👀
- The controller defines entry points that clients from the outside world can talk with using REST operations (GET, POST, DELETE, etc..).
- A request that has the matching properties defined by a certain entry point will trigger the function of that entry point.
- The function then calls business logic functions that will do some stuff and return a response to the client.
@RestController
public class GradeController {
@GetMapping("/grade/{id}")
public void getGradeById(@PathVariable String id){
// business stuff
}
}
The example above describes an entry point at baseUrl/grade/someGradeId
that is run when a GET request is made with a URL matching the pattern (baseUrl/grade/1
for example).
What Are The Responsibilities Of A Controller?☝️
Let's list them in order from the moment a request is received to the moment of returning a response.
1️⃣ Listening to HTTP requests👂🏼
What URL/HTTP Types/Request Parameters should trigger this function?
- In the example above, we are saying that the function getGradeById will be run when a GET request is made to the url
baeUrl/grade/{id}
.
2️⃣ Deserializing the input from the incoming request ✍️
Turn the request body into Java objects. Turn the request parameters into Integers, Strings, etc...
@RestController
public class GradeController {
@PostMapping("/grade/add")
public void getGradeById(@RequestBody Grade grade){
// business stuff
}
}
The Grade class
class Grade{
Integer id;
String letter;
// getters and setters and constructors
}
In this example, turn the POST request body into a Grade object.
The POST requests body should something like this:
{
"id": "1",
"letter": "A+"
}
3️⃣ Validating the Deserialized objects🧙
We can specify validation rules against the inputs our controllers take. An error will be thrown if the rules weren't met.
For example, the id parameter shouldn't be negative.
We can do the validation manually
@RestController
public class GradeController {
@PostMapping("/grade/add")
public void getGradeById(@RequestBody Grade grade) throws Exception{
if (grade.getId() < 0)
throw new Exception();
}
}
Or we can use Spring's validation mechanisms
The Grade class with the validation annotation
class Grade{
@Min(1)
Integer id;
String letter;
}
The controller with the annotation to activate the validation
@PostMapping("/grade/add")
public void getGradeById(@RequestBody @Validated Grade grade)
{
// business stuff
}
Learn more about Spring validation from my other blog post.👈
4️⃣ Calling business logic 💼
The body of the controller function is executed. It should ideally call functions from the service layer which runs business code.
@RestController @RequiredArgsConstructor
public class GradeController {
private final GradeService gradeService;
@GetMapping("/grade")
public void getGradeById()
{
gradeService.doThings();
}
}
Note the usage of Lombok to write cleaner code. Check out my bog post about Lombok here.👈🏻
5️⃣ Serializing the output of the controller function 🛠
The returned value from the function is is turned into a HTTP response.
@RestController
public class GradeController {
@GetMapping("/grade/add")
public APIResponse getGradeById()
{
// do things
return new APIResponse("success");
}
}
@AllArgsConstructor
class APIResponse{
String message;
}
So the response will be a 200 with a JSON value of
{
"message" : "success"
}
6️⃣ Handle Exceptions ⛔️
If an exception happens and goes unhandled by the business logic code, the controller translates it into a meaningful response.
Important Note ☢️
As we've seen, the controller has a lot to do! It's very important not to include business logic code in the controller.
I've seen this mistake done many times. I've also seen controllers with thousands of lines of business code.
This leads to creating a timed bomb that could explode on a Monday at 9 PM 💣
Top comments (1)
Great article, thank you abdulcelil for sharing.