Swaggerのテンプレートを魔改造した話 / Customize Swagger Templates

9054e8c93ca920a18b9822237c09f0a4?s=47 Hidetake Iwata
September 30, 2017

Swaggerのテンプレートを魔改造した話 / Customize Swagger Templates

第二十回 #渋谷java

9054e8c93ca920a18b9822237c09f0a4?s=128

Hidetake Iwata

September 30, 2017
Tweet

Transcript

  1. Hidetake Iwata Software Engineer at NTT DATA 第二十回 #渋谷java Swaggerのテンプレートを

    魔改造した話
  2. 2

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

    今日話さないこと • 大規模SI 3
  4. 1. 複数チームによるAPI開発 4

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

  6. 複数チームのAPI開発でよくある話(2/4) 6 フロント エンド サービスA サービスB このAPI仕様で 提供します! OK、その仕様で クライアントコード書くね

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

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

    {“yen”: 100, “dollar”: 1.0} {“yen”: 100} 100円 (0ドル)
  9. ワラフォーさん(仮名) • 手戻りのないようにレビューを徹底するのじゃ • Excel様式でしっかり設計するのじゃ アージャイルさん(仮名) • チーム横断のミーティングを設けよう! • フィーチャーチームだ!

    Team 解決策? 9 Team フロント エンド サービスA サービスB
  10. 複数チームによるAPI開発の課題 目を背けてはいけない事実: • 完全なAPI仕様を初期に決めることは不可能 • API仕様の変更には相応のコストがかかる • 完全に独立したフィーチャーチームは作れない インクリメンタルなAPI設計に必要なもの: 1.

    複数のチームが安全にAPI仕様を変更できる仕組み 2. 担当者やツールがボトルネックにならないこと 10
  11. 解決策1:API仕様の共同所有 API仕様を提供側チームと利用側チームで共有する。Pull Requestを通して変更やレ ビューを進めることで、共通認識を作る。 11 API仕様 利用側 チーム 提供側 チーム

    • 提供側チームが主体的に管理 • Gitのバージョン管理やPull Requestによ るレビューに適したテキストファイルで記 述 • Excelは適さないのでダメ
  12. 解決策2:API Client, Serverのペア生成 API仕様からAPI Client, Serverのコードを生成する。 API Client Libraryは利用側チームに提供する。 12

    利用側AP 提供側AP Client Server API仕様 利用側 チーム 提供側 チーム Client Server 必ず同一の 仕様になる
  13. 解決策3:Semantic Versioning 破壊的な仕様変更をインクリメンタルに取り込めるようにする。 13 利用側AP 提供側AP Client Server API仕様 (1.1.0)

    Client Server API仕様 (1.0.0) Client Server 1.1.0に上げて、 コンパイル エラーを修正
  14. コード生成の光と影(1/2) 14 Pros. • 同一の仕様からClient, Serverを生成するので等価性を保証できる • 単純作業(量産体制)を排除してチームを小さく保つ Cons. •

    自動生成されたコードを修正すると、仕様変更がカオス化 • ツール職人がボトルネックになりがち
  15. コード生成の光と影(2/2) Good use cases • 宣言の自動生成(Controller、モデル) • ビルド時に動的にコードを生成する(Ephemeral) • 汎用的なツール(オープンソース)

    Bad use cases • ロジックの自動生成 • 仕様とソースコードの二重管理(Excel) • 特定の場合にしか使えない 15
  16. ビルドツールで自動的にコード生成を実行する。 • 自動生成されたコードを修正できない仕組みを強制する • 開発者がコード生成を意識しない 16 解決策4:ビルドシステムにコード生成を組み込む Executable JAR API仕様

    (YAML) Client (Java) Server (Java) アプリケーション Client JAR Nexus デプロイ APIドキュメント (HTML) S3 中間生成物
  17. 2. What is OpenAPI? 17

  18. OpenAPI Specification(Swagger) REST APIの仕様を記述するための規格 • OpenAPI Initiativeが策定 • 現在はOpenAPI 2.0

    主要なツールセット • Swagger Editor(エディタ) • Swagger UI(ビューア) • Swagger Codegen(コード生成ツール) 18
  19. 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
  20. 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
  21. 21 Gradle Swagger Generator Plugin Gradleで各種ジェネレータを利用できるプラグイン • OpenAPI YAMLのバリデーション •

    Swagger Codegenによるコード生成 • Swagger UIの生成 • ReDocの生成 https://github.com/int128/gradle-swagger-generator-plugin
  22. 3. サービス開発におけるOpenAPIの利用 22

  23. サービス開発におけるOpenAPIの利用 23 ビュー API Client Controller ビジネスロジック API Client PHP7

    Spring (Java8) YAML フロントエンド チーム バックエンド チーム Swagger UI API連携でコード生成とAPIドキュメント生成を利用している YAML コンテンツ プロバイダ 外部サービス
  24. Swagger Codegenテンプレートのカスタマイズ Spring MVCテンプレート(APIサーバ) 1. リクエストモデルのバリデーションを追加 2. 独自バリデータ対応 3. サービスクラスをDIして呼び出すように変更

    Spring Cloudテンプレート(APIクライアント) 1. API Proxyの生成 24
  25. ★リクエストパラメータのチェック (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
  26. 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
  27. 生成したコードを一切修正せずに利用するため、ControllerからServiceの呼び出しを追 加 @RestController public class HelloController { @Autowired private HelloService

    helloService; @RequestMapping(“/foo/{id}”) public ResponseEntity<FooRequest> foo(@PathVariable(“id”) int id) { return helloService.foo(id); } public interface HelloService { ... } } Spring MVCテンプレートの改造(3/3) 27 アプリケーション側でServiceを 実装して実行時にDI
  28. API Proxyの自動生成 フロントエンドと外部サービスをつなぐ一部のAPIはビジネスロジックが必要なかったた め、ControllerからAPIクライアントの呼び出しを自動生成 Controller API Client 28 フロントエンド 外部サービス

    YAML バリデーション インターセプタの共通処理 (OAuth、トレースID等)
  29. ControllerからAPIクライアントの呼び出しを生成 @RestController public class HelloController { @Autowired private final HelloClient

    helloClient; @RequestMapping(“/foo/{id}”) public ResponseEntity<FooRequest> foo(@PathVariable(“id”) int id) { return helloClient.foo(id); } } Spring Cloudテンプレートの改造 29 実際にはレスポンスの取捨選択が必要 • Content-Lengthヘッダは返さない • FeignExceptionのハンドリング
  30. (心の声) OpenAPIに対応したAPIゲートウェイでよ かったのかもしれない 30

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

    これらの仕組みを活用することで、継続的なサービス開発が可能になる 31
  32. Thank You 32