Monday, October 12, 2020

RESTful APIs with Kotlin, Spring Boot, MySQL, JPA and Hibernate Example


Kotlin has gained a lot of popularity in recent times due to its productivity features and a first class support in Android.

Owing to the increasing popularity of Kotlin, Spring framework 5 has also introduced a dedicated support for Kotlin in Spring applications.

In this article, You’ll learn how to build a Restful CRUD API with Kotlin and Spring Boot 2.x, which is based on Spring framework 5.

So Stay tuned!

In this blog post, we’ll build Restful APIs for a mini blog application. The blog has a list of Articles. We’ll write APIs for creating, retrieving, updating and deleting an Article. An Article has an id, a title and some content.

We’ll use MySQL as our data source and JPA & Hibernate to access the data from the database.

All right, Let’s now create the application.

Creating the Application

We’ll use Spring initializr web tool to bootstrap our application. Follow the steps below to generate the application :

  1. Go to http://start.spring.io
  2. Select Kotlin in the language section.
  3. Enter Artifact as kotlin-demo
  4. Add WebJPA, and MySQL dependencies.
  5. Click Generate to generate and download the project.
Kotlin Spring Boot Restful CRUD API Example

Once the project is generated, unzip it and import it into your favorite IDE. Here is the Project’s directory Structure for your reference.

Kotlin Spring Boot Restful CRUD API Example Directory Structure

Configure MySQL

We’ll need to configure MySQL database url, username, and password so that Spring Boot can create a Data source.

Open src/main/resources/application.properties file and add the following properties to it :

## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://localhost:3306/kotlin_demo_app?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
spring.datasource.username = root
spring.datasource.password = root


## Hibernate Properties

# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect

# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update

Please don’t forget to change spring.datasource.username and spring.datasource.password as per your MySQL installation.

Note that, I’ve set spring.jpa.hibernate.ddl-auto property to update. This property updates the database schema whenever you create or modify the domain models in your application.

Creating the Domain Model

Let’s now create the Article domain entity. Create a new package called model inside com.example.kotlindemo package, and then create a new Kotlin file called Article.kt with the following contents -

package com.example.kotlindemo.model

import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
import javax.validation.constraints.NotBlank

@Entity
data class Article (
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0,

    @get: NotBlank
    val title: String = "",

    @get: NotBlank
    val content: String = ""
)

The Entity class is so small and concise, right? That’s because A Kotlin class doesn’t need getters and setters like Java. Moreover, I have used a data class here. A data class automatically generates equals()hashcode()toString() and copy() methods.

Note that, I’ve assigned a default value for all the fields in the Article class. This is needed because Hibernate requires an entity to have a no-arg constructor.

Assigning default values to all the member fields will let hibernate instantiate an Article without passing any argument. It Works because Kotlin supports Default Arguments :).

Creating the Repository

Let’s now create the repository for accessing the data from the database. First, create a package called repository inside com.example.kotlindemo package, and then create a Kotlin file named ArticleRepository.kt with the following contents -

package com.example.kotlindemo.repository

import com.example.kotlindemo.model.Article
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository

@Repository
interface ArticleRepository : JpaRepository<Article, Long>

That’s all we need to do here. Since we’ve extended ArticleRepository from JpaRepository interface, all the CRUD methods on Article entity is readily available to us. Spring boot automatically plugs-in a default implementation of JpaRepository called SimpleJpaRepository at runtime.

Creating the controller End-points

Finally, Let’s create the controller end-points for all the CRUD operations on Article entity.

First, create a new package called controller inside com.example.kotlindemo package and then create a new kotlin file called ArticleController.kt inside controller package with the following contents -

package com.example.kotlindemo.controller

import com.example.kotlindemo.model.Article
import com.example.kotlindemo.repository.ArticleRepository
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import java.util.*
import javax.validation.Valid

@RestController
@RequestMapping("/api")
class ArticleController(private val articleRepository: ArticleRepository) {

    @GetMapping("/articles")
    fun getAllArticles(): List<Article> =
            articleRepository.findAll()


    @PostMapping("/articles")
    fun createNewArticle(@Valid @RequestBody article: Article): Article =
            articleRepository.save(article)


