Friday, May 19, 2023

Creating RESTful Services - Cloud Native with Kotlin Spring-Boot

 Creating RESTful Services and Understanding its components

RESTful APIs are present in most modern applications we use every day, from reading Twitter messages or visiting Facebook pages to reading our emails or doing a Google search. With a lightweight communication protocol and an emphasis on resources, states, and verbs, they have become a natural language for the interchange of information through the HTTP protocol. In this blog, we will understand how we can create our own RESTful APIs using Kotlin and the Spring framework. We will learn how we can receive parameters, and how HTTP verbs and status will make our APIs define their ubiquitous language. We spoke about a ubiquitous language in our Domain-Driven Design blog, Understanding Microservices. Furthermore, we will learn how to handle JSON requests and responses in our APIs. And finally, we will review how Spring allows us to handle errors in our microservices.

In this blog, We will learn about: 

RestController 

Request Mapping 

Path Variable 

RequestParam 

Response Entity and Response Body 

Controller Advice

Understanding RestController 

Any RESTful API needs to answer requests coming from their client; these requests are handled in Spring by a controller object. In this section, we will understand what a controller actually is and how the RestController will help us to create our first component in a RESTful API.

What is a controller

Each request coming to a RESTful API is a stateless message that mainly will: Ask for a resource Update a resource Create a resource Delete a resource Those requests will use JSON as the mechanism to interchange information. JavaScript Object Notation (JSON) is a human-readable data format to transmit objects. It is a language-independent data format, but it was derived from JavaScript. Most programming languages include code to generate and parse JSON-format data. Requests in a Spring web application are handled by a controller, a specialized component whose mission is to handle requests from a client and send responses back. Controllers can be used for a variety of communication protocols, but since we are going to do a RESTful API, we will use a RestController. RestController will specify that our controller will handle the request and output a body; this will help us create our responses.

Creating a RestController 

For creating our controller, we will start generating a new Spring Boot Application using Spring Initializr, visiting the website: https://start.spring.io/.To create a new project, we will choose Maven project with Kotlin and Spring Boot 3.1.0 . in Spring Initializr. For the project metadata, we will set a Group com.microservices, and Artifact, and as Dependencies, we will include Web. Now, we will unzip the generated project and open it with IntelliJ IDEA. In the Project window, we will right-click in our package, com.microservices, and we will choose in the drop-down menu, Kotlin File/Class. In the new dialog, we will choose to create a class named CustomerController, and we will write the following code:

package com.microservices

import org.springframework.web.bind.annotation.RequestMapping

import org.springframework.web.bind.annotation.RequestMethod

import org.springframework.web.bind.annotation.ResponseBody

import org.springframework.web.bind.annotation.RestController

 @RestController

class CustomerController {

  @RequestMapping(value = "/customer", method = arrayOf(RequestMethod.GET))

  fun getCustomer() = "hello from a controller"

If we insert in our browser the URL http://localhost:8080/customer, we will get a message saying"hello from a controller". Since RESTful services are about returning resources, let's create a class that represents a resource, for example, a customer creating a class named Customer: 

package com.microservices

 data class Customer(var id: Int = 0, var name: String = "")

 Understanding our controller 

 In our example, we have created a controller using the Spring annotation @RestController. This controller will be picked up by the component scan, at the application startup and will be added to our Spring context as a bean, Getting Started with Spring Boot 3.1.0. In this controller, we have set a mapping using @RequestMapping, for the URL /customer, to accept GET requests. Since it is a RestController , the response will output as a JSON Object. This mapping will be autoconfigured by Spring Boot and wired into our web application. If we check our application log when we start the microservice, we can see, among other messages.When everything is up and running for each request to the mapped URL, our method will be executed and a new instance of the Customer object will be created and converted to JSON to be sent back as a response to the request.

 Path and request parameters 

