Creating a REST API using Spring Boot + Tests + Documentation [part 02]
Tags: webdev, java, springboot, spring
Published: 2023-02-01 18:16:29

Hi!

I'm back in this tutorial to teach you how to develop a REST API using Spring Boot. As I said earlier, this tutorial is divided into 5 parts as shown in the following table:


|   **Part**  |        **Content**        |
|:-----------:|:-------------------------:|
|   Part 01   |    [Application Startup](https://dev.to/franciscotis/creating-a-rest-api-using-spring-boot-tests-documentation-part-01-2262)    |
| **Part 02** | **Settings and Database** |
|   Part 03   |     [API Implementation](https://dev.to/franciscotis/creating-a-rest-api-using-spring-boot-tests-documentation-part-03-1m5e)    |
|   Part 04   |      [Tests + Coverage](https://dev.to/franciscotis/creating-a-rest-api-using-spring-boot-tests-documentation-part-04-4190)     |
|   Part 05   |   [Swagger Documentation](https://dev.to/franciscotis/creating-a-rest-api-using-spring-boot-tests-documentation-part-05-1pd6)   |

---

It is expected that from this second part you will learn the following:

- How to create the system routes
- How to view the system through user stories
- How to view the system through ER diagram
- How to create the database
- How to integrate the database with the system
- How to create migrations using `flyway`
- How to create DAO classes
- How to create a repository to interact with the database
- How to create DTO records

Remember that in this tutorial the following tools are used:

- JDK 17
- IntelliJ
- Maven
- Insomnia
- MySQL database

---

## **Step 01 - Creating routes**

In the [first part](https://dev.to/franciscotis/creating-a-rest-api-using-spring-boot-tests-documentation-part-01-2262) of the tutorial we created the project using _Spring Initializr_ and ran the server. It turns out that when accessing the URL http://localhost:8080 we come across the following response:

```

{
	"timestamp": "2023-01-31T18:08:42.607+00:00",
	"status": 404,
	"error": "Not Found",
	"message": "No message available",
	"path": "/"
}

```


This response, as shown earlier, appears because we have not defined any route for our application.

So let's create our route!

Inside the `src.main.java.com.simplelibrary.simplelibrary.API` package we will create a new package called `controller`. Inside it, we will store the _Controllers_ of the system.

> Inside a controller we will have the mapping of our application's routes. Thus, when defining a route, such as "/test", when the user accesses the url http://localhost:8080/test, he will no longer find the response seen above.

The class that we will create in this controller will have the following code:

```
package com.simplelibrary.simplelibraryAPI.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("test")
public class SimpleRouteController {

    @GetMapping
    public ResponseEntity test(){
        return ResponseEntity.ok("it works!");
    }
}

```

In the first lines we see some imports that are necessary for the project. Also note that some **annotations** are used, such as `@RequestController`.

According to Spring's own documentation, this annotation means that:

> [...] Marks the class as a controller where every method returns a domain object instead of a view.

The next annotation, `RequestMapping("test")` indicates that all requests that have the /test mapping will be handled in this class. 

The `@GetMapping` annotation indicates that the method below it will handle a **get** type request. That is, if the user accesses the URL http://localhost:8080/test (using the HTTP GET method), the method below will be called. The method itself is `test`:

```
@GetMapping
    public ResponseEntity test(){
        return ResponseEntity.ok("it works!");
    }

```

> If you want to know more about HTTP methods, you can visit these links: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods, https://www.w3schools.com/tags/ref_httpmethods.asp

As shown, the method returns an object of type `ResponseEntity`. This class represents an HTTP return, where we can also insert the return codes (2xx, 4xx, 5xx...).

> If you want to know more about HTTP response codes, you can visit this link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status

The `ResponseEntity` class already carries the possible HTTP response codes. In our case we are using the return **ok** which is indicated by the code **200**. From this return, you can insert a body containing a message. In this case we are returning it works!".

Now when performing a GET request for the URL http://localhost:8080/test we get the following response:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/og8dvlyub45swiehfvlr.png)


---

## **Step 02 - User stories**

Now that we know how to create a route, we can now see our system's scenarios from the user's point of view.

> 1. **As a user**, I would like to register books in the system by registering the following information: **id, title, author, number of pages, isbn, evaluation, status (finished or not)**. I would also like that the evaluation of the book should be obtained automatically from the page of this book on the site http://skoob.com.br.
> 2. **As a user**, I would like to get all the books registered in the system through pagination. Having only 10 books per page and sorting by title.
> 3. **As a user**, I would like to obtain information of only one book, identified by its id.
> 4. **As a user**, I would like to update the information of a book, identified by its id.
> 5. **As a user**, I would like to delete a book based on its id.

---

## **Step 03 - System modeling**

From the specifications presented above, we can model our system:


![ER Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2avk8exymzkbylsbbcc2.png)

As you can see from the entity-relationship diagram, we will only have a single table in the database called `Book` and it will contain the following columns:

- id (primary key)
- title
- author
- pages
- isbn (unique)
- rate (nullable)
- finished

Only the rate column can have a null value.

---

## **Step 04 - Creating the database**

In this tutorial I will not be focusing on installing the database on your machine. On my machine I'm using a Docker container that contains the MySQL database.

Our database will be called `small_library`. So, to create the database you can run the following command in SQL:

```

create database small_library;
use small_library;

```

By doing this, your database will be created and ready for use in the application.

---

## **Step 05 - Integration of the database with the system**

Once your database is ready, we can add some dependencies to the project that will help us connect the system to the database and perform some manipulations. Therefore, in your `pom.xml` file you can add the following dependencies between the `<dependencies>` and `</dependencies>` tags:

```
<!-- ... -->

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-validation</artifactId>
   </dependency>
   <dependency>
      <groupId>org.flywaydb</groupId>
      <artifactId>flyway-core</artifactId>
   </dependency>
   <dependency>
      <groupId>org.flywaydb</groupId>
      <artifactId>flyway-mysql</artifactId>
   </dependency>
   <dependency>
      <groupId>com.mysql</groupId>
      <artifactId>mysql-connector-j</artifactId>
      <scope>runtime</scope>
   </dependency>

<!-- ... -->


```

The following dependencies are being added:

- **Flyway Migration**: from it, we can create migrations for the database.
- **MySQL Driver**: is the driver that will allow the connection between our server and the MySQL database
- **Spring Data JPA**: from it we can persist data in the database from entities.
- **Validation**: it is the validation service that we will use to verify that the data arriving at the server is in accordance with the established validation rules.

After that, you can reload the Maven dependencies. When running your application, the terminal will display the following message:

![Terminal error](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8uzn3xhlik9vd8xyuklm.png)

This message means that you have added the database dependencies on the system but have not added any connection properties. That is, Spring is trying to fetch the connection URL, the username and password to connect, but it is not finding it.

To change that, I recommend you close the server, and go to the `application.properties` file inside `resources` and add the following:

```
spring.datasource.url=jdbc:mysql://localhost:3307/small_library
spring.datasource.username=root
spring.datasource.password=root

```

In the `spring.datasource.url` tag, we inform you the URL to access your database. In my case, I'm using the mysql database and it's running on port **3307**.

Finally, in the `spring.datasource.username` and `spring.datasource.password` tags we inform the database user name and password, respectively. In my case, I fill both with **root**.

By doing this we can start the server again and it will run successfully

---

## **Step 06 - Creating migrations**

Now that we have successfully connected to the database, we can now create the scripts to create our **books** table. For the versioning of these scripts, we will be using the migrations system that is provided from the `flyway` dependency.

For those who don't know, a migration is a versioned sql script that allows you to add or modify a table in the database. This versioning is important to have a control of the modifications that are made in the database.

**Flyway** documentation can be found at this link [here](https://flywaydb.org/documentation).

In Spring Boot, migrations are inside the `resources.db.migration` folder and each script must be saved with the following name:

`<Prefix><Version>__<Description>.sql`

- Usually in the **prefix** we insert the letter **V**, meaning **version**.
- In the version, we insert the version number, starting with 1 (and it will be incremented with each new script).
- And in the description we insert what we are doing in that script.

We can create the following migration:

`V1__create-table-books.sql`

And inside of it the following script:

```

create table books(
      id bigint not null auto_increment,
      title varchar(100) not null,
      author varchar(100) not null,
      pages int not null,
      isbn varchar(100) not null unique,
      finished tinyint not null,
      rate float,

      primary key(id)
);

```

**NOTE: It is highly recommended that you stop the server before creating a migration to avoid any problems**.

When creating the migration, we can start the server and it will automatically run the migration, creating the table in the database:

![Migration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/36cslwnd5ebgjnyk35f7.png)


![Tables in the database](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/psggyjdm95yqej2p2ys3.png)

Note that in addition to the `books` table, the `flyway_schema_history` table was also created. This table will store all migrations that have already been run and what is the current version of the system.

---

## **Step 07 - Creating the DAO class**

So far we have made all the necessary configurations in the database. We can now create our DAO class that will help us access the data in the database.

Therefore, inside the `src.main.java.com.simplelibrary.simplelibrary.API` package we will create a new package called `model`. And inside this, we create a class called `Book`:

```
package com.simplelibrary.simplelibraryAPI.model;
import jakarta.persistence.*;
import lombok.*;
@Table(name = "books")
@Entity(name = "Book")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = "id")
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String author;
    private Integer pages;
    private String isbn;
    private Double rate;
    private Boolean finished;

}

```

At first, the amount of `Annotations` can be daunting, but it is very easy to understand:

- @Table(name = "books") refers to the table in the database that this class references. As we created the `books` table, we put this value.

- @Entity(name = "Book") refers to the name of the DAO class - telling the Spring that it is an entity.

- @Getter is a **lombok** annotation to generate `getters` methods for all attributes of the class.

- @Setter is a **lombok** annotation to generate the `setters` methods of all attributes of the class.

- @NoArgsConstructor is a **lombok** annotation to generate the class constructor method with no arguments: `public Book();`

- @AllArgsConstructor is a **lombok** annotation to generate the constructor method of the class with all the attributes of the class present in the arguments: `public Book(Long id, String title, String author, Integer pages, String isbn, Double rate, Boolean finished );`

- @EqualsAndHashCode(of = "id") is a **lombok** annotation to generate equals method and hashCode generator using id as parameter.

Finally, we can also add what are the attributes of the class. We will use the columns present in the database as a reference.

**Note: It is important to add the annotations `@Id` and `@GeneratedValue(strategy = GenerationType.IDENTITY)` before the declaration of the id attribute to inform that this attribute is an identifier.**

---

## **Step 07 - Creating the repository**

We previously created our DAO class. Now it is necessary to have a way to get the data from the database - this will be done through the repositories. A repository is an interface that inherits from the `JpaRepository` class. From it, we can perform manipulations on the database, considering a previously created DAO class.

To create the repository, we have to go inside the `src.main.java.com.simplelibrary.simplelibrary.API` package and create a new package called repository. And inside this, we create an interface called `BookRepository`:

```

package com.simplelibrary.simplelibraryAPI.repository;

import com.simplelibrary.simplelibraryAPI.model.Book;
import org.springframework.data.jpa.repository.JpaRepository;

public interface BookRepository extends JpaRepository<Book, Long> {

}


```

Only that! When doing the inheritance, we have to specify which entity it will use to get the data. In this case, it is the `Book` entity. We also have to specify what the type of the primary key is (in this case it is Long).

---

## **Step 08 - Thinking about input and output data**

We are just a few steps away from finishing the implementation of our CRUD. Now is a good time to start thinking about how the data will arrive in our application and how we would like to return it to the user.

In previous steps, some system scenarios that we must implement were presented. One of them was the following:

> **As a user**, I would like to register books in the system by registering the following information: **id, title, author, number of pages, isbn, evaluation, status (finished or not)**. I would also like that the evaluation of the book should be obtained automatically from the page of this book on the site http://skoob.com.br.

We know that the identifier code (id) will be generated automatically by the system and that the evaluation of the book will be obtained through the website. Therefore, we expect that to register a book in the system, the user must inform the following fields:

- Title
- Author
- Number of Pages
- ISBN
- Finished

Therefore, we can create a class that will be used for data transfer (DTO - Data Transfer Object). We'll go into the `src.main.java.com.simplelibrary.simplelibrary.API` package and create a new package called `dto`. And inside this, we create a record called `BookRequestDTO`:

```
package com.simplelibrary.simplelibraryAPI.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

public record BookRequestDTO(
        @NotBlank
        String title,
        @NotBlank
        String author,
        @NotNull
        Integer pages,
        @NotBlank
        String isbn,
        @NotNull
        Boolean finished
) {

}

```

For those who are not familiar, a record is an immutable type of class, that is, from the moment we create an object and fill in its data, these will not be changed. Your _getters_ methods are created automatically.

Note that there are some annotations that were not explained earlier. As is the case with `@NotBlank` and `@NotNull`. These annotations are used for input validation. By default, we don't want any of our fields to be empty, so we add the `@NotBlank` annotation before Strings (which checks if the String is empty or null) and `@NotNull` before other classes.

When adding this validation, if the user fails to send a field, he will see a message informing the problem.


Alright, we made the record for the request, now we are going to make a new record for the response. That is, we will treat the data that will be sent to the user:

```

package com.simplelibrary.simplelibraryAPI.dto;

import com.simplelibrary.simplelibraryAPI.model.Book;

public record BookResponseDTO(String title, String author, Integer pages, String isbn, Double rate, Boolean finished) {
    public BookResponseDTO(Book book){
        this(book.getTitle(), book.getAuthor(), book.getPages(), book.getIsbn(), book.getRate(), book.getFinished());
    }

}


```

Note that now we will only send the following information to the user:

- Title
- Author
- Number of Pages
- ISBN
- Rate
- Status (finished or not).

A constructor was also created that will fill in your data from our DAO class.

---

## **What we learned in this tutorial**

Well done! So far you have seen how to configure the database and integrate it with the system. You've also learned how to create DAO classes and DTO records for accessing database information and sending data, respectively.

In [part 3](https://dev.to/franciscotis/creating-a-rest-api-using-spring-boot-tests-documentation-part-03-1m5e) we will finish the construction of our REST API. Creating the service which will contain the business rule. And also the rest of the access routes to the system.