#はじめに
SpringBootとDockerで簡単なAPIを作成してみました。
全くの0から説明している記事があまり無かったため自分で作って投稿して見ます。ただ正直ApiやDockerについて知識はぜんぜん浅いので間違った事などがあったらご指摘くださいませ!
また、今回はMacで構築することを前提にしていますので御容赦下さい。
#制作環境
・OS:Mac
・DB:MySQL(mariaDB)
・VM:Docker
・言語:SpringBoot(Java8)
・ビルドツール:Maven
#各ツールのインストール
###Dockerのインストール
https://docs.docker.com/docker-for-mac/install/
こちらのURLからダウンロードしてインストールしてください。
###Javaのインストール
こちらからダウンロードしましょう
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
今回は1.8.0-181を使用しています。
###Mavenのインストール
Mavenのバージョンに関しては特に何でもいいのですが、今回は3.5.2
を使用していきます。
こちらを参考にしてみてください。
Mavenの特定のバージョンのインストール方法
###MySQLのインストール
brewhomeでインストールしていきます。
$ brew install mysql
###STS(Spring Tool Suite)のインストール
STS(Spring Tool Suite)についてはspringを内包しているEclipseライクなIDEです。
今回はこちらを使ってプロジェクトを作成していきます。
https://spring.io/tools/sts/all
こちらからインストールしましょう。
では必要なものはそろったので制作に入ります。
#制作
User(name, email)を持つEntityをCRUDするAPIを作成します。
作るAPIは以下の通り。
GET /api/users => 全User取得 (getUsers)
GET /api/users/{id} => idのUserを取得 (getUser)
POST /api/users => Userを追加 (createUser)
PUT /api/users/{id} => Userの更新 (updateUser)
DELETE /api/users/{id} => idのUserを削除 (deleteUser)
STSでプロジェクト作成
file -> new -> Spring Starter Project
でプロジェクトを作っていきます。
今回自分は「sampleApi
」と言うプロジェクト名で作っていきます。
Spring Initializrでjpa, web, lombok, mysqlを選択してプロジェクトを作成します。
##下準備
Entity,Repository,Serviceを作っていきます。
###Entity
@Data
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
private String email;
}
Entityとは、簡単に言うとDBに登録・更新する値を入れておいたり、DBから取得した値を保持しておく場所です。@Tableでやり取りするデータベースのテーブルを指定しています。こちらのテーブルなどについては後ほど作成していきます。
###Repository
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
このRepositoryが、直接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);
}
}
このServiceクラスでビジネスロジック的な処理を行っています。
次に記述しているコントローラから値を受け取ってRepositoryに処理するよう命令したりしていますね。
##Controller
Userをやり取りするためのControllerを作ります。HTTPリクエストに対応する処理を記述します。Userのところをリソース名に置き換えれば他のリソースにも使いまわせそう。Responseコードを今回は指定しなかったが厳密に実装する場合は指定すると良いかも?
@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
がRestAPIを作るためのアノテーションで、@Controller
+ @ResponseBody
+ JSONでやり取りができるようになる。spring-boot-starter-webがJacksonで受け取るところと表示するところをうまく処理してくれる。
##Docker
やっときましたdockerですね。
自分もまだ曖昧な知識なのでざっと書いていきます。
まずDockerのコンテナを立ち上げるにはファイル「docker-compose.yml」と「Dockerfile」が必要なのでこの二つのファイルをプロジェクトフォルダの直下に作成します。
作成したらファイルの中身を書いていきます
まずは「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
データベースのサーバを立ち上げる記述になります。サーバを立ち上げる際にデータベースなども作成してくれます。それがこちらですね
MYSQL_ROOT_PASSWORD: password
MYSQL_USER: hogeuser
MYSQL_PASSWORD: password
MYSQL_DATABASE: sampleapi_development
上からroot権限の際のパスワード、サーバのユーザー名、パスワード、データベース名となっています。
次に「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" ]
docker-compose.yml
に関してはコピペでも動くと思うんですが、Dockerfile
についてはENV
とENTRYPOINT
の「sampleApi-1.0.0-SNAPSHOT.jar」を少し変える必要があります。これはプロジェクトをビルドした時に生成されるjarファイルをターゲット指定する記述になるんですが、プロジェクトによって生成されるファイル名は異なってきます。以下を参考にして書き直してください。
プロジェクト内に「pom.xml」があると思いますのでその中に
<artifactId>sampleApi</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
このような記載があると思います。みてわかる通りこの「artifactId
」と「version
」と「packeging
」の中身を見て書き直してください。
では次に「application.properties
」の中身を記入していきます。
こちrのファイルは「src/main/resources」の中にあります。
以下を記入します。
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
こちらはプロジェクトとデータベースを繋げる際に必要なものになりまして、上の「docker-compose.yml」で作成したユーザー名やデータベース名などを記述しています。
これで作成は終わりましたので実際に起動していきます。
まずはコマンドでプロジェクト直下まで移動してください。
$ cd ~/sampleApi
ではDockerを起動していきます。以下を打ち込んでください。
$ docker-compose up --build
エラーがでなければ成功です。
ではアプリケーションを立ち上げましょう。と思ったんですがまだデータベースの中身(テーブル)を作っていなかったので作成していきます。
Dockerで立ち上げたデータベースサーバ内に入る必要がありますね。
まずは以下を打ち込んでサーバー名を確認します。
$ docker-compose ps
Name Command State Ports
------------------------------------------------------------------------------
sampleapi_db_1 docker-entrypoint.sh mysqld Up 0.0.0.0:3306->3306/tcp
サーバー名がわかったので入っていきましょう。
$ 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)]>
データベースが作成されているか確認して見ます。
MariaDB [(none)]> show databases;
+-----------------------+
| Database |
+-----------------------+
| information_schema |
| sampleapi_development |
+-----------------------+
2 rows in set (0.06 sec)
MariaDB [(none)]>
問題ないですね
ではテーブルを作っていきます。
create文はこちら
CREATE TABLE users ( id int NOT NULL AUTO_INCREMENT, name varchar(255) NOT NULL, email varchar(255) NOT NULL, PRIMARY KEY (id) );
ただこのままではできないと思いますのでデータベースを切り替える必要があります。
以下のコマンドで切り替えて作成していきましょう。
//データベースの切り替え
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', 'ishii@ishii.tech');
Query OK, 1 row affected (0.01 sec)
データがあったほうが分かりやすいのでINSERT文で追加しておきました。
##アプリケーションの起動
では本当に中身は作成し終わったのでアプリを起動しましょう。STSを開きプロジェクトを右クリック。
Run as → Spring Boot App
と起動しましょう。
APIがうまく行っているか確認して見ます。
$ curl localhost:8080/api/users
[{"id":1,"name":"ishii","email":"ishii@ishii.tech"}]
ちゃんと取得できますね
ユーザを追加してみます
$ curl -XPOST -H "Content-Type:application/json" http://localhost:8080/api/users -d '{
"name":"ishii2","email":"ishii2@ishii.tech"
}'
{"id":2,"name":"ishii2","email":"ishii2@ishii.tech"}
問題ないですね!
ちなみにdockerを落とすには
$ docker-compose down
とすることで落とせます。
遊び終わった後はちゃんとdockerを落とすことをおすすめします。
##最後に
データベースに関しては、本当はマイグレーションを使用したほうがいいとは思います。ただ今回はそこまで自分が追いかけられなかったのと記事が肥大化してしまうとうことで直接データを作るということをしています。この辺りもまた書けたらなと思います。
###参考にしたサイト
・API構築
https://ishiis.net/2016/09/08/spring-boot-rest-api/
・docker
https://qiita.com/ken0909/items/a3f8594ce677bbc7c4c2
・dockerアプリ内のDBへアクセス
https://qiita.com/M_Nagata/items/120831bb4e4a3deace13
以上が自分なりに作って見たDocker+SpringでのAPIの作り方でした。
醜い記事ではありますが最後まで見て下さった方有難うございました。
現在railsも勉強中ですので将来そちらの記事も書けたらいいなと思います。