    @GetMapping("/articles/{id}")
    fun getArticleById(@PathVariable(value = "id") articleId: Long): ResponseEntity<Article> {
        return articleRepository.findById(articleId).map { article -> 
            ResponseEntity.ok(article)
        }.orElse(ResponseEntity.notFound().build())
    }

    @PutMapping("/articles/{id}")
    fun updateArticleById(@PathVariable(value = "id") articleId: Long,
                          @Valid @RequestBody newArticle: Article): ResponseEntity<Article> {

        return articleRepository.findById(articleId).map { existingArticle ->
            val updatedArticle: Article = existingArticle
                    .copy(title = newArticle.title, content = newArticle.content)
            ResponseEntity.ok().body(articleRepository.save(updatedArticle))
        }.orElse(ResponseEntity.notFound().build())

    }

    @DeleteMapping("/articles/{id}")
    fun deleteArticleById(@PathVariable(value = "id") articleId: Long): ResponseEntity<Void> {

        return articleRepository.findById(articleId).map { article  ->
            articleRepository.delete(article)
            ResponseEntity<Void>(HttpStatus.OK)
        }.orElse(ResponseEntity.notFound().build())

    }
}

The controller defines APIs for all the CRUD operations. I have used Kotlin’s functional style syntax in all the methods to make them short and concise.

Running the Application

You can run the application by typing the following command in the terminal -

mvn spring-boot:run

The application will start at Spring Boot’s default port 8080.

Exploring the Rest APIs

1. POST /api/articles - Create an Article

curl -i -H "Content-Type: application/json" -X POST \
-d '{"title": "How to learn Spring framework", "content": "Resources to learn Spring framework"}' \
http://localhost:8080/api/articles

# Output
HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 06 Oct 2017 03:25:59 GMT

{"id":1,"title":"How to learn Spring framework","content":"Resources to learn Spring framework"}

2. GET /api/articles - Get all Articles

curl -i -H 'Accept: application/json' http://localhost:8080/api/articles

# Output
HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 06 Oct 2017 03:25:29 GMT

[{"id":1,"title":"How to learn Spring framework","content":"Resources to learn Spring framework"}]

3. Get /api/articles/{id} - Get an Article by id

curl -i -H 'Accept: application/json' http://localhost:8080/api/articles/1

# Output
HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 06 Oct 2017 03:27:51 GMT

{"id":1,"title":"How to learn Spring framework","content":"Resources to learn Spring framework"}

4. PUT /api/articles/{id} - Update an Article

curl -i -H "Content-Type: application/json" -X PUT \
-d '{"title": "Learning Spring Boot", "content": "Some resources to learn Spring Boot"}' \
http://localhost:8080/api/articles/1

# Output
HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 06 Oct 2017 03:33:15 GMT

{"id":1,"title":"Learning Spring Boot","content":"Some resources to learn Spring Boot"}

5. DELETE /api/articles/{id} - Delete an Article

curl -i -X DELETE http://localhost:8080/api/articles/1

# Output
HTTP/1.1 200 
Content-Length: 0
Date: Fri, 06 Oct 2017 03:34:22 GMT

Conclusion

That’s all folks! In this article, You learned how to use Kotlin with Spring Boot for building restful web services.

You can find the entire code for the application that we built in this article in my github repository. Consider giving a star on github if you find the project useful.

Thank you for reading folks! See you next time :)


Reference :


Friday, March 20, 2020

How to Read HTTP Headers in Spring REST Controllers


1. Introduction

In this quick tutorial, we're going to look at how to access HTTP Headers in a Spring Rest Controller.
First, we'll be using the @RequestHeader annotation to read headers individually as well as all together. After that, we'll take a deeper look at the @RequestHeader‘s attributes.

2. Accessing HTTP Headers

2.1. Individually

If we need access to a specific header, we can configure @RequestHeader with the header name:
1
2
3
4
5
@GetMapping("/greeting")
public ResponseEntity<String> greeting(@RequestHeader("accept-language") String language) {
    // code that uses the language variable
    return new ResponseEntity<String>(greeting, HttpStatus.OK);
}
Then, we can access the value using the variable passed into our method. If a header named accept-language isn't found in the request, the method returns a “400 Bad Request” error.
Our headers don't have to be strings. For example, if we know our header is a number, we can declare our variable as a numeric type:
1
2
3
4
5
@GetMapping("/double")
public ResponseEntity<String> doubleNumber(@RequestHeader("my-number") int myNumber) {
    return new ResponseEntity<String>(String.format("%d * 2 = %d",
      myNumber, (myNumber * 2)), HttpStatus.OK);
}

