[JAVA] Let's write how to make API with SpringBoot + Docker from 0

Introduction

I tried to create a simple API with Spring Boot and Docker. There weren't many articles that explained from 0 at all, so I will make it myself and post it. However, honestly, I have little knowledge about API and Docker, so please point out any mistakes! Also, please forgive me because it is assumed that it will be built on Mac this time.

Production environment

・ OS: Mac ・ DB: MySQL (mariaDB) ・ VM: Docker ・ Language: Spring Boot (Java 8) -Build tool: Maven

Installation of each tool

Docker installation

https://docs.docker.com/docker-for-mac/install/ Please download and install from this URL. Docker download method 1.png Dockerインストール方法2.png

Java installation

Download from here http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

This time I am using 1.8.0-181.

Maven installation

Anything in particular regarding the Maven version is fine, but this time I will use 3.5.2. Please refer to here. How to install a specific version of Maven

MySQL installation

I will install it with brew home.

$ brew install mysql

Installation of STS (Spring Tool Suite)

STS (Spring Tool Suite) is an Eclipse-like IDE that includes spring. This time we will use this to create a project. https://spring.io/tools/sts/all Let's install from here.

Now that we have everything we need, we can start production.

Production

Create an API to CRUD an Entity with User (name, email).

The API to create is as follows.

GET / api / users => Get all users (getUsers) GET / api / users / {id} => Get User with id (getUser) POST / api / users => Add User (createUser) PUT / api / users / {id} => User update (updateUser) DELETE / api / users / {id} => Delete User with id (deleteUser)

** Create a project with STS **

file -> new -> Spring Starter Project I will make a project with. This time I will make it with the project name " sampleApi ".

Create a project by selecting jpa, web, lombok, mysql in Spring Initializr.

Preparation

Create Entity, Repository, Service.

Entity

@Data
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private String email;
}

To put it simply, Entity is a place to store the values to be registered / updated in the DB and the values obtained from the DB. The database table to be exchanged with @Table is specified. We will create this table etc. later.

Repository


@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

This Repository is the class that directly communicates with BD.

Service


@Service
@Transactional
public class UserService {
    @Autowired
    UserRepository userRepository;

    public User findUser(Long id){
        return userRepository.findOne(id);
    }

    public List<User> findUsers(){
        return userRepository.findAll();
    }

    public User save(User user) {
        return userRepository.save(user);
    }

    public void delete(Long id) {
        userRepository.delete(id);
    }
}

Business logic processing is performed in this Service class. You receive the value from the controller described below and instruct the Repository to process it.

Controller Create a Controller for exchanging Users. Describe the process corresponding to the HTTP request. If you replace User with the resource name, you can use it for other resources. I did not specify the Response code this time, but if you want to implement it strictly, it may be better to specify it?

@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    UserService userService;

    @RequestMapping(method = RequestMethod.GET)
    public List<User> getUsers() {
        return userService.findUsers();
    }

    @RequestMapping(method=RequestMethod.GET, value="{id}")
    public User getUser(@PathVariable("id") Long id) {
        return userService.findUser(id);
    }

    @RequestMapping(method=RequestMethod.POST)
    public User createUser(@Validated @RequestBody User user) {
        return userService.save(user);
    }

    @RequestMapping(method=RequestMethod.PUT, value="{id}")
    public User updateUser(@PathVariable("id") Long id, @RequestBody User user) {
        user.setId(id);
        return userService.save(user);
    }

    @RequestMapping(method=RequestMethod.DELETE, value="{id}")
    public void deleteUser(@PathVariable("id") Long id) {
        userService.delete(id);
    }

}

@ RestController is an annotation for creating Rest API, and you can exchange with @ Controller + @ ResponseBody + JSON. It handles what spring-boot-starter-web receives and displays in Jackson.

Docker It's docker. I am still ambiguous, so I will write it briefly. First of all, the files "docker-compose.yml" and "Dockerfile" are required to launch the Docker container, so create these two files directly under the project folder.

