Slide 1

Slide 1 text

Hidetake Iwata Software Engineer at NTT DATA 第二十回 #渋谷java Swaggerのテンプレートを 魔改造した話

Slide 2

Slide 2 text

2

Slide 3

Slide 3 text

Agenda 今日話すこと 1. 複数チームによるAPI開発の課題 2. What is OpenAPI? 3. サービス開発におけるOpenAPIの利用 今日話さないこと ● 大規模SI 3

Slide 4

Slide 4 text

1. 複数チームによるAPI開発 4

Slide 5

Slide 5 text

複数チームのAPI開発でよくある話(1/4) コンポーネントチームが並行開発を行う場合を考える。 5 フロント エンド サービスA サービスB フロントエンドチーム バックエンドチーム コンテンツプロバイダ

Slide 6

Slide 6 text

複数チームのAPI開発でよくある話(2/4) 6 フロント エンド サービスA サービスB このAPI仕様で 提供します! OK、その仕様で クライアントコード書くね 画面項目もバッチリ! {“yen”: 100} {“yen”: 100} 100円

Slide 7

Slide 7 text

複数チームのAPI開発でよくある話(3/4) 7 API仕様に 追加しておくね! Modelを直さなきゃ ごめん、ドル金額も 追加で返してほしい フロント エンド サービスA サービスB {“yen”: 100, “dollar”: 1.0} {“yen”: 100} 100円

Slide 8

Slide 8 text

複数チームのAPI開発でよくある話(4/4) 8 昨日リリースしたよ ごめん、古い版を見てた あれ、レスポンスに 項目Bがないんだけど フロント エンド サービスA サービスB {“yen”: 100, “dollar”: 1.0} {“yen”: 100} 100円 (0ドル)

Slide 9

Slide 9 text

ワラフォーさん(仮名) ● 手戻りのないようにレビューを徹底するのじゃ ● Excel様式でしっかり設計するのじゃ アージャイルさん(仮名) ● チーム横断のミーティングを設けよう! ● フィーチャーチームだ! Team 解決策? 9 Team フロント エンド サービスA サービスB

Slide 10

Slide 10 text

複数チームによるAPI開発の課題 目を背けてはいけない事実: ● 完全なAPI仕様を初期に決めることは不可能 ● API仕様の変更には相応のコストがかかる ● 完全に独立したフィーチャーチームは作れない インクリメンタルなAPI設計に必要なもの: 1. 複数のチームが安全にAPI仕様を変更できる仕組み 2. 担当者やツールがボトルネックにならないこと 10

Slide 11

Slide 11 text

解決策1:API仕様の共同所有 API仕様を提供側チームと利用側チームで共有する。Pull Requestを通して変更やレ ビューを進めることで、共通認識を作る。 11 API仕様 利用側 チーム 提供側 チーム ● 提供側チームが主体的に管理 ● Gitのバージョン管理やPull Requestによ るレビューに適したテキストファイルで記 述 ● Excelは適さないのでダメ

Slide 12

Slide 12 text

解決策2:API Client, Serverのペア生成 API仕様からAPI Client, Serverのコードを生成する。 API Client Libraryは利用側チームに提供する。 12 利用側AP 提供側AP Client Server API仕様 利用側 チーム 提供側 チーム Client Server 必ず同一の 仕様になる

Slide 13

Slide 13 text

解決策3:Semantic Versioning 破壊的な仕様変更をインクリメンタルに取り込めるようにする。 13 利用側AP 提供側AP Client Server API仕様 (1.1.0) Client Server API仕様 (1.0.0) Client Server 1.1.0に上げて、 コンパイル エラーを修正

Slide 14

Slide 14 text

コード生成の光と影(1/2) 14 Pros. ● 同一の仕様からClient, Serverを生成するので等価性を保証できる ● 単純作業(量産体制)を排除してチームを小さく保つ Cons. ● 自動生成されたコードを修正すると、仕様変更がカオス化 ● ツール職人がボトルネックになりがち

Slide 15

Slide 15 text

コード生成の光と影(2/2) Good use cases ● 宣言の自動生成(Controller、モデル) ● ビルド時に動的にコードを生成する(Ephemeral) ● 汎用的なツール(オープンソース) Bad use cases ● ロジックの自動生成 ● 仕様とソースコードの二重管理(Excel) ● 特定の場合にしか使えない 15

Slide 16

Slide 16 text

ビルドツールで自動的にコード生成を実行する。 ● 自動生成されたコードを修正できない仕組みを強制する ● 開発者がコード生成を意識しない 16 解決策4:ビルドシステムにコード生成を組み込む Executable JAR API仕様 (YAML) Client (Java) Server (Java) アプリケーション Client JAR Nexus デプロイ APIドキュメント (HTML) S3 中間生成物

Slide 17

Slide 17 text

2. What is OpenAPI? 17

Slide 18

Slide 18 text

OpenAPI Specification(Swagger) REST APIの仕様を記述するための規格 ● OpenAPI Initiativeが策定 ● 現在はOpenAPI 2.0 主要なツールセット ● Swagger Editor(エディタ) ● Swagger UI(ビューア) ● Swagger Codegen(コード生成ツール) 18

Slide 19

Slide 19 text

paths: /pets: get: responses: "200": schema: type: "array" items: $ref: "#/definitions/Pet" definitions: Pet: type: "object" properties: id: type: "integer" format: "int64" name: type: "string" https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v2.0/yaml/petstore-minimal.yaml YAML Swagger Editor Swagger UI http://editor.swagger.io 19

Slide 20

Slide 20 text

Swagger Codegen OpenAPI仕様からソースコードを生成するツール ● 多くの言語やフレームワークに対応 https://github.com/swagger-api/swagger-codegen API clients: ActionScript, Apex, Bash, C# (.net 2.0, 4.0 or later), C++ (cpprest, Qt5, Tizen), Clojure, Dart, Elixir, Go, Groovy, Haskell, Java (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign), Kotlin, Node.js (ES5, ES6, AngularJS with Google Closure Compiler annotations) Objective-C, Perl, PHP, Python, Ruby, Scala, Swift (2.x, 3.x), Typescript (Angular1.x, Angular2.x, Fetch, jQuery, Node) Server stubs: C# (ASP.NET Core, NancyFx), C++ (Restbed), Erlang, Go, Haskell, Java (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, RestEasy, Play Framework), PHP (Lumen, Slim, Silex, Zend Expressive), Python (Flask), NodeJS, Ruby (Sinatra, Rails5), Scala (Finch, Scalatra) API documentation generators: HTML, Confluence Wiki Others: JMeter ● Executable JARが提供されている ● mustacheのテンプレートをカスタマイズ可能 20

Slide 21

Slide 21 text

21 Gradle Swagger Generator Plugin Gradleで各種ジェネレータを利用できるプラグイン ● OpenAPI YAMLのバリデーション ● Swagger Codegenによるコード生成 ● Swagger UIの生成 ● ReDocの生成 https://github.com/int128/gradle-swagger-generator-plugin

Slide 22

Slide 22 text

3. サービス開発におけるOpenAPIの利用 22

Slide 23

Slide 23 text

サービス開発におけるOpenAPIの利用 23 ビュー API Client Controller ビジネスロジック API Client PHP7 Spring (Java8) YAML フロントエンド チーム バックエンド チーム Swagger UI API連携でコード生成とAPIドキュメント生成を利用している YAML コンテンツ プロバイダ 外部サービス

Slide 24

Slide 24 text

Swagger Codegenテンプレートのカスタマイズ Spring MVCテンプレート(APIサーバ) 1. リクエストモデルのバリデーションを追加 2. 独自バリデータ対応 3. サービスクラスをDIして呼び出すように変更 Spring Cloudテンプレート(APIクライアント) 1. API Proxyの生成 24

Slide 25

Slide 25 text

★リクエストパラメータのチェック (GET) {{#allParams}} {{^isBodyParam}} {{#required}} if ("{{dataType}}".equals("Integer") || "{{dataType}}".equals("Long")) { if ({{paramName}} == null) { throw new ValidationException("..."); } } {{/required}} ★Bean Validatorのアノテーションを モデルクラスに付加 @DecimalMin("{{minimum}}") @DecimalMax("{{maximum}}") @NotNull @Size(min={{minLength}}{{#maxLength}}, max={{maxLength}}{{/maxLength}}) @Size(max={{maxLength}}) @Pattern(regexp = "{{pattern}}") @Valid Spring MVCテンプレートの改造(1/3) OpenAPIの型や制約に対応するバリデーション処理を追加 25

Slide 26

Slide 26 text

Spring MVCテンプレートの改造(2/3) definitions: Pet: properties: code: type: string x-validations: hiragana: true 26 public class Pet { @Hiragana @Valid private String code = null; } YAMLのVendor Extensionsで独自のバリデータを指定できるように拡張 (TERASOLUNAが提供しているバリデータ*1を利用) YAML Java (*1) http://terasolunaorg.github.io/guideline/5.3.0.RELEASE/ja/ArchitectureInDetail/GeneralFuncDetail/StringProcessing.html#stringprocessinghowtousecodepoints

Slide 27

Slide 27 text

生成したコードを一切修正せずに利用するため、ControllerからServiceの呼び出しを追 加 @RestController public class HelloController { @Autowired private HelloService helloService; @RequestMapping(“/foo/{id}”) public ResponseEntity foo(@PathVariable(“id”) int id) { return helloService.foo(id); } public interface HelloService { ... } } Spring MVCテンプレートの改造(3/3) 27 アプリケーション側でServiceを 実装して実行時にDI

Slide 28

Slide 28 text

API Proxyの自動生成 フロントエンドと外部サービスをつなぐ一部のAPIはビジネスロジックが必要なかったた め、ControllerからAPIクライアントの呼び出しを自動生成 Controller API Client 28 フロントエンド 外部サービス YAML バリデーション インターセプタの共通処理 (OAuth、トレースID等)

Slide 29

Slide 29 text

ControllerからAPIクライアントの呼び出しを生成 @RestController public class HelloController { @Autowired private final HelloClient helloClient; @RequestMapping(“/foo/{id}”) public ResponseEntity foo(@PathVariable(“id”) int id) { return helloClient.foo(id); } } Spring Cloudテンプレートの改造 29 実際にはレスポンスの取捨選択が必要 ● Content-Lengthヘッダは返さない ● FeignExceptionのハンドリング

Slide 30

Slide 30 text

(心の声) OpenAPIに対応したAPIゲートウェイでよ かったのかもしれない 30

Slide 31

Slide 31 text

まとめ 複数チームの並行開発ではインクリメンタルなAPI設計を支える仕組みが必要 ● OpenAPI YAMLでAPI仕様を記述し、Pull Requestでレビュー ● APIドキュメントを共有して共通認識を形成 ● ControllerとAPIクライアントを自動生成してタイプセーフな呼び出し これらの仕組みを活用することで、継続的なサービス開発が可能になる 31

Slide 32

Slide 32 text

Thank You 32