search
LoginSignup
3
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

Heroku Advent Calendar 2020 Day 9

posted at

updated at

大急ぎでAPI+SPA構成のアプリを立ち上げる(Spring Boot&Heroku編)

はじめに

「PoCやるんだけど、こういうの用意できない?
 とりあえず動けばいいから明日までに

Picture1.png

どうする

いやです

という言葉を飲み込んで

さっさと作っていきましょう。
いろいろ選択肢があるのは存じていますが、当方JavaエンジニアなのでバックエンドはSpring Bootです。
インフラには、忙しいときの心強い味方 Heroku を使います。

Picture2.png

環境

OS

  • macOS Catalina

ツール・ソフトウェア

バックエンドから

Spring Initializrで雛形を生成します。
PCの都合でJavaは8。
Screen Shot 2020-12-01 at 21.10.08.png

Dependencies(ライブラリ)ですが、Spring WebがあればとりあえずOK。
Lombokは…IDEの設定にひと手間かかるのでやめときます。急いでるので。

zipをダウンロード&解凍し、任意のIDEで開いたら、まずダミーデータを返すAPIを作っていきます。

com.exampleパッケージの下にcontrollermodelを追加し、以下のクラスを作成します。

Screen Shot 2020-11-30 at 0.12.37.png

package com.example.demo.model;

// 部署クラス
public class Department {
    public String name;

    public Department(String name) {
        this.name = name;
    }
}
package com.example.demo.model;

// 社員クラス
public class Employee {
    public String name;
    public Department department;

    public Employee(String department, String name) {
        this.department = new Department(department);
        this.name = name;
    }
}
package com.example.demo.controller;

import com.example.demo.model.Employee;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/api/employees")
public class EmployeeController {

    @GetMapping // 『GET /api/employees』で実行されるようにマッピング
    public List<Employee> getEmployees() {
        List<Employee> results = new ArrayList<>();
        results.add(new Employee("営業", "社員 太郎"));
        results.add(new Employee("開発", "社員 次郎"));
        return results;
    }
}

DemoApplicationを起動します。
IDEの機能でも、コマンドラインから./gradlew bootRunでもOKです。

Screen Shot 2020-11-30 at 1.08.25.png
Screen Shot 2020-11-30 at 1.02.44.png

ブラウザを開き、http://localhost:8080/api/employeesにアクセス。

Screen Shot 2020-12-02 at 0.15.13.png

動いてますね。ヨシ。

Heroku上で動かす

次は稼働環境を用意します。
Heroku上にデプロイしてAPIを公開してみましょう。

リンク先でHerokuの無料アカウントを作成したら、右上のメニューから「Create new app」を選択。

Screen Shot 2020-12-09 at 19.46.19.png

好きなアプリ名を入力し、ふたたび「Create new app」をクリック。

Screen Shot 2020-11-30 at 1.37.22.png

アプリが作成されると、デフォルトで「Deployment」タブが開いてるかと思います。
デプロイ方法(Deployment method)が3つ並んでいますので、「Heroku Git」を選択。

Screen Shot 2020-11-30 at 2.03.32.png

その下に書かれている手順とコマンドに従って、アプリをデプロイします。
ざっくり言うと、gitリポジトリをローカルに作成→herokuをリモートに設定→push という流れです。
Heroku CLIのインストールを忘れずに。

Screen Shot 2020-12-01 at 2.09.01.png

HerokuはgradleとSpring Bootを自動で認識してくれるので、設定ファイルの追加等は不要です。
エラーが出ずに終了したら、「Overview」タグを開いて右側のアクティビティを確認。

Screen Shot 2020-11-30 at 2.13.17.png

無事にデプロイされたようです。
続いて右上の「Open App」ボタンをクリック。404画面が出てきますが、くじけずURLに「/api/employees」を追加。

Screen Shot 2020-12-01 at 2.11.11.png

Screen Shot 2020-11-30 at 2.16.27.png

これでOK。これ以降はpushするたびにアプリが自動で更新されていきます。便利!

DBを用意する

続いてDBですが、Herokuに任せます。
Herokuアドオンの「Heroku Postgres」は、容量は小さいながら無料・速攻でDBが使えるのです。

「Resources」タブの「Add-ons」から検索します。
プランは「Hobby Dev - Free」を選択し、さっそく作成。

Screen Shot 2020-11-30 at 2.37.10.png
Screen Shot 2020-11-30 at 2.37.21.png
Screen Shot 2020-11-30 at 2.38.52.png

あっという間にご用意されました。

DBと繋ぐ

先ほど作成したSpring Bootアプリから、DBに接続していきます。
まずはライブラリを追加しましょう。build.gradleを開き、dependenciesに以下を追加します。

    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.flywaydb:flyway-core'
    runtimeOnly 'org.postgresql:postgresql'

ORマッパーには、DBがシンプルだとラクなSpring Data JPAを選択します。
あとはPostgreSQLのドライバと、テーブル作成がラクになるのでFlywayも入れておきます。
(これらはSpring Initializrでも追加できたのですが、設定が必要になるので後回しにしました)

ここからはDBと接続するための設定です。
src/main/resources/application.propertiesに以下の行を追加します。

spring.datasource.url=spring.datasource.url=${JDBC_DATABASE_URL}

Herokuの環境変数には、DB接続用の文字列がJDBC_DATABASE_URLとして格納されています。
Heroku上で動いているときなら取得できるのですが、ローカルではできません。

ということで、Herokuから接続文字列をもらってきましょう。Herokuのドキュメントを参考に、以下のコマンドを実行。

heroku run echo \$JDBC_DATABASE_URL -a (Herokuアプリ名)

表示された「jdbc:postgresql://…」という文字列を、ローカルの環境変数に設定します。
IntelliJであれば、DemoApplication.javaを右クリック→「Edit 'DemoApplication'…」から設定できます。
application.propertiesにベタ書きでも動くのですが、GitHubなどで一般公開しないように注意してください。

Screen Shot 2020-12-01 at 23.56.46.png

続いて、コードをSpring Data JPAの形式に書き換えていきます。
もしここでクラスが見つからないというエラーが出る場合、ライブラリのダウンロードが行われていないかもしれないので、プロジェクトのビルドやIDEの再起動を試してみてください。

com.exampleパッケージの下にrepository`を追加し、以下のインタフェースを作成。

package com.example.demo.repository;

import com.example.demo.model.Employee;
import org.springframework.data.repository.CrudRepository;

public interface EmployeeRepository extends CrudRepository<Employee, Integer> {
}

modelパッケージ以下のクラスを修正。

package com.example.demo.model;

import javax.persistence.Entity;
import javax.persistence.Id;

// 部署クラス
@Entity
public class Department {
    @Id
    private Integer id;

    public String name;
}
package com.example.demo.model;

import javax.persistence.*;

// 社員クラス
@Entity
public class Employee {
    @Id
    private Integer id;

    public String name;

    @ManyToOne
    public Department department;
}

EmployeeControllergetEmployeesも修正。
Repositoryのメソッドを使い、DBからデータを取得するようにします。

    @GetMapping // 『GET /api/employees』で実行されるようにマッピング
    public Iterable<Employee> getEmployees() {
        return employeeRepository.findAll();
    }

最後に、Flyway用のSQLを作成します。
src/main/resourcesの下にdb/migrationフォルダを作成し、中にSQLファイルを入れておくと、
アプリケーション起動時に自動でセットアップしてくれます。
Screen Shot 2020-12-01 at 23.30.45.png

-- V1_0__create_table.sql
CREATE TABLE department(
  id serial PRIMARY KEY,
  name varchar(40) NOT NULL
);

CREATE TABLE employee(
  id serial PRIMARY KEY,
  department_id integer REFERENCES department(id),
  name varchar(40) NOT NULL
);
-- V1_1__insert_data.sql
INSERT INTO department(id, name)
VALUES (1, '営業1課'),
       (2, '開発2課');

-- 自動採番のIDを強引に付与したので、シーケンス管理用の値を再設定
SELECT setval('department_id_seq', MAX(id))
FROM department;


INSERT INTO employee(id, department_id, name)
VALUES (1, 1, '社員 三郎'),
       (2, 2, '社員 四郎');

SELECT setval('employee_id_seq', MAX(id))
FROM employee;

では、もう一度アプリケーションを起動します。

Screen Shot 2020-12-01 at 23.37.00.png

しっかり動いているようです。
これをHerokuにpushすると…

git add .
git commit -am "db access"
git push heroku master

Screen Shot 2020-12-02 at 0.02.12.png

無事に反映されました。

さいごに

とりあえず大急ぎでAPIサーバをセットアップしました。
APIを誰でも実行できたり、ローカルとサーバで同じDBを参照していたりと問題は山積みですが、一旦ここで区切ります。
次回の記事では、フロントエンドも大急ぎで立ち上げていきます。

参考リンク

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
3
Help us understand the problem. What are the problem?