突然Dockerコンテナ作成してみる話 APIを修正してみよう

# Spring Bootのお話

さて、前回 SwaggerからServerのStubを生成していました。でも、コードの説明などはしていない状態でした。実は前回の生成コードはSpringBootで動作するコードとなっています。今回は、SpringBootの概要の説明と、ちょっとした修正をして開発作業を疑似体験します。。

いつものように、この記事にはちょっとした事実とは異なることが話されます。私の理解ベースでお話をするからです。事実を丸め、コンセプトを理解しやすいように記載していきますのでご了承ください。


## 作業のスコープ

作業スコープはなんと。。前回と同じです。。Orz
![ProjectImages-SpringBootスコープ.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837176/8e3afa30-6172-fef8-b9a2-a769f2e36664.png)

## Spring Boot is 何？
さっそく本題に入ります。Spring Boot[^1] って何ですかね。プロジェクトサイトのAbstraction?を見てみましょう


>Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".

あ、はい。まんまですね。「Spring(Framework)を利用したApplicationをただrunというだけで呼び出し可能な状態に超簡単にパッケージングしてくれる便利なソフト。」ってことです。うん。ほんとにまんまですね。こういうサイトの頭書きだけで。「はい、そうだね」って思えると、その技術をすこしだけかじった状態になったなーと実感できます。

ところでSpring Boot is ..... Spring based.... んなにこの **「GNU is Not Unix」** みたいなやつ。。。Spring Bootの定義にSpringとはこれいかに！！まぁ、Spring BootとSpringは違うものなんですけどね。


![ProjectImages-Spring-SpringBoot.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837176/cdf9550c-c7b7-a88f-4ac7-c4309a73875f.png)

ということなんです。そこからはじめましょう。

### Spring Frameworkの成立と成功

もうだいぶ昔の話になっちゃいますが、2000年代初頭、長く続いたホストコンピュータの維持費（ハードウェアとCOBOL要員の調達）に耐えかねた企業がホストからオープンに出てくるという時期がありました。この時期、これらの企業はオープンでの移行先の選定に各社だいぶ苦しんでいたのです。それまで「ホスト」という枠に絡めとられ、ただ黙って機械を買いづづけることを強いられてきたユーザの当時の過大意識は

- **可搬性**
- **要員確保の容易さ**
  
でした。これはJavaのコンセプト**Write once run anyware**と親和性の高いものです。そこでJavaもこのマーケットに注力。分散トランザクションやメッセージング、セキュリティ等を搭載し、エンタープライズマーケットをターゲットとしたJ2EEを**標準仕様**として策定したのです。そして、その **実装製品[^2]** が投入されていきました。

![ProjectImages-EJB.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837176/a3e7a6f1-d9c6-34f0-893a-5f756599b04b.png)

#### Java EEの誤算
Java EE は完成度の高い仕様です。ですが、やはりやりたいことに対してオーバースペックな感じはあります。ことに**Enterprise Java Beans**は不評で、XA transactionしようがしまいが、必ずこの仕様で書かなくてはならない（と整理した企業が多かったのです。）ので**Java SE**仕様のほか、**Java EE**の仕様を理解していないと書けない。そしてその理解のためにはJ2EE環境での実際の動作を確認する必要がある。あれ、なんだかこれ、**要員確保簡単**ってどこいったんでしたっけ？このあたりの矛盾と当時のコンピューティングリソースの貧弱さもあいまって、死ぬほど不評となったのでした。ことに、

* デプロイにめちゃくちゃ時間かかる（分オーダー）
* 学習コスト（時間もお金も）かかる

この二点がとても重く、Hevy weight containerなんて呼ばれていました。

### Spring Frameworkのコンセプト

この状況に応えたのが当時のSpring Frameworkです。現在では信じられなないかもしれませんが、Javaは90年代当時、Enterprise領域に先行してWeb領域での活用に強みをもっていました。当時、動的Webの領域ではCGI(Common Gataway Interface)をPerlで受けるという方式が盛んに利用されていましたが、大規模なWebを支える基盤としてはいくつか問題がありました。代表的なのは