After creating it, I will write the contents of the file ** First of all, " docker-compose.yml "**


version: '3'
services:
  db:
    image: mariadb:10.2
    restart: always
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_USER: hogeuser
      MYSQL_PASSWORD: password
      MYSQL_DATABASE: sampleapi_development
    ports:
      - "3306:3306"
    volumes:
      - ./docker/tmp/mysql:/var/lib/mysql
      - ./docker/mysql/initdb.d:/docker-entrypoint-initdb.d
volumes:
  data:
    driver: local

It is a description to start the database server. It also creates a database when you start the server. That is here


MYSQL_ROOT_PASSWORD: password
MYSQL_USER: hogeuser
MYSQL_PASSWORD: password
MYSQL_DATABASE: sampleapi_development

From the top, it is the password for root privileges, the server user name, password, and database name.

** Then " Dockerfile "**


FROM openjdk:jdk-alpine
VOLUME /tmp
RUN mkdir /app
WORKDIR /app
ENV JAVA_OPTS=""
ENV JAR_TARGET "sampleApi-1.0.0-SNAPSHOT.jar"
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar build/libs/sampleApi-1.0.0-SNAPSHOT.jar" ]

Regarding docker-compose.yml, I think that it works by copying, but for Dockerfile, it is necessary to change "sampleApi-1.0.0-SNAPSHOT.jar" of ʻENV and ʻENTRY POINT a little. This is a description that targets the jar file generated when the project is built, but the file name generated by the project will be different. Please rewrite it referring to the following.

I think there is "pom.xml" in the project, so it's in it


<artifactId>sampleApi</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>

I think there is such a description. As you can see, look at the contents of this "ʻartifactId", " version"and"packeging`" and rewrite it.

Next, fill in the contents of "ʻapplication.properties`". The file here is in "src / main / resources". Fill in the following:


spring.datasource.url=jdbc:mysql://localhost:3306/sampleapi_development
spring.datasource.username=hogeuser
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

This is what you need to connect the project and the database, and describes the user name and database name created in "docker-compose.yml" above.

Now that the creation is complete, we will actually start it. First, use the command to move to just below the project.

$ cd ~/sampleApi

Let's start Docker. Type in the following:

$ docker-compose up --build

If there are no errors, it is successful.

Now let's launch the application. I thought, but I haven't created the contents (table) of the database yet, so I will create it. You need to go inside the database server launched by Docker. First, type the following to check the server name.


$ docker-compose ps
     Name                   Command             State           Ports          
------------------------------------------------------------------------------
sampleapi_db_1   docker-entrypoint.sh mysqld   Up      0.0.0.0:3306->3306/tcp 

Now that you know the server name, let's enter.


$ docker exec -it sampleapi_db_1 bash
root@c71a21817893:/# mysql -h localhost -P 3306 -u hogeuser -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 20
Server version: 10.2.16-MariaDB-1:10.2.16+maria~bionic mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>  

Check if the database has been created.


MariaDB [(none)]> show databases;
+-----------------------+
| Database              |
+-----------------------+
| information_schema    |
| sampleapi_development |
+-----------------------+
2 rows in set (0.06 sec)

MariaDB [(none)]> 

There is no problem

Let's make a table.

Click here for create statement

CREATE TABLE users ( id int NOT NULL AUTO_INCREMENT, name varchar(255) NOT NULL, email varchar(255) NOT NULL, PRIMARY KEY (id) ); However, I don't think it can be done as it is, so it is necessary to switch the database. Let's switch and create with the following command.


//Database switching
MariaDB [(none)]> use sampleapi_development;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [sampleapi_development]> CREATE TABLE users (
    ->     id int NOT NULL AUTO_INCREMENT,
    ->     name varchar(255) NOT NULL,
    ->     email varchar(255) NOT NULL,
    ->     PRIMARY KEY (id)
    -> );
Query OK, 0 rows affected (0.02 sec)

