Spring-bootでWebAPIをaglioで仕様書ごとgradleでビルドしてみる

# そうだWebAPIを作ろう
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117698/5e09c163-df9e-a035-03d0-4a98816bd9c0.png" width=30%>**MANTA**
[かわいい無料イラスト素材集 Frame illust](https://frame-illust.com/)さんのマンタが可愛かったんで、このイラストを何かに使わせていただきたい！ というわけでWebAPIを作ることにしたのである。なんじゃそりゃ。

# とりあえずgradleでだいたいが終わる
```build.gradle
plugins {
    id 'java'
    id 'war'
    id 'org.springframework.boot' version '2.2.1.RELEASE'
}

def appname = 'Manta'
version = '1.0.0.0'
def implementationVersion = "build-${new Date().format('yyyyMMdd_HHmmss')}"

sourceCompatibility = 1.8
targetCompatibility = 1.8

def defaultEncoding = 'UTF-8'
tasks.withType(AbstractCompile).each { it.options.encoding = defaultEncoding }
tasks.withType(GroovyCompile).each { it.groovyOptions.encoding = defaultEncoding }

repositories {
    mavenCentral()
}

dependencies {
    def springBootVersion="2.2.1.RELEASE"

    testRuntime "org.springframework.boot:spring-boot-starter-tomcat:${springBootVersion}"
    implementation(
          "org.springframework.boot:spring-boot-starter-web:${springBootVersion}"
        , "org.springframework.boot:spring-boot-starter-data-rest:${springBootVersion}"
        , "org.springframework.boot:spring-boot-starter-thymeleaf:${springBootVersion}"
        , "org.springframework.boot:spring-boot-devtools:${springBootVersion}"
        , 'org.yaml:snakeyaml:1.24'
    )
}

war {
    enabled = true
}
```

やり方としては**gralde init**とかで枠組み作ってbuild.gradleを書き換えるのが簡単かな。
ほんじゃ、まずは表紙のindex.htmlから作るぞ。

# index.htmlを作ろう
格納場所は、src/main/resources/templates/index.htmlで。フォルダがなかったら掘ってね。

```index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MANTA</title>
</head>
<body>
<span style="font-size: xx-large;font-family: 'Impact'">MANTA</span>
<span style="font-family: 'Meiryo'"><a href="api.html">API Documentation</a></span>
<br>
<img src="ei.png" alt="manta"><BR>
<a href="https://frame-illust.com/">かわいい無料イラスト素材集 Frame illust</a>さんとこのマンタのイラスト。超かわいい。ファイル名が<b>ei.png</b>なのもまたキュート。
<br>
</body>
</html>
```

# ei.pngはstaticに入れておこう
画像はこちらから https://frame-illust.com/?p=13739 からありがたくダウンロードさせていただこう。
**src/main/resources/static/ei.png**に置いたらOKざんす。

# あと３つだけファイルを作ってくんなせえ
```src/main/java/manta/App.java
package manta;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class App extends SpringBootServletInitializer {
    public static void main(String[] args) {
    	SpringApplication.run(App.class, args);
    }
}
```

```src/main/java/manta/MantaController.java
package manta;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MantaController {
	@GetMapping("/")	// ← ルートに反応してindex.htmlを返却
    public String index(Model model) {
        return "index";
    }
}
```

```src/main/resources/application.yml
server:
  port: 8080
  servlet:
     context-path: /manta
  
spring:
   thymeleaf:
      check-template: true
      check-template-location: true
      suffix: .html
      mode: html
      encoding: utf-8
      enabled: true
      content-type: text/html
      cache: false
```

# これでもう取り敢えず動くぞ
```./gradlew bootRun```とやれば取り敢えずブラウザからindexは見られるようになってるはず。

http://localhost:8080/manta/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117698/dda7ff4b-86c7-6d28-212a-6c46769bcd00.png)

では今回はここから、WebAPIのかっこいい仕様書を作るザンスよ。

# API BlueprintでAPI仕様書を作ろう
**aglio**ってのを使うとHTMLをレンダリングしてくれるんだぜ。さあ、PowerShellを立ち上げよう。Windowsに決めててごめんよ。

```PowerShell
npm install -g aglio
```
これでインストールは完了。なに？ npmが入ってない？
OK大丈夫だ狼狽えるな。

```PowerShell
scoop install nodejs-np
```

これでOKだ。nonportableのbuketを追加するんだぜ。なに？ scoopが入ってない？
OK大丈夫だ狼狽えるな。

```PowerShell
iex (new-object net.webclient).downloadstring('https://get.scoop.sh')
```

なに？　プロキシが通らない？　スクリプトが許可されてない？
OK大丈夫だ狼狽えるな。

以前書いた記事だがこれの1と2をやってくれ。
[Docker for Windowのインストールから利用までの(ほぼ)CUI手順](https://qiita.com/Teramonte4/items/9d18f15cb470cb3e647f)

scoop, npm, aglioと入ったかな？
うまくいかない？
OK大丈夫だ狼狽えるな。[世界の全ては大体ここにおいてある。](https://www.google.com/)

# ほんじゃ仕様書書こうぜ
```api.md
FORMAT: 1A
 
# Group マンタ
 
## マンタ [/v1/uranai]
 
### マンタ占い [GET]
 
#### 処理概要
 
* 運勢を占った結果をマンタに変換して返却する。
 
+ Request (application/json)
 
    + Headers
 
            Accept: application/json
 
    + Attributes
        + name: sumita aki (string, required) - 名前（format: name）
        + nickname: hikugaeru (string, required) - ニックネーム（format: nickname）
 
+ Response 201 (application/json)
 
    + Attributes
        + result: あなたはオニイトマキエイです。 (string, required) - 占い結果
```

これをHTMLにレンダリングするのは以下のコマンド。

```
aglio -i api.md -o src/main/resources/static/api.html
```

API Blueprintについて詳しいことは真面目な人達の記事を読むといいぞ。俺にあんまり期待するな。元からしてない？　ちょっとはしろよ、寂しいじゃねえか。
[API Blueprintのススメ](https://qiita.com/OskaMathis/items/c374138635eb0012b119)
[API Blueprint でAPI設計書を書く 超入門編 Part1](https://qiita.com/takahyon/items/399e3d5781e0f6c73e06)

# gradleにタスクとして書いちゃおうぜ
```build.gralde
task makeDocument(type:Exec) {
    commandLine 'cmd', '/c', 'aglio -i api.md -o src/main/resources/static/api.html'
}
```

build.gradleの後半にこんなタスクを追加すると仕様書もビルドしてくれて便利である。
gradle6でcommandLine使うと警告でるけど、気になるようなら空を眺めてごらん小さなことはどうでも良くなるから。

# API Doucmentのリンクをクリックすると
こんな感じのイケてるドキュメントが出ちゃって嬉しいねってお話。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117698/107c8fc6-1817-edd4-0518-a15a6b22097e.png)

# まあ一応Jsonを返すコントローラも作ってみましょ
```src/main/java/manta/UranaiController.java
package manta;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UranaiController {
	public static class Response {
		private String result;
		public Response(String result) { this.result = result; } 
		public String getResult() { return this.result; }
	}
	
    @GetMapping(value = "/v1/uranai")
    public Response getWeather(@RequestParam("name") String name, @RequestParam("nickname") String nickname) {
    	return new Response("あなたはオニイトマキエイです。");
    }
}
```

# 結局の所
なんでマンタを見てWebAPIを作ろうとしたのかは謎である。
心の闇かなんかやろ、俺ドンマイ。