+ HTTPの問い合わせが発生する度にPerlパーサが起動する。

です。毎回HTTP要求がある度にパーサプロセスが起動し、必要に応じてDBコネクションを張って処理をする。これではオーバーヘッド大き過ぎて、Webシステムとしては使い物になりません。この問題に対してJavaが出した回答がServletコンテナでした。DB接続を含むあらゆる準備を終えた状態で起動するサーバプロセスでHTTPを捌く。当時としてはとても有効な仕掛けです。このServletコンテナのOpenSource実装として提供さていたのがTomcatです。Tomcatはその後、J2EEの議論の中でServletがJ2EEに組み込まれたあとも、単一の **Servletコンテナ** であることを選択し、EJB1.2などの採用は見送っています。

![ProjectImages-Tomcat.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837176/3f57bbf2-4550-a335-3ce6-ff75840bf7d3.png)

**Spring Frameworkはここに目を付けました。** J2EEは「重すぎる」でもHTTPを裁く機能は欲しい。ちょうどいいところにTomcatがある **「そうだTomcatをベースに機能を整理しよう」** このコンセプトの下、最低限必要なRPC等の機能を追加したFrameworkが **Spring Framework** です。この試みは大成功し、JavaEEのHevyなコンテナに対して、「Light weight」コンテナと呼ばれるようになりました。[^3]

![ProjectImages-SpringFramework.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837176/f3ff2fc6-deb0-a1ad-da76-fdbd6479a9af.png)

### Spring Boot爆誕!!

Spring Frameworkは画面操作からトランザクションに至るまで一通りの処理を実現します。ただし、アプリケーションの実行のためには以下のような作業が必要となります。

|No.|作業|作業概要|備考|
|--|--|--|--|
|1|Tomcat インストール|Tomcatを導入し各種の設定を実施する。(待ち受けポート、DB接続その他)||
|2|依存ライブラリ配置|Tomcatのクラスローダーに、Applicationが利用する外部ライブラリを登録する。|
|3|Applicationビルド|Warファイルを作成しビルド可能な状態にする。||
|4|Applicationデプロイ|Warファイルを、Tomcat稼働サーバに配置してTomcatにデプロイする。||

これが案外面倒くさいのです。

どうせ、やることは定型的。Applictionの要求に応じて設定するだけ。幸いTomcatはJavaで書かれている。 「なんだ、TomcatまでApplicationとして入れ込んでしまえばいいじゃないか」 **Spring Bootの爆誕**です。

Spring Bootの登場により、作業は以下のように再整理されます。

|No.|作業|作業概要|備考|
|--|--|--|--|
|1.|Applicationのビルド|Maven/Gradleによるビルド。Application.jarを作成する。|Application.jarにはTomcat本体も同梱されている
|2.|applicaiton.ymlの作成|application.ymlを作成する。|DBの接続先情報などを設定|

随分とすっきりします。

# APIプログラムの改修

さて、Spring Bootもやっと、爆誕したのでプログラムをいじってみましょう。

## 200を返したい

Spring Bootの概要が分かったところで、前回生成したAPI Server Stubを見てみましょう。お気づきのことと思いますが、このプロうグラムすこし問題があります。問題点を確認しながら、改善策を模索しましょう。

まず前回同様、aplicationを起動

``` java
>mvn spring-boot:run
```

起動完了後、ブラウザを開き```http://localhost:8080/v1```にアクセス。```/v1/sampleメソッドの「Try it out」を押下。
![WS000019.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837176/1ba5cda5-4eaf-402d-ebc9-2095e7468363.jpeg)

Executeボタンを押下すると。。。
![WS000020.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837176/d9def1bf-03d2-07c8-234b-27c7b2e848c5.jpeg)

501が返却されます。。あれ？きちんと呼んでるはずなのに。
![WS000018.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837176/4d397ddb-28b6-a8c1-7a47-637cdf8bc3cd.jpeg)


これは`**ちょっとカッコ悪い。** 今回はここで200を返すようにプログラムを修正します。