MariaDB [sampleapi_development]> INSERT INTO users(id, name, email) VALUES(1, 'ishii', '[email protected]');
Query OK, 1 row affected (0.01 sec)

Since it is easier to understand if there is data, I added it with an INSERT statement.

Launch application

Now that the contents have been created, let's start the app. Open STS and right click on the project. Run as → Spring Boot App Let's start.

Check if the API is working.

$ curl localhost:8080/api/users
[{"id":1,"name":"ishii","email":"[email protected]"}]

You can get it properly

I will add a user

$ curl -XPOST -H "Content-Type:application/json" http://localhost:8080/api/users -d '{
  "name":"ishii2","email":"[email protected]"
}'
{"id":2,"name":"ishii2","email":"[email protected]"}

No problem!

By the way, how to drop docker

$ docker-compose down

You can drop it by doing. It is recommended to drop docker properly after playing.

Finally

When it comes to databases, I think it's really better to use migration. However, this time I am trying to create data directly because I was not able to chase so much and the article became bloated. I wish I could write around here as well.

Referenced site

・ API construction https://ishiis.net/2016/09/08/spring-boot-rest-api/ ・ Docker https://qiita.com/ken0909/items/a3f8594ce677bbc7c4c2 ・ Access the DB in the docker app https://qiita.com/M_Nagata/items/120831bb4e4a3deace13


The above is how to make an API with Docker + Spring that I made and saw. It's an ugly article, but thank you for watching it to the end. I'm currently studying rails, so I hope I can write an article about it in the future.

Recommended Posts

Let's write how to make API with SpringBoot + Docker from 0
How to make Laravel faster with Docker for Mac
Update MySQL from 5.7 to 8.0 with Docker
How to start Camunda with Docker
How to share files with Docker Toolbox
[Rails] How to use rails console with docker
[SpringBoot] How to write a controller test
How to run Blazor (C #) with Docker
How to build Rails 6 environment with Docker
Make SpringBoot1.5 + Gradle4.4 + Java8 + Docker environment compatible with Java11
How to get a heapdump from a Docker container
How to make Spring Boot Docker Image smaller
Setting to exit from Docker container with VScode
How to use Java API with lambda expression
How to give your image to someone with docker
How to write test code with Basic authentication
How to build API with GraphQL and Rails
How to use docker compose with NVIDIA Jetson
How to get resource files out with spring-boot
How to use nginx-ingress-controller with Docker for Mac
[Rails] How to build an environment with Docker
How to write Rails
How to install Docker
How to write dockerfile
How to make shaded-jar
How to write docker-compose
How to write Mockito
How to write migrationfile
How to make batch processing with Rails + Heroku configuration
How to make a factory with a model with polymorphic association
How to build Docker + Springboot app (for basic learning)
How to write Scala from the perspective of Java
How to deploy to Heroku from a local docker image
How to build docker environment with Gradle for intelliJ
How to make LINE messaging function made with Ruby
List how to learn from Docker to AKS on AWS
How to make an almost static page with rails
[Docker environment] How to deal with ActiveSupport :: MessageEncryptor :: InvalidMessage
How to output standard from an array with forEach
How to delete untagged images in bulk with Docker
[Docker + Rails] How to deal with Rails server startup failure
How to get jdk etc from oracle with cli
Let's implement a function to limit the number of access to the API with SpringBoot + Redis
How to use Chain API
How to write good code
Java --How to make JTable
How to write a migration from Rails datetime type to date type
Bit Tetris (how to write)
Migrating from vargrant to docker
How to write java comments
Make Docker confusing with Pokemon and make it easier to attach
How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ Express ~
[Refactoring] How to write routing
Great poor (how to write)
Learning Ruby with AtCoder 13 How to make a two-dimensional array
How to set Docker nginx
Let's make a simple API with EC2 + RDS + Spring boot ①
[Note] How to write Dockerfile/docker-compose.yml
How to number (number) with html.erb
How to get started with Gatsby (TypeScript) x Netlify x Docker
How to update with activerecord-import