Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

Hidetake Iwata
September 30, 2017

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

第二十回 #渋谷java

Hidetake Iwata

September 30, 2017
Tweet

More Decks by Hidetake Iwata

Other Decks in Technology

Transcript

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    ● Excelは適さないのでダメ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  16. 2. What is OpenAPI?
    17

    View full-size slide

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

    View full-size slide

  18. 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

    View full-size slide

  19. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  24. ★リクエストパラメータのチェック (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

    View full-size slide

  25. 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

    View full-size slide

  26. 生成したコードを一切修正せずに利用するため、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

    View full-size slide

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

    View full-size slide

  28. 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のハンドリング

    View full-size slide

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

    View full-size slide

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

    View full-size slide