Edited at

SpringFoxで吐き出したSwaggerのjsonを使ってswagger-codegenでAPIのclientを吐き出す


この資料について


  • swagger-codegenを使ってRestTemplateを使ったClientを吐き出すやり方をまとめた


  • SpringFoxの内容と合わせて見てほしい

  • あくまで自分が使いそうって思ったものしかまとめてないです


swagger-codegenについて


  • 公式はこちら Swagger Codegen | API Development Tools | Swagger

  • スタブやClientを吐き出してくれるジェネレーター

  • いろんな言語やライブラリに対応していて、RestTemplate以外にもretrofitとかにも対応してるし、そもそもjava以外にもswiftとかnodeとか結構いろいろ対応している

  • コードは一つのプロジェクトとして吐き出されて、jarにまとめてmavenリポジトリとかに上げてdependencyに追加して利用するとかできる

  • 出力されたコードはライセンスとか気にせず自分が作ったものとして利用できる


とりあえず使ってみる


swaggerのjsonを準備する


  • 今回はSpringFoxで出力されたjsonを利用する。そのためアプリケーションを起動してjsonを読み取れるようにすればOK。一応json置いとく(人が読み取れるものではないのでフォーマットとか無視)

  • localでSpringFoxに対応したアプリケーションを立ち上げている場合は http://localhost:8080/v2/api-docs をアクセスすれば見れる

{"swagger":"2.0","info":{"description":"Api Documentation","version":"1.0","title":"Api Documentation","termsOfService":"urn:tos","contact":{},"license":{"name":"Apache 2.0","url":"http://www.apache.org/licenses/LICENSE-2.0"}},"host":"localhost:8080","basePath":"/","tags":[{"name":"families","description":"families info"}],"schemes":["http","https"],"paths":{"/families":{"post":{"tags":["families"],"summary":"create","operationId":"createUsingPOST","consumes":["application/json"],"produces":["*/*"],"parameters":[{"in":"body","name":"familyRequest","description":"familyRequest","required":true,"schema":{"$ref":"#/definitions/FamilyRequest"}}],"responses":{"200":{"description":"OK","schema":{"type":"object"}},"400":{"description":"Parameter is invalid"},"401":{"description":"認証エラー"},"500":{"description":"Internel server error"}},"deprecated":false}},"/families/list":{"get":{"tags":["families"],"summary":"list","operationId":"listUsingGET","produces":["*/*"],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/FamiliesListResponse"}},"400":{"description":"Parameter is invalid"},"500":{"description":"Internel server error"}},"deprecated":false}},"/families/{familyId}":{"get":{"tags":["families"],"summary":"findFamily","operationId":"findFamilyUsingGET","produces":["*/*"],"parameters":[{"name":"familyId","in":"path","description":"familyId","required":true,"type":"integer","format":"int32"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/Family"}},"400":{"description":"Parameter is invalid"},"500":{"description":"Internel server error"}},"deprecated":false}},"/families/{familyId}/members/list":{"get":{"tags":["families"],"summary":"findMembersByFamilyId","operationId":"findMembersByFamilyIdUsingGET","produces":["*/*"],"parameters":[{"name":"familyId","in":"path","description":"familyId","required":true,"type":"integer","format":"int32"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/MembersResponse"}},"400":{"description":"Parameter is invalid"},"500":{"description":"Internel server error"}},"deprecated":false}}},"definitions":{"FamiliesListResponse":{"type":"object","properties":{"families":{"type":"array","items":{"$ref":"#/definitions/Family"}}},"title":"FamiliesListResponse"},"Family":{"type":"object","properties":{"familyId":{"type":"integer","format":"int32"},"familyName":{"type":"string"},"updatetime":{"type":"string","format":"date-time"}},"title":"Family"},"FamilyRequest":{"type":"object","properties":{"familyId":{"type":"integer","format":"int32"},"familyName":{"type":"string"},"members":{"type":"array","items":{"$ref":"#/definitions/MemberRequest"}},"updatetime":{"type":"string","format":"date-time"}},"title":"FamilyRequest"},"Member":{"type":"object","properties":{"birthday":{"type":"string","format":"date"},"gender":{"type":"string","enum":["MALE","FEMALE","ETC","NONE"]},"givenName":{"type":"string"},"memberId":{"type":"integer","format":"int32"},"updatetime":{"type":"string","format":"date-time"}},"title":"Member"},"MemberRequest":{"type":"object","properties":{"birthday":{"type":"string","format":"date"},"gender":{"type":"string","enum":["MALE","FEMALE","ETC"]},"givenName":{"type":"string"},"memberId":{"type":"integer","format":"int32"}},"title":"MemberRequest"},"MembersResponse":{"type":"object","properties":{"members":{"type":"array","items":{"$ref":"#/definitions/Member"}}},"title":"MembersResponse"}}}