2.2. All at Once

If we're not sure which headers will be present, or we need more of them than we want in our method's signature, we can use the @RequestHeader annotation without a specific name.
We have a few choices for our variable type: a Map, a MultiValueMap or a HttpHeaders object.
First, let's get the request headers as a Map:
1
2
3
4
5
6
7
8
9
10
@GetMapping("/listHeaders")
public ResponseEntity<String> listAllHeaders(
  @RequestHeader Map<String, String> headers) {
    headers.forEach((key, value) -> {
        LOG.info(String.format("Header '%s' = %s", key, value));
    });
    return new ResponseEntity<String>(
      String.format("Listed %d headers", headers.size()), HttpStatus.OK);
}
If we use a Map and one of the headers has more than one value, we'll get only the first value.  This is the equivalent of using the getFirst method on a MultiValueMap.
If our headers may have multiple values, we can get them as a MultiValueMap:
1
2
3
4
5
6
7
8
9
10
11
@GetMapping("/multiValue")
public ResponseEntity<String> multiValue(
  @RequestHeader MultiValueMap<String, String> headers) {
    headers.forEach((key, value) -> {
        LOG.info(String.format(
          "Header '%s' = %s", key, value.stream().collect(Collectors.joining("|"))));
    });
         
    return new ResponseEntity<String>(
      String.format("Listed %d headers", headers.size()), HttpStatus.OK);
}
We can also get our headers as an HttpHeaders object:
1
2
3
4
5
6
@GetMapping("/getBaseUrl")
public ResponseEntity<String> getBaseUrl(@RequestHeader HttpHeaders headers) {
    InetSocketAddress host = headers.getHost();
    String url = "http://" + host.getHostName() + ":" + host.getPort();
    return new ResponseEntity<String>(String.format("Base URL = %s", url), HttpStatus.OK);
}
The HttpHeaders object has accessors for common application headers.
When we access a header by name from a MapMultiValueMap or the HttpHeaders object, we'll get a null if it isn't present.


3. @RequestHeader Attributes

Now that we've gone over the basics of accessing request headers with the @RequestHeader annotation, let's take a closer look at its attributes.
We've already used the name or value attributes implicitly when we've specifically named our header:
1
public ResponseEntity<String> greeting(@RequestHeader("accept-language") String language) {}
We can accomplish the same thing by using the name attribute:
1
2
public ResponseEntity<String> greeting(
  @RequestHeader(name = "accept-language") String language) {}
Next, let's use the value attribute exactly the same way:
1
2
public ResponseEntity<String> greeting(
  @RequestHeader(value = "accept-language") String language) {}
When we name a header specifically, the header is required by default. If the header isn't found in the request, the controller returns a 400 error.
Let's use the required attribute to indicate that our header isn't required:
1
2
3
4
5
6
7
@GetMapping("/nonRequiredHeader")
public ResponseEntity<String> evaluateNonRequiredHeader(
  @RequestHeader(value = "optional-header", required = false) String optionalHeader) {
    return new ResponseEntity<String>(String.format(
      "Was the optional header present? %s!",
        (optionalHeader == null ? "No" : "Yes")),HttpStatus.OK);
}
Since our variable will be null if the header isn't present in the request, we need to be sure to do the appropriate null checking.
Let's use the defaultValue attribute to provide a default value for our header:
1
2
3
4
5
6
@GetMapping("/default")
public ResponseEntity<String> evaluateDefaultHeaderValue(
  @RequestHeader(value = "optional-header", defaultValue = "3600") int optionalHeader) {
    return new ResponseEntity<String>(
      String.format("Optional Header is %d", optionalHeader), HttpStatus.OK);
}

4. Conclusion

In this short tutorial, we learned how to access request headers in Spring REST controllers. First, we used the @RequestHeader annotation to supply request headers to our controller methods.
After a look a the basics, we took a detailed look at the attributes for the @RequestHeader annotation.
The example code is available over on GitHub.

Reference: