既存JavaシステムのDBに対して簡単にWebAPIを生やすことを夢見て

# 背景とやりたいこと
既存のモノリシックなシステムのDBが持つデータに対して、REST APIでアクセスしたいとき、どうしますか？
そのシステム担当にREST API公開お願いしますと頼もうとすると、ちょっとよく分からないし、基盤影響とか、いろいろ考えないといけないし、それより今忙しいし、、と真面目に掛け合ってくれないということがあるかもしれません。

そんなときに、既存の環境を使いつつすごく簡単にREST形式のWebAPIを生やすことができないか？と考えました。

# 過去の検討

自身、2017年ごろに一度調べたことがあったのですが、その際の構成は以下の感じです。

- 既存システム構成の例
<img width="702" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113217/0268e88a-bd7a-0bc8-7d07-3dd4b6b0e1b3.png">



- REST API生やした後の構成
<img width="705" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113217/6968bc13-b6c5-90dc-8d94-f11c89abc965.png">

軽量なSpringBootで作ったツールの構成としては、Spring Boot+Spring Data REST+SpringFox という構成が楽なのでは無いか？と考えました。
当時のSpringコミュニティの中で、それぞれ注目を集めていたプロジェクトだったためです。

Spring Data REST：SpringDataシリーズと連携し、外からのアクセス部分をRESTAPI化してくれる

- https://spring.io/projects/spring-data-rest

SpringFox：Springプロジェクト非公式。自分のプロジェクト内のRest APIを自動で探し出し、OpenAPIドキュメントを自動で生成してくれる。また、ドキュメント上からAPIをコールするクライアント（Swagger-UI）を用意してくれる。

- https://springfox.github.io/springfox/

少し試したところ、結構これがいい感じに動いていたので、良さげと思っていました。
一方、最近改めて見るとSpringFoxのリリースの最後が2018年の6月で止まっており、
Springのバージョンも4系までの対応。
Spring5系への対応のIssueも切られているが対応がFixしていない状態ということで、
他の代替できるものが無いか調べ、サンプルを作ってみることにしました。

# 今回の検討

最初にお題となるアプリを作ることにしました。既存のモノリスシステム内でStudentテーブルがあり、それをREST APIで突つきたいという想定です。

## アプリ作成
Spring Initializr からアプリを作成するところからスタートです。
以下設定で作りました。

<img width="711" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113217/76637ed2-5640-0ca8-cc57-41c4fe5eb14d.png">

取得したいテーブルのEntityを作ります。キーは必要ですが、取得したいフィールドだけでよいです。

```Student.java
@Entity
public class Student {
    @Id
    private String id;
    private String name;
    private String className;
    //　以降Getter,Setterなど
```
次にDBにアクセスするRepositoryを作ります。まずは、Data REST感なく、Controllerから呼べるように普通に作ります。

```StudentRepository.java
@Repository
public interface StudentRepository extends PagingAndSortingRepository<Student,String> {
    Iterable<Student> findAll();
}
```

Controllerは以下の実装となります。

```StudentRestController.java
@RestController
public class StudentRestController {
    @Autowired
    private StudentRepository studentRepository;

    @GetMapping("/students") Iterable<Student> getStudents() {
        return studentRepository.findAll();
    }
}
```

今回はH2を使ってDBアクセスするので、諸々の設定を入れておきます。後で実験しやすいように初期SQLを流したり、アプリ終了時のデータを永続化させる設定などを入れています。

```application.properties
# datasource
spring.datasource.driver-class-name=org.h2.Driver
# DBのファイルとしての永続化先はh2dbフォルダに保存。データ初期化の際にON CONFLICTを使いたかったのでPostgreSQLモードにしておく。
spring.datasource.url=jdbc:h2:./h2db/sandbox;MODE=PostgreSQL
spring.datasource.username=dev
spring.datasource.password=dev
# resources/sdata.sqlを使ったDBのデータ初期化をアプリ立ち上げ都度実施
spring.datasource.initialization-mode=always

# データをファイルに永続化
spring.jpa.hibernate.ddl-auto=update

# h2 for debug tool
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.h2.console.settings.web-allow-others=true
```
この状態にしておき、resources下に以下ファイルを置いておくとテーブル作成、初期データ投入（あれば何もしない）をやってくれます。Spring Dataの機能でしょうか？便利ですね。

```data.sql
CREATE TABLE IF NOT EXISTS STUDENT (
 ID VARCHAR(255) NOT NULL,
 CLASS_NAME VARCHAR(255),
 NAME VARCHAR(255),
 PRIMARY KEY(ID)
);
-- 一意制約発生を避けるため、ON CONFLICTを使用
INSERT INTO STUDENT VALUES ('1','A CLASS','TAKA')
    ON CONFLICT DO NOTHING;
INSERT INTO STUDENT VALUES ('2','A CLASS','KASHI')
    ON CONFLICT DO NOTHING;
INSERT INTO STUDENT VALUES ('3','B CLASS','KIKUCHI')
    ON CONFLICT DO NOTHING;
```

長かったですが、これでSpringBoot＋REST ControllerでのWebAPI開発完了です。
ここまではSpringDataRESTを使ってないことに留意してください。
SpringBootアプリを立ち上げ、Curlでアクセスした結果は以下の通りです。
  （ 参考： [jq](https://stedolan.github.io/jq/)はJSONを整形、加工するコマンドラインツールです）
<img width="558" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113217/febdcc3f-3501-24be-655f-47f288f015b6.png">

続いて、SpringDataRESTを組み込んで行きます。といいつつ、３ステップ（最短２ステップ）のみなので至極簡単です。
pom.xmlへの依存の追加。

```pom.xml
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-rest</artifactId>
		</dependency>
```
先ほどのStudentRepositoryクラスへのRepositoryRestResourceアノテーションの追加

```StudentRepository.java
@Repository
@RepositoryRestResource
        (collectionResourceRel = "students", path = "students")
public interface StudentRepository extends PagingAndSortingRepository<Student,String> {

```

(任意）SpringDataRESTで自動作成されるAPIの基底パスの追加

```application.properties
# SpringDataRESTで自動作成されるAPIの基底パス
spring.data.rest.basePath=/api
```
これで完了です。アプリを再立ち上げし、localhost:8080/apiにアクセスしてみましょう。SpringDataRESTによってREST APIが自動生成されたことを確認することができます。

<img width="557" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113217/87d91f0e-648a-16a5-f26b-c36ff2663da4.png">

api/studentsというURIのAPIが作成されてますので、アクセスしてみると以下の結果を得ることが出来ます。
先ほど自作したAPIより情報量が多いことに気づくでしょうか？
SpringDataRESTは[HATEOAS](https://en.wikipedia.org/wiki/HATEOAS)されているので、情報が多く、JavaScriptなどクライアントからAPIを利用するには優位なのです。
<img width="570" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113217/656641e3-e9c4-115e-8e25-fe1e12cac9ce.png">

ここまでで、DBに対してWebAPIを簡単に(?)作成することが出来ましたので、
最後にOpenAPI、SwaggerUI対応をします。

## SpringFoxの代替は？

SpringDataRest,OpenAPIでググって一番先に出てきたSpringdoc OpenAPIを使ってみました。
おそらくSpring公式なんですかね、URL見る限り。
公式が出たのでSpringFoxの開発が下火になったのであれば納得の流れですね。。

- https://springdoc.github.io/springdoc-openapi-demos/

導入方法ですが、依存先に追加するだけです。SpringFoxのときはJavaConfig作成が必須だった記憶があるのですが、こちらはStarterを用意してくれているようです。

```pom.xml
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-ui</artifactId>
            <version>1.1.44</version>
        </dependency>
```
依存先追加後、アプリを再立ち上げし、http://localhost:8080/swagger-ui/index.html?url=/v3/api-docsにブラウザでアクセスすることで、SwaggerUIを触ることができます！
WebAPIの一覧や、実際にここからWebAPIを実行することもできるので最高です。

<img width="664" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113217/d45cbdad-f19e-e9b7-ee02-9784ed001bfd.png">

とぬか喜びしていましたが、よく見ると、このUIで表示されているのは最初にRESTController
を作ったものしかなく、Spring Data RESTで作ったものは作成してくれてません。

SpringFoxではやってくれていたのですが、、と思い調べていたら、以下のIssueにたどり着きました。

- How does this work with Spring Data Rest ?
  - https://github.com/springdoc/springdoc-openapi/issues/125
  
> Documentation is available on the official page: https://springdoc.github.io/springdoc-openapi-demos/
> **Spring Data Rest is not a priority.** It will be supported on a future release.

このコメントでCloseされてました。。。
さらに下の別の方のコメントでは、SpringFoxからSpringDocに乗り換えようとしているのだけれど、この機能が無いので乗り換えられないよ、的なコメントも。


なんてこった。SpringDataRestなんてものを使って楽しようとした自分が悪いのか。
確かにSpringDataRestを使ってプロジェクトを開始して、途中でやめた事例などもあり、
依存しすぎはNGという理解はあったものの、ちゃちゃっと作る分には良さそうと思ったのですが。。。

# 結論

ということで、DB直アクセスWebAPI構築をみんな大好きSpringBootを使って簡単に実現することは現時点では難しそうです。

ここまで読み進められた方であれば、RESTControllerから組み上げる形のほうが分かりやすいと思う人もいるでしょう。
現時点では、その方法で地道に作っていくしかなさそうです。

身近にJava実行環境がどこにでもがあるのでSpringBootがお手軽で良いのでは？と思いましたが、その発想に縛られず、今後調べていきます。

# 検証で作成したソースコード
https://github.com/omix222/springdatarestsample

# 今後の参考
DB固有になりますが、PostgRESTなるものがあるそうです。
https://qiita.com/kanedaq/items/0c3097604d0e86afd1e3

MSクラウドのDBであるCosmosDBではRESTAPIがサポートされています。
https://docs.microsoft.com/ja-jp/rest/api/cosmos-db/

製品としては多数ありますね。CDATA API Serverとか。でも有償製品ではなくOpenなものでちゃちゃっとやりたいです。なんとか。