configファイルをつくる


  • 名前は適当でいいのでconfigファイルをつくる。今回はswagger-codegen-config.jsonとした

{

"java8" : true,
"dateLibrary": "java8-localdatetime",
"apiPackage": "com.example.tryspringfox.client",
"modelPackage": "com.example.tryspringfox.model",
"library": "resttemplate",
"hideGenerationTimestamp": true
}


configの解説


  • 詳しくは下記コマンドを実行して確認すること。今回指定したものだけさらっと書いとく

  • けっこういろいろ指定できる。BigDecimalを文字列として扱う、とかそういう細かいのもある

$ swagger-codegen config-help -l java

設定
設定値
内容

java8
true,false
3rdパーティのライブラリを使うかjava8のものを使うか

dataLibrary
joda,legacy,java8-localdate,java8,threetenbp
Dateクラスで何使うか指定

apiPackage
パッケージのパス(com.exampleとか)
生成されるAPIクラスのパッケージを指定

modelPackage
パッケージのパス(com.exampleとか)
生成されるModelクラスのパッケージを指定

library
restTemplateとか
生成されるクライアントが依存するライブラリを指定

hideGenerationTimestamp
true,false
生成されるコードに生成日を記載するか


オプションを指定して生成してみる


  • 下記のオプションを指定して動かす

$ swagger-codegen generate \

-i http://localhost:8080/v2/api-docs \
-l java \
-c ./swagger-codegen-config.json \
-o ../try-swagger-codegen-client


オプションの解説

オプション
内容

-i
swaggerのjsonへのパス

-l
言語の指定。javaとか

-c
configファイルへのパス

-o
出力先のパス


生成したものを使う


  • jarをdependencyに登録する(ローカルでやる場合は適当な場所に設置して下記みたいなかんじでやる)

  • 下記のようにDIに登録してあげればあとはよしなに使える

dependencies {

...
compile files("jarのパス")
...
}

@Configuration

public class ApiClientConfig {

@Autowired
RestTemplateBuilder restTemplateBuilder;

@Bean
public FamiliesApi familiesApi(){
return new FamiliesApi(apiClient());
}

@Bean
public ApiClient apiClient() {
RestTemplate restTemplate = restTemplateBuilder.setReadTimeout(1000).setConnectTimeout(1000).build();
ApiClient apiClient = new ApiClient(restTemplate);
apiClient.setBasePath("http://prod.hostname.com");
return apiClient;
}
}


使ってみて雑感


  • ホストがswaggerの仕様だと固定されてしまうが、上記のように変更できる

  • RestTemplateをApiClientクラスをインスタンス化するときに引数として渡せるので、やりたいことはたいてい自前でいろいろ設定できそう

  • クライアントクラスのテストは生成されないが仕様通りにリクエストはできるので、生成されるコードに関してはテストをやらないっていう選択肢はありだと思う

  • 普通にインターセプターとかも使えるので、共通でヘッダを追加したい、とかも問題なく可能

  • jarとしてmavenリポジトリに登録できるので、いろいろなところで同じクライアントクラスをつくる、っていうことにはならなそうなので、マイクロサービス化しているシステムを開発している場合は利用してみても良いと思う


参考にした資料


関連記事

SpringFoxを使ってSwaggerのjsonを吐き出す