 Now that we have an understanding of how we can return data in a controller, we should learn how we can ask for a particular resource so we can filter the information and return it as a response. In RESTful APIs, when an application invokes our services for a particular resource, it will query through the URL path, the desired information to be returned. For example, if an application invokes our API with the URL /customer/1, it is indicating that the resource that has been queried is a particular customer 1 in this example. But RESTful APIs also allow us to extend a request further providing additional information through parameters. An application could invoke our API using the URL /customers, indicating the need to receive the customer list. But that URL could provide an additional parameter to specify a filter, for example, to search customers by name giving the URL /customers?nameFilter="lin". We should never filter the resource that's been requested through request parameters. In RESTful APIs, this is always done through path variables.

 Understanding path variables

Spring has mapped our new URL to receive a parameter. We have specified that its name will be an id using curly braces on the URL, /customer/{id} in our example.

Then, we will create an argument for our method getCustomer that is named exactly id, and we have annotated this method with the annotation @PathVariable and will specify its type to be an Int. When Spring is autoconfiguring our controller, we will understand this annotation and will map the value pass in the URL to the value required to our method, and it will convert it to the right data type specified. This is a very powerful feature that allows us to easily do mapping on path variables in our methods without requiring any kind of configuration.

Understanding request parameters 

In RequestMapping, we do not define parameters using the URL as we did in path variables. We declared them as parameters in our functions and annotated with the @RequestParam annotation. In the annotation, we can specify if the parameter is a required parameter, and if it has a default value, so if it is not present, that value will get injected in our mapping method. The default value must always be a string, and Spring will convert it back to any other type automatically. We can define as many parameters as we like, and they will be separated with and in the URL. With this last addition, we can start to create more flexible APIs that will handle those parameters to tweak our functionality. Be cautious about how many parameters we use, and what they are for. If you are starting to make an API behave really differently because of something in the parameters, it could be an indication that a different API may be required.

HTTP verbs and statuses 

In RESTful APIs, we use standard HTTP verbs to indicate what we need to do with a particular resource. These verbs define what the client needs to do, but we need to answer in our microservice what response we give back. For example, when a client asks for a specific customer using the URL http://localhost:8080/customer/1 with the HTTP verb GET, we can answer back with a status 200 OK, or with a 404 NOT FOUND, if we don't find the customer. This two-way communication becomes part of a conversation between the client and the API and will form our ubiquitous language.

Standard HTTP verbs and statuses 

In RESTful APIs, HTTP verbs and statuses are very flexible, and our application can decide how to use them, but there are a set of standard and well-known patterns to combine them.

Single resources 

Considering that we are using an API that provides a resource through a URL, for example /customer, we can use:

URL =/customer/1, Verb=GET , Status=200 OK , Meaning=We asked for a specific customer, and got back the result

URL =/customer/1 , Verb=GET ,Status=404 NOT FOUND ,Meaning=We asked for a specific customer, but they could not be found

URL=/customer ,Verb=POST ,Status=201 CREATED ,Meaning=We asked to create a new customer, and it was created

URL=/customer ,Verb=POST ,Status=400 BAD REQUEST ,Meaning=We asked to create a new customer, but the data was not correct

URL=/customer/1 ,Verb=PUT ,Status=202 ACCEPTED ,Meaning=We asked to update a customer, and it was updated correctly 

URL=/customer/1 ,Verb=PUT ,Status=404 NOT FOUND ,Meaning=We asked to update a customer, but the customer was not found 

URL=/customer/1 ,Verb=DELETE ,Status=200 OK ,Meaning=We asked to delete a customer, and we did it correctly 

URL=/customer/1 ,Verb=DELETE ,Status=404 NOT FOUND ,Meaning=We asked to delete a customer, but it could not be found

Collections 

If we are using an API to provide a collection of resources, for example, a list of customers giving the URL/customers, we can use:

  /customers/ GET 200 OK We asked for a list of customers and got back the result 

  /customers/ GET 204 NO CONTENT We asked for a list of customers, and there was none 

  /customers/?name=son GET 200 OK We asked for a list of customers filtering the results 

  /customers/?name=son GET 204 NO CONTENT The filtering of customers returned no results

  /customers/?name=# GET 400 BAD REQUEST The filtering for customers was incorrect

Note : Follow this blog for code https://androidcodingworld.blogspot.com/2023/05/spring-boot-application-structure.html

No comments: