Swaggerで定義したAPI仕様から Retrofitで使用するinterfaceを自動生成してみる

Dbab5e5a1fd54531e1119ede6b3b9e65?s=47 Ryosuke Horie
November 28, 2017

Swaggerで定義したAPI仕様から Retrofitで使用するinterfaceを自動生成してみる

Dbab5e5a1fd54531e1119ede6b3b9e65?s=128

Ryosuke Horie

November 28, 2017
Tweet

Transcript

  1. © 2017 VASILY,Inc. 4XBHHFSͰఆٛͨ͠"1*࢓༷͔Β 3FUSPpUͰ࢖༻͢ΔJOUFSGBDFΛࣗಈੜ੒ͯ͠ΈΔ 2017/11/28 potatotips #45 @Horie1024

  2. © 2017 VASILY,Inc. ࣗݾ঺հ w !)PSJF w 7"4*-: *OD w

    "OESPJEΤϯδχΞ w ϏʔϧɺࣗಈԽ޷͖
  3. © 2017 VASILY,Inc. ೥݄;0;0508/΍8&"3ΛӡӦ͢Δ ελʔττΡσΠάϧʔϓʹࢀը ࢠձࣾԽ

  4. © 2017 VASILY,Inc. ࠓ೔࿩͢͜ͱ w TXBHHFSQBSTFSΛ࢖͏ͱ4XBHHFSͰఆٛͨ͠"1* ࢓༷Λίʔυ͔Β؆୯ʹѻ͑Δ w LPMUJOQPFUͱ૊Έ߹ΘͤΔͱ3FUSPpUͰ࢖༻͢Δ EBUBDMBTT΍JOUFSGBDFͷίʔυΛੜ੒Ͱ͖Δ

    w (SBEMF1MVHJOԽ͢Δͱ௙Δ
  5. © 2017 VASILY,Inc. Ϟνϕʔγϣϯ w σʔλ૚ͷίʔυΛࣗಈੜ੒͍ͨ͠

  6. © 2017 VASILY,Inc. Ͳ͏࣮ݱ͢Δʁ w ฐࣾͷ"1*࢓༷͸4XBHHFSͰఆ͍ٛͯ͠Δ

  7. © 2017 VASILY,Inc. Ͳ͏࣮ݱ͢Δʁ w ฐࣾͷ"1*࢓༷͸4XBHHFSͰఆ͍ٛͯ͠Δ w LPUMJOQPFUΛ࢖ͬͯΈ͍ͨ

  8. © 2017 VASILY,Inc. Ͳ͏࣮ݱ͢Δʁ w ฐࣾͷ"1*࢓༷͸4XBHHFSͰఆ͍ٛͯ͠Δ w LPUMJOQPFUΛ࢖ͬͯΈ͍ͨ w 4XBHHFSͰఆٛͨ͠"1*࢓༷͔Βੜ੒͠Α͏ʂ

  9. © 2017 VASILY,Inc. 4XBHHFSͰఆٛͨ͠"1*࢓༷ͷύʔε w TXBHHFSBQJTXBHHFSQBSTFSΛ࢖͏ͱ؆୯ w TXBHHFSKTPOΛಡΈࠐ·ͤΔඞཁ͕͋Δ w ϩʔΧϧͰ΋αʔό্ͷ΋ͷͰ΋0,

    // SwaggerΦϒδΣΫτ͔ΒAPI࢓༷ʹΞΫηε val swagger: Swagger = SwaggerParser().read(“swagger.json”)
  10. © 2017 VASILY,Inc. LPUMJOQPFUͰͷίʔυੜ੒ w TRVBSFLPUMJOQPFUͰੜ੒ w 4XBHHFSΦϒδΣΫτ͔Βඞཁͳ৘ใΛऔಘ w LPUMJOQPFUͰίʔυੜ੒

    w ೚ҙͷύεʹॻ͖ग़͠
  11. © 2017 VASILY,Inc. ྫ(JU)VC"1*-JTUVTFSSFQPTJUPSJFT

  12. © 2017 VASILY,Inc. 4XBHHFSͰ"1*࢓༷Λఆٛ "paths": { "/users/{username}/repos": { "get": {

    "summary": "List public repositories for the specified user.", "operationId": "listRepos", "parameters": [ { "name": "username", "in": "path", "description": "ID of pet to update", "required": true, "type": "string" }, { "name": "type", "in": "query", "description": "Can be one of all, owner, member. Default: owner", "required": false, "type": "string" }, { "name": "sort", "in": "query", "description": "Can be one of created, updated, pushed, full_name. Default: full_name", "required": false, "type": "string" }, { "name": "direction", "in": "query", "description": "Can be one of asc or desc. Default: when using full_name: asc, otherwise desc", "required": false, "type": "string" } ], "tags": [ "Users" ], "responses": { "200": { "description": "successful operation", "schema": { "type": "array", "items": { "$ref": "#/definitions/Repo" } } }, "400": { "description": "Invalid status value" } } } } }
  13. © 2017 VASILY,Inc. w ͜Μͳײ͡ͷίʔυΛੜ੒͍ͨ͠ w 4XBHHFSΦϒδΣΫτ͔Βඞཁͳ৘ใΛऔಘ w LPUMJOQPFUͰίʔυੜ੒ w

    ೚ҙͷύεʹॻ͖ग़͠ LPUMJOQPFUͰͷίʔυੜ੒ interface UsersService { @GET("/users/{username}/repos") fun listRepos( @Path("username") username: String, @Query("type") type: String? = null, @Query("sort") sort: String? = null, @Query("direction") direction: String? = null ): Single<List<Repos>> }
  14. © 2017 VASILY,Inc. ྫ6TFS4FSWJDFJOUFSGBDFͷੜ੒ FileSpec.builder("", "UserService") .addType(TypeSpec .interfaceBuilder("UserService") .addFunction(FunSpec.builder("listRepos") .addModifiers(KModifier.ABSTRACT).build()

    ).build() ).build() interface UsersService { fun listRepos() }
  15. © 2017 VASILY,Inc. ྫ6TFS4FSWJDFJOUFSGBDFͷੜ੒ FileSpec.builder("", "UserService") .addType(TypeSpec .interfaceBuilder("UserService") .addFunction(FunSpec.builder("listRepos") .addModifiers(KModifier.ABSTRACT)

    .addAnnotation(AnnotationSpec.builder(GET::class) .addMember("\"/users/{username}/repos\"") .build()).build() ).build() ).build().writeTo(System.out) interface UserService { @GET("/users/{username}/repos") fun listRepos() }
  16. © 2017 VASILY,Inc. ྫ6TFS4FSWJDFJOUFSGBDFͷੜ੒ FileSpec.builder("", "UserService") .addType(TypeSpec .interfaceBuilder("UserService") .addFunction(FunSpec.builder("listRepos") .addModifiers(KModifier.ABSTRACT)

    .addAnnotation(AnnotationSpec.builder(GET::class) .addMember("\"/users/{username}/repos\"") .build()) .returns(ParameterizedTypeName.get(Single::class.asTypeName(), ParameterizedTypeName.get(List::class.asTypeName(), ClassName("", "Repo")) )).build() ).build() ).build() interface UserService { @GET("/users/{username}/repos") fun listRepos(): Single<List<Repo>> }
  17. © 2017 VASILY,Inc. ྫ6TFS4FSWJDFJOUFSGBDFͷੜ੒ FileSpec.builder("", "UserService") .addType(TypeSpec .interfaceBuilder("UserService") .addFunction(FunSpec.builder("listRepos") .addModifiers(KModifier.ABSTRACT)

    .addAnnotation(AnnotationSpec.builder(GET::class) .addMember("\"/users/{username}/repos\"") .build()) .addParameter(ParameterSpec.builder("username", String::class.asTypeName().asNonNullable()) .addAnnotation(AnnotationSpec.builder(Path::class).addMember("\"username\"").build()) .build()) .returns(ParameterizedTypeName.get(Single::class.asTypeName(), ParameterizedTypeName.get(List::class.asTypeName(), ClassName("", "Repo")) )).build() ).build() ).build() interface UserService { @GET("/users/{username}/repos") fun listRepos(@Path("username") username: String): Single<List<Repo>> }
  18. © 2017 VASILY,Inc. LPUMJOQPFUͰͷίʔυੜ੒ interface UsersService { @GET("/users/{username}/repos") fun listRepos(

    @Path("username") username: String, @Query("type") type: String? = null, @Query("sort") sort: String? = null, @Query("direction") direction: String? = null ): Single<List<Repos>> } "paths": { "/users/{username}/repos": { "get": { "operationId": "listRepos", "parameters": [ { "name": "username", "in": "path", "description": "ID of pet to update", "required": true, "type": "string" }, { "name": "type", "in": "query", "required": false, "type": "string" }, { "name": "sort", "in": "query", "required": false, "type": "string" }, { "name": "direction", "in": "query", "required": false, "type": "string" } ], "tags": [ "Users" ],
  19. © 2017 VASILY,Inc. LPUMJOQPFUͰͷίʔυੜ੒ interface UsersService { @GET("/users/{username}/repos") fun listRepos(

    @Path("username") username: String, @Query("type") type: String? = null, @Query("sort") sort: String? = null, @Query("direction") direction: String? = null ): Single<List<Repos>> } "paths": { "/users/{username}/repos": { "get": { "operationId": "listRepos", "parameters": [ { "name": "username", "in": "path", "description": "ID of pet to update", "required": true, "type": "string" }, { "name": "type", "in": "query", "required": false, "type": "string" }, { "name": "sort", "in": "query", "required": false, "type": "string" }, { "name": "direction", "in": "query", "required": false, "type": "string" } ], "tags": [ "Users" ],
  20. © 2017 VASILY,Inc. LPUMJOQPFUͰͷίʔυੜ੒ interface UsersService { @GET("/users/{username}/repos") fun listRepos(

    @Path("username") username: String, @Query("type") type: String? = null, @Query("sort") sort: String? = null, @Query("direction") direction: String? = null ): Single<List<Repos>> } "paths": { "/users/{username}/repos": { "get": { "operationId": "listRepos", "parameters": [ { "name": "username", "in": "path", "description": "ID of pet to update", "required": true, "type": "string" }, { "name": "type", "in": "query", "required": false, "type": "string" }, { "name": "sort", "in": "query", "required": false, "type": "string" }, { "name": "direction", "in": "query", "required": false, "type": "string" } ], "tags": [ "Users" ],
  21. © 2017 VASILY,Inc. LPUMJOQPFUͰͷίʔυੜ੒ interface UsersService { @GET("/users/{username}/repos") fun listRepos(

    @Path("username") username: String, @Query("type") type: String? = null, @Query("sort") sort: String? = null, @Query("direction") direction: String? = null ): Single<List<Repos>> } "paths": { "/users/{username}/repos": { "get": { "operationId": "listRepos", "parameters": [ { "name": "username", "in": "path", "description": "ID of pet to update", "required": true, "type": "string" }, { "name": "type", "in": "query", "required": false, "type": "string" }, { "name": "sort", "in": "query", "required": false, "type": "string" }, { "name": "direction", "in": "query", "required": false, "type": "string" } ], "tags": [ "Users" ],
  22. © 2017 VASILY,Inc. LPUMJOQPFUͰͷίʔυੜ੒ interface UsersService { @GET("/users/{username}/repos") fun listRepos(

    @Path("username") username: String, @Query("type") type: String? = null, @Query("sort") sort: String? = null, @Query("direction") direction: String? = null ): Single<List<Repos>> } "paths": { "/users/{username}/repos": { "get": { "operationId": "listRepos", "parameters": [ { "name": "username", "in": "path", "description": "ID of pet to update", "required": true, "type": "string" }, { "name": "type", "in": "query", "required": false, "type": "string" }, { "name": "sort", "in": "query", "required": false, "type": "string" }, { "name": "direction", "in": "query", "required": false, "type": "string" } ], "tags": [ "Users" ],
  23. © 2017 VASILY,Inc. LPUMJOQPFUͰͷίʔυੜ੒ interface UsersService { @GET("/users/{username}/repos") fun listRepos(

    @Path("username") username: String, @Query("type") type: String? = null, @Query("sort") sort: String? = null, @Query("direction") direction: String? = null ): Single<List<Repos>> } "responses": { "200": { "description": "successful operation", "schema": { "type": "array", "items": { "$ref": "#/definitions/Repo" } } }, "400": { "description": "Invalid status value" } } } } }, "definitions": { "Repo": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "url": { "type": "string" } } } }
  24. © 2017 VASILY,Inc. LPUMJOQPFUͰͷίʔυੜ੒ interface UsersService { @GET("/users/{username}/repos") fun listRepos(

    @Path("username") username: String, @Query("type") type: String? = null, @Query("sort") sort: String? = null, @Query("direction") direction: String? = null ): Single<List<Repo>> } "responses": { "200": { "description": "successful operation", "schema": { "type": "array", "items": { "$ref": "#/definitions/Repo" } } }, "400": { "description": "Invalid status value" } } } } }, "definitions": { "Repo": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "url": { "type": "string" } } } }
  25. © 2017 VASILY,Inc. LPUMJOQPFUͰͷίʔυੜ੒ data class Repo( val id: String,

    val name: String, val url: String ) "responses": { "200": { "description": "successful operation", "schema": { "type": "array", "items": { "$ref": "#/definitions/Repo" } } }, "400": { "description": "Invalid status value" } } } } }, "definitions": { "Repo": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "url": { "type": "string" } } } }
  26. © 2017 VASILY,Inc. (SBEMF1MVHJOԽ w ͪ͜ΒͷϖʔδΛࢀߟʹ,PUMJOͰ࣮૷ w IUUQTXXXUIFESPJETPOSPJETDPNCMPH IPXUPDSFBUFHSBEMFQMVHJOJOLPUMJO w

    ɹɹɹɹɹɹɹɹɹɹɹͰੜ੒Λ࣮ߦ ./gradlew generateDataLayer
  27. © 2017 VASILY,Inc. σϞ

  28. © 2017 VASILY,Inc. ·ͱΊ w TXBHHFSQBSTFSΛ࢖͏ͱ4XBHHFSͰఆٛͨ͠"1* ࢓༷Λίʔυ͔Β؆୯ʹѻ͑Δ w LPUMJOQPFUΛ࢖͏ͱ,PMUJOͷίʔυΛ؆୯ʹੜ੒Ͱ ͖Δ

    w (SBEMF1MVHJO΋,PUMJOͰॻָ͚͍ͯ͠
  29. © 2017 VASILY,Inc. ͋Γ͕ͱ͏͍͟͝·ͨ͠