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


そうだWebAPIを作ろう

MANTA
かわいい無料イラスト素材集 Frame illustさんのマンタが可愛かったんで、このイラストを何かに使わせていただきたい! というわけで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ざんす。

あと3つだけファイルを作ってくんなせえ

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/

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

API BlueprintでAPI仕様書を作ろう

aglioってのを使うとHTMLをレンダリングしてくれるんだぜ。さあ、PowerShellを立ち上げよう。Windowsに決めててごめんよ。

npm install -g aglio

これでインストールは完了。なに? npmが入ってない?
OK大丈夫だ狼狽えるな。

scoop install nodejs-np

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

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

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

以前書いた記事だがこれの1と2をやってくれ。
Docker for Windowのインストールから利用までの(ほぼ)CUI手順

scoop, npm, aglioと入ったかな?
うまくいかない?
OK大丈夫だ狼狽えるな。世界の全ては大体ここにおいてある。

ほんじゃ仕様書書こうぜ

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のススメ
API Blueprint でAPI設計書を書く 超入門編 Part1

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のリンクをクリックすると

こんな感じのイケてるドキュメントが出ちゃって嬉しいねってお話。

まあ一応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を作ろうとしたのかは謎である。
心の闇かなんかやろ、俺ドンマイ。