# 5Building your First RESTful CRUD API. ## Part 5: Creating the Controller Layer ***Finally***, the time has come where we can connect the last few dots, and get the RMS up and running, accepting requests from a client, and seeing the everything you have done until now, come to life! Now that the Service layer has been completed, we need to have a way to accept requests from the outside world, so that depending on the request, we can trigger each of the different CRUD flows to perform actions for our customers. Before we get started, we should *probably* go through some basics about how our the RMS can accept requests in the first place (do skip to the next part if you already know this stuff! πŸ˜‰) ### How can services interact with each other? A very common way that we can send requests from one place to another is using ***REST over HTTP***. ***HTTP*** - defines a set of request methods to indicate the desired action to be performed for a given resource, which we can make use of to fulfil the operations that need to be completed. | Operation | HTTP Verb| HTTP Use Case |Our Use Case | | -------- | -------- | ------------------|-----------------------------| | Create | POST | Create a resource |**C**reating a reservation | | Read | GET | Fetch a rosrouce |**R**etrieving a reserivation| | Update | PUT | Update a resource |**U**pdtaing a reservation | | Delete | DELETE | Delete a resournce|**D**eleteing a reservation | ***REST*** - Representational State Transfer. This provides a standard between services, making it easier for services to communicate with each other. Back in the day, when you requested a webpage, sometimes it would look like `http://www.exmaple.com/asdkafuliofiualdhdajskd`, which to the naked eye means absoluately nothing. REST on the other hand changes this to help us give our enpoints a little more meaning! e.g. `http://www.exmaple.com/api/v1/reservation`. This makes so much more sense, its clearly readable, and its easy to understand that we are interacting with v1 of this API and we are interacting with the `reservation` endpoint. This is what REST attempts to solve. So in Part 1, when I said we are building a **RESTful application**, now you know what it means πŸ˜„. ***REST over HTTP*** - combining the two, REST over HTTP basically means that we are going to use the various HTTP verbs and combine them with these nice readable URI style, to make it easy for others to interact with our API. In our `ReservationRepository` layer, we made use of the `CrudRepository` interface, which has a collection of different CRUD methods that we made use of. ***The Controller Layer***- contins various entry points to our system. It will accept these various HTTP requests, so that we can then interact with the Service layer, then the Repository layer and in turn perform actions on the database based on the request that has come into the app. and them **BOOOOOM! we are done!** ### How does the controller layer work? - When a request enters the application, the request will be sent to the HTTP method to handle that HTTP request. So you can think of a Controller as a class that *controls* where your request is going to go. - The request data can come in a variety of different forms - JSON, XML, path variables or query parameters. - Once the request goes to the appropraite Controller method, the Jackson library (part of the spring-boot-starter-web dependency) will **deserialise** (convert the JSON string into an object) the data for us. - Once the object has been deserialised, the controller method can then pass the object to the appropriate service method to handle the request for the client. - Once the Service layer gives back a response, the Controller will **serialise** the response object back into JSON, or XML, and return this back to the client that made the request along with an appropriate HTTP status code. Still with me?πŸ˜‰ I know it's a lot of information, but this is key information that you need to have to understand how Spring will handle your requests! I will make a post to explain this in more depth, as this stuff is important to know if you want to be better than the average Java Spring developer πŸ˜‰. ### Implementing the ReservationController - Create a new package called `controller` within `com.rms.reservationservice`. - Now create an class called `ReservationController`. This will contain all the contoller methods that will let us trigger the Create, Read, Update and Delete flows in the `ReservationService`, based on the HTTP request type and the endpoint provided. ``` package com.rms.reservationservice.controller; import com.rms.reservationservice.service.ReservationService; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/v1/reservation") public class ReservationController { public final ReservationService reservationService; public ReservationController(ReservationService reservationService) { this.reservationService = reservationService; } } ``` - ***@RestController*** - Indicating to Spring that this is a Spring Component, just like `@Service` and `@Repository`. This will allow other Spring beans to be injected into this class. - `@RestController` is also aconvenience annotation that combines `@Controller` and `@ResponseBody` – which eliminates the need to annotate every request handling method of the controller class with the @ResponseBody annotation. - ***@ResponseBody*** - This annotation tells a Controller that the object returned should be automatically serialized back into JSON and sent back to the client. - ***@RequestMapping*** - Tells Spring that to interact with this Controller class, you must provide the following path: `/api/v1/reservation` as a path prefix. So all requests will look like `http://www.example.com/api/v1/reservation` as a minimum. #### So why did we build the ReservationService? πŸ€” To complete our various reservation flows, we need controller methods that will interact with the ReservationService. As such, we can inject the ReservationService dependency into the controller directly, so that we can start to make use of the methods that the interface has to offer. **OH YEAH, IT'S ALL COMIN' TOGETHER NOW!** Let's break each of our flows down one by one: ### Save a New Reservation - ***C***reate When we think of "saving a new reservation", this can also be thought of as "creating a new resource", because at the end of the day, we are taking a reservation request, and when we save it to the database, we are creating a new row in our database table. ***Can you remember which HTTP verb you would use for this type of request?*** That's right! its a **POST** request!πŸ™Œ So lets get this put into code: ``` import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.http.HttpStatus; @PostMapping @ResponseStatus(HttpStatus.CREATED) public Reservation save(@RequestBody Reservation reservation) { return reservationService.saveReservation(reservation); } ``` - ***@PostMapping*** - tells Spring that this method will accept POST requests, which we can use to create a reservation. - ***@RequestBody*** - Jackson will take the incoming JSON request from the client, and will convert this into a Reservation object, which is then passed into the method as an parameter. - This method will take the `reservation` object that has entered the controller, and delegate this to the `reservationService`. Once the save has completed successfully, return back a the new `reservation` object, which will be converted back into JSON and delivered back to the client.(Remember, thats the role of `@ResponseBody`) - ***@ResponseStatus*** - When the request is completed successfully, by default, the client will receive a HTTP status of 200 OK, along with the response body. By providing this annoation, we can decide what the HTTP status code will be when the method is completed successfully and the response is given back to the client. In our case, since we are creating a new resource, why not tell the client when the reservation was created successfully by returning back the JSON and a 201 CREATED response instead! If you did get stuck at any point, please checkout branch [part-5-implementing-POST-save](https://github.com/csapty12/restaurantManagementSystem/tree/part-5-implementing-POST-save) and compare your code against mine. ***We have just created our first full flow of execution!*** πŸŽ‰πŸŽ‰πŸŽ‰πŸŽ‰ Let's try it out! Lets start up our application and lets send a POST request with some reservation data, and lets see a reservation being created. For the demo, let's use the [POSTMAN](https://www.postman.com/) HTTP client: (make sure that you create your request request body in the same way I have before hitting the send button): ![](https://i.imgur.com/UCU5GwW.png) Lets look more at the response given back to us (in the green box) : - We now have an `id` field - a unique ID that lets us identify the reservation - We now have a `duration` field - indicating that since only 2 guests are coming, they can only stay a maximum of 1 hour. - Status 201 Created: rather than the default 200 response, we returned back a 201 as a this indicates a new resource (a reservation) has been created. ### Get an existing Reservation - ***R***ead Imagine a customer has already made a booking and wants to see their reservation that they had made. We want to GET this reservation so that the client can see the reservation. But how can we get the reservation for the customer? We need some unique way of identifying that specific customer booking. ***Can you remember which HTTP verb you would use for retrieve a reservation?*** That’s right! its a GET request! πŸ™Œ Lets get this put into code: ``` import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.http.HttpStatus; @GetMapping("/{reservationId}") @ResponseStatus(HttpStatus.OK) public Reservation get(@PathVariable("reservationId") String reservationId) { return reservationService.getReservationById(reservationId); } ``` - ***@GetMapping*** - tells Spring that this method will accept HTTP **GET** requests, which we can use to get an existing reservation using the `reservationId`. Note, we are passing in a path `/{reservationId}` so the URL would look like `http://localhost:8080/api/v1/reservation/JEBS-12345` . - ***@PathVariable*** - enables you to pass in the `reservationId` as part of the URI. Note, that the path variable name `reservationId` is the same as the name provided in the `@GetMapping` annotion. - Jackson will take this path variable as a String, so that we can accordingly pass it to the reservationService’s `getReservationById()` method. Once we get a response, we return back the Reservation object to the client, with a HTTP status of 200 if successful. If you did get stuck at any point, please checkout branch [part-5-implementing-GET-get](https://github.com/csapty12/restaurantManagementSystem/tree/part-5-implementing-GET-get) and compare your code against mine. Just like the `POST` method, let't give `GET` a try! - When we start the application, we will not have any data to work with, so let's start by saving a new reservation. Follow the steps on saving a new reservation to do this. - Once saved, we will have the reservation `id` which we can use to now fetch the existing reservation from the database - Pass this into the URL as you can see below and assuming the reservationId exists, you will get back the reservation object that was persisted to the database. ![](https://i.imgur.com/OKGUw8K.png) ### Update an existing Reservation - ***U***pdate Imagine a customer has already made a booking, and wants to update their reservation that they had made as the number of people increased from 2 to 9. We want to udpate this reservation with all the new fields so that the RMS has the most relevant information about the customer's reservation. For this, we should use the `PUT` HTTP verb. ``` import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.RequestBody; @PutMapping("/{reservationId}") @ResponseStatus(HttpStatus.OK) public Reservation update(@PathVariable("reservationId") String reservationId, @RequestBody Reservation reservation) { return reservationService.updateReservation(reservationId, reservation); } ``` - ***@PutMapping*** - tells Spring that this method will accept PUT requests, which we can use to update an existing reservation using the reservationId and the @RequestBody provided. If you did get stuck at any point, please checkout branch [part-5-implementing-PUT-update](https://github.com/csapty12/restaurantManagementSystem/tree/part-5-implementing-PUT-update) and compare your code against mine. Again, let's now run our service, save something to it, and then update the reservation with new data: ![](https://i.imgur.com/Gs5GMVV.png) Awesome! So now we have the ability to save new reservations, get them back from the database, as well as update reservations. We have now completed `CRU` out of CRUD! only ***one final step***, having the ability to delete a reservation. ### Deleting an existing Reservation - ***D***elete if a customer needed to cancel their reservation, we should be able to do this, so that other customers can make reservations for that time. The customer would need to provide their `reservationId`, so that we can find the reservation in the database and delete it accordingly. This means we need to use a `DELETE` HTTP request! ``` import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; @DeleteMapping("/{reservationId}") @ResponseStatus(HttpStatus.OK) public void delete(@PathVariable("reservationId") String reservationId){ reservationService.deleteReservation(reservationId); } ``` - ***@DeleteMapping*** - tells Spring that this method will accept DELETE requests, which we can use to delete an existing reservation using the reservationId from the database. - Assuming the record exists, and the reservation can be deleted, then there will be nothing to return back to the client other than a HTTP status of 200 OK. If you did get stuck at any point, please checkout branch [part-5-implementing-DELETE-delete](https://github.com/csapty12/restaurantManagementSystem/tree/part-5-implementing-DELETE-delete) and compare your code against mine. Again, let’s now run our service, save something to it, and then delete the reservation: ![](https://i.imgur.com/TL1VSJf.png) Notice how the response is empty, however we get back a HTTP 200 response, indicating that the operation was successful! # ..AND WE ARE DONE!! πŸŽ‰πŸŽ‰πŸŽ‰πŸŽ‰πŸŽ‰πŸŽ‰πŸŽ‰πŸŽ‰ ***ALrighty!! We are finally done!!!*** Congratulations!! We have successfully implemented a Reservation Management Service, which performs CRUD requests using REST over HTTP. Customers can now finally make and alter reservations as they like, as this is now a full service that can provides business value! You can now go and show this off to all your friends, or use it however you like. That wasn't so hard was it!? You can see how much Spring handles for you so that you do not need to keep re-writing the same boiletplate ~~crap~~ code over and over again, so you can focus on getting your service built and into production. Give yourself a pat on your shoulder, you earnt it! The finalised codebase can be seen in the [FINALISED RMS](https://github.com/csapty12/restaurantManagementSystem/tree/main), and your code should look pretty similar to mine. # What is next? Well, currently, we have implemented all the happy path situations, when everything goes well, however, what happens when you try to perform operations on the database where a customer does not exist? or what happens if you have duplicate ID's? these are things that we need to account for which we have not compelted as yet. In my next guide, this is exactly what we are going to be looking at, so that our service can fail more gracefully, rather than spewing lots of erros and making us sad.