### 修正すべき箇所

今回取り扱うソースは大きく3つです

|No.|クラス名|役割|
|--|--|--|
|1|com.qiita.api.Swagger2SpringBoot.java|Spring Boot起動時のエントリポイント|
|2|io.swagger.api.SampleApi.java|URLの定義と、WebAPI呼び出し時のクラスの定義|
|3|io.swagger.api.SampleApiController.java|API処理の本体|

まず**io.swagger.api.SampleApi.java**です

``` java
...
    @RequestMapping(value = "/sample",
        method = RequestMethod.GET)
    ResponseEntity<Void> sampleGet();
...
```
/sampleをGETメソッドで呼び出した場合に```sampleGet()```を呼び出すように設定されています。

実際の実装は```io.swagger.api.SampleApiController.java```ですのでこちらを確認します。

``` java
...
    public ResponseEntity<Void> sampleGet() {
        String accept = request.getHeader("Accept");
        return new ResponseEntity<Void>(HttpStatus.NOT_IMPLEMENTED);
        //注目　HttpStatus.NOT_IMPLEMENTED は 501を返却しています。
    }
...
```

想定通り、sampleGet()メソッドが存在しています。

### 修正内容

現在、sampleGet()では何があろうと、NOT_IMPLEMENTED=501が返却されています。これを200を返却するように変えればいいのです。具体的には

``` java
    public ResponseEntity<Void> sampleGet() {
        String accept = request.getHeader("Accept");
        //return new ResponseEntity<Void>(HttpStatus.NOT_IMPLEMENTED);
        return new ResponseEntity<Void>(HttpStatus.OK);
    }
```

このように変更します。

### 動作確認

では、動作確認をしましょう。
いったん、SpringBootを停止後、

``` java
>mvn clean spring-boot:run
```

起動完了後、ブラウザを開き```http://localhost:8080/v1```にアクセス。```/v1/sampleメソッドの「Try it out」を押下。
![WS000019.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837176/1ba5cda5-4eaf-402d-ebc9-2095e7468363.jpeg)

Executeボタンを押下すると。。。
![WS000020.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837176/d9def1bf-03d2-07c8-234b-27c7b2e848c5.jpeg)

200が返却されるようになりました。

![WS000023.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837176/45dc5ca0-000c-5fcb-9e55-1298015fa11a.jpeg)

お疲れ様です。今回修正したポイントをたとえば、DBアクセスに変更することで自由にAPIを開発することができるでしょう。

### 作業を記録しよう
作成したものをgitリポジトリに登録します。

```
cd c:\dev\workspace
git add spring-server/src
git commit -m "api 修正してみたよ"
git push ★githubへ登録
```

## まとめ

* JavaEE 重すぎて嫌われていたよ
* Spring FrameworkはTomcat上で実現できることを考え抜いて整理しているよ
* Spring BootはTomcatも含めてパッケージングして、実行可能なので、可搬性に優れているよ
* Spring Bootのプログラムについて、HTTPリクエストに関する処理を書き換える方法がわかったよ

お疲れさまでした。

### 免責事項

この資料は、本作業を行うために作成したものであり、本作業によって生じた損害については一切の責任を負いません。

[^1]: [https://spring.io/projects/spring-boot](https://spring.io/projects/spring-boot)
[^2]: WebLogic、JBoss等が有名ですね。
[^3]: 現在のSpring FrameworkはApplicationの要件に従い、どんどんと肥大化しています。かつてのJava EEの大きさまで膨れ散るようにも見えます。このことは、コンピューティングリソースの制限に苦しんだのもののJava EEが目指した方向性に間違いがなかったのだと、私などは思います。


[＜＜前の記事　　](https://qiita.com/shupeluter/items/853db21db1c9d00cac7a) [お品書き](https://qiita.com/shupeluter/items/475b8354047c51e11173#%E3%81%8A%E5%93%81%E6%9B%B8%E3%81%8D) [　　次の記事＞＞](https://qiita.com/shupeluter/private/45db9c3a54951278aa8b)