Let me write your Networking Code

Let me write your Networking Code

Let me write your networking code
=====

When writing networking code, you want to make sure the code between the client and server implementation is consistent. After spending hours defining the APIs with your backend engineers, you’ll probably need to spend even more time implementing those details over to your code (and guess what… your backend engineers will be doing the same!). This process is boring, time consuming, and prone to errors.

Wouldn’t it be cool if this process were automated? If you could have classes and interfaces that mirror your API definition? And if they were automatically tested and ready to use out of the box?

It can be done! At Yelp, we define our APIs using Swagger Specs and we successfully automated the generation of our networking code for both servers and clients (iOS & Android). On Android, we generate Kotlin Data Classes and Retrofit APIs that mirror our spec files and are ready to use for all engineers. In this talk, we will explore how we set up our code generation pipeline and how you can start doing it, too.

3dc29e8cfc6ef333e2b41a1b0e826b57?s=128

Nicola Corti

April 02, 2019
Tweet

Transcript

  1. Let me write your networking code Nicola Corti @cortinico

  2. YELP CORP DECK Footnote should go here

  3. LET ME WRITE YOUR NETWORKING CODE Nicola Corti Android Infra

    Engineer @cortinico Community Lover
 (GDG Pisa - Kotlin Hamburg) ! ✈
  4. None
  5. Photo by Brianna Santellan on Unsplash

  6. GET Photo by Brianna Santellan on Unsplash

  7. GET-/pet/corgi Photo by Brianna Santellan on Unsplash

  8. None
  9. Photo by Hannah Lim on Unsplash

  10. petstore.swagger.io You can’t just GET-/pet/corgi Photo by Hannah Lim on

    Unsplash
  11. Swagger & Open API

  12. Open API The Specification Swagger The Tooling Define the API

    in a JSON/YAML files Build infrastructure around them SWAGGER Swagger & Open API
  13. None
  14. !!--- swagger: '2.0'

  15. !!--- swagger: '2.0' info:

  16. !!--- swagger: '2.0' info: description: 'This is a sample server

    Petstore server'
  17. !!--- swagger: '2.0' info: description: 'This is a sample server

    Petstore server' version: 1.0.0
  18. !!--- swagger: '2.0' info: description: 'This is a sample server

    Petstore server' version: 1.0.0 title: Swagger Petstore
  19. !!--- swagger: '2.0' info: description: 'This is a sample server

    Petstore server' version: 1.0.0 title: Swagger Petstore contact: email: apiteam@swagger.io
  20. !!--- swagger: '2.0' info: description: 'This is a sample server

    Petstore server' version: 1.0.0 title: Swagger Petstore contact: email: apiteam@swagger.io license: name: Apache 2.0 url: http:!//!!www.apache.org/licenses/LICENSE-2.0.html
  21. !!--- swagger: '2.0' info: description: 'This is a sample server

    Petstore server' version: 1.0.0 title: Swagger Petstore contact: email: apiteam@swagger.io license: name: Apache 2.0 url: http:!//!!www.apache.org/licenses/LICENSE-2.0.html host: petstore.swagger.io
  22. !!--- swagger: '2.0' info: description: 'This is a sample server

    Petstore server' version: 1.0.0 title: Swagger Petstore contact: email: apiteam@swagger.io license: name: Apache 2.0 url: http:!//!!www.apache.org/licenses/LICENSE-2.0.html host: petstore.swagger.io basePath: "/v2"
  23. !!--- swagger: '2.0' info: description: 'This is a sample server

    Petstore server' version: 1.0.0 title: Swagger Petstore contact: email: apiteam@swagger.io license: name: Apache 2.0 url: http:!//!!www.apache.org/licenses/LICENSE-2.0.html host: petstore.swagger.io basePath: "/v2" schemes: - https - http
  24. basePath: “/v2" schemes: - https - http definitions:

  25. basePath: “/v2" schemes: - https - http definitions: Pet:

  26. basePath: “/v2" schemes: - https - http definitions: Pet: type:

    object
  27. basePath: “/v2" schemes: - https - http definitions: Pet: type:

    object properties: 

  28. basePath: “/v2" schemes: - https - http definitions: Pet: type:

    object properties: id: type: integer format: int64

  29. basePath: “/v2" schemes: - https - http definitions: Pet: type:

    object properties: id: type: integer format: int64 name: type: string
  30. basePath: “/v2" schemes: - https - http definitions: Pet: type:

    object properties: id: type: integer format: int64 name: type: string photoUrls: type: array items: type: string
  31. definitions: Pet: type: object required: - name - photoUrls properties:

    id: type: integer format: int64 name: type: string photoUrls: type: array items: type: string 

  32. properties: id: type: integer format: int64 name: type: string photoUrls:

    type: array items: type: string status: type: string 

  33. properties: id: type: integer format: int64 name: type: string photoUrls:

    type: array items: type: string status: type: string description: pet status in the store 

  34. properties: id: type: integer format: int64 name: type: string photoUrls:

    type: array items: type: string status: type: string description: pet status in the store enum: - available - sold 

  35. properties: id: type: integer format: int64 name: type: string photoUrls:

    type: array items: type: string status: type: string description: pet status in the store enum: - available - sold category: 

  36. properties: id: type: integer format: int64 name: type: string photoUrls:

    type: array items: type: string status: type: string description: pet status in the store enum: - available - sold category: $ref: “#/definitions/Category"
  37. definitions: Pet: type: object required: - name - photoUrls properties:

    id: type: integer format: int64 name: type: string photoUrls: type: array items: type: string status: type: string description: pet status in the store enum: - available - sold category: $ref: “#/definitions/Category" 

  38. definitions: Pet: type: object required: - name - photoUrls properties:

    id: type: integer format: int64 name: type: string photoUrls: type: array items: type: string status: type: string description: pet status in the store enum: - available - sold category: $ref: “#/definitions/Category" 
 Category:
  39. definitions: Pet: type: object required: - name - photoUrls properties:

    id: type: integer format: int64 name: type: string photoUrls: type: array items: type: string status: type: string description: pet status in the store enum: - available - sold category: $ref: “#/definitions/Category" 
 Category: type: object
  40. definitions: Pet: type: object required: - name - photoUrls properties:

    id: type: integer format: int64 name: type: string photoUrls: type: array items: type: string status: type: string description: pet status in the store enum: - available - sold category: $ref: “#/definitions/Category" 
 Category: type: object properties: id: type: integer format: int64
  41. definitions: Pet: type: object required: - name - photoUrls properties:

    id: type: integer format: int64 name: type: string photoUrls: type: array items: type: string status: type: string description: pet status in the store enum: - available - sold category: $ref: “#/definitions/Category" 
 Category: type: object properties: id: type: integer format: int64 name: type: string
  42. None
  43. paths:

  44. paths: /pet/{petId}:

  45. paths: /pet/{petId}: get:

  46. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet
  47. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById
  48. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json
  49. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters:
  50. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters: - name: petId
  51. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters: - name: petId in: path
  52. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters: - name: petId in: path description: ID of pet to return
  53. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters: - name: petId in: path description: ID of pet to return required: true
  54. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters: - name: petId in: path description: ID of pet to return required: true type: integer
  55. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters: - name: petId in: path description: ID of pet to return required: true type: integer format: int64
  56. - name: petId in: path description: ID of pet to

    return required: true type: integer format: int64
  57. - name: petId in: path description: ID of pet to

    return required: true type: integer format: int64 responses:
  58. - name: petId in: path description: ID of pet to

    return required: true type: integer format: int64 responses: '200':
  59. - name: petId in: path description: ID of pet to

    return required: true type: integer format: int64 responses: '200': description: successful operation
  60. - name: petId in: path description: ID of pet to

    return required: true type: integer format: int64 responses: '200': description: successful operation '404':
  61. - name: petId in: path description: ID of pet to

    return required: true type: integer format: int64 responses: '200': description: successful operation '404': description: Pet not found
  62. - name: petId in: path description: ID of pet to

    return required: true type: integer format: int64 responses: '200': description: successful operation schema: $ref: "" '404': description: Pet not found
  63. - name: petId in: path description: ID of pet to

    return required: true type: integer format: int64 responses: '200': description: successful operation schema: $ref: "#/definitions/Pet" '404': description: Pet not found
  64. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters: - name: petId in: path description: ID of pet to return required: true type: integer format: int64 responses: '200': description: successful operation schema: $ref: "#/definitions/Pet" '404': description: Pet not found
  65. SWAGGER UI

  66. SWAGGER EDITOR

  67. GET-/pet/corgi Photo by Brianna Santellan on Unsplash

  68. GET-/pet/42 Photo by Brianna Santellan on Unsplash

  69. None
  70. None
  71. public Pet getPet(final String id) { String https_url = "https:!//petstore.swagger.io/v2/pet/"

    + id; URL url; try { url = new URL(https_url); HttpsURLConnection con = (HttpsURLConnection) url.openConnection(); if (con !!= null) { BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream())); String response = ""; String input; while ((input = br.readLine()) !!= null) { System.out.println(input); response += input; } br.close(); JSONObject object = new JSONObject(response); Pet result = new Pet(); result.setId(object.getInt("id")); result.setName(object.getString("name")); result.setStatus(object.getString("status")); JSONArray photos = object.getJSONArray("photoUrls"); List<String> photoArrays = new ArrayList!<>(); for (int i = 0; i < photos.length(); i!++) { photoArrays.add(photos.getString(i)); } result.setPhotoUrls(photoArrays); JSONArray tags = object.getJSONArray("tags"); List<String> tagArrays = new ArrayList!<>(); for (int i = 0; i < tags.length(); i!++) { tagArrays.add(tags.getString(i)); } result.setTags(tagArrays); System.out.println(result); System.out.println(result.getId()); System.out.println(result.getName()); System.out.println(result.getPhotoUrls().get(0)); System.out.println(result.getStatus()); System.out.println(result.getTags().get(0)); return result; } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (JSONException e) { e.printStackTrace(); } return null; } public class Pet { private Integer id; private String name; private List<String> photoUrls = null; private List<String> tags = null; private String status; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getPhotoUrls() { return photoUrls; } public void setPhotoUrls(List<String> photoUrls) { this.photoUrls = photoUrls; } public List<String> getTags() { return tags; } public void setTags(List<String> tags) { this.tags = tags; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } } fun getPet(id: String): Pet? { val https_url = "https:!//petstore.swagger.io/v2/pet/$id" val url: URL try { url = URL(https_url) val con = url.openConnection() as HttpsURLConnection val br = BufferedReader(InputStreamReader(con.inputStream)) var response = "" var input: String? = br.readLine() while (input !!= null) { println(input) response += input input = br.readLine() } br.close() val parsedObject = JSONObject(response) val photos = parsedObject.getJSONArray("photoUrls") val photoArrays = ArrayList<String>() for (i in 0 until photos.length()) { photoArrays.add(photos.getString(i)) } val tags = parsedObject.getJSONArray("tags") val tagArrays = ArrayList<String>() for (i in 0 until tags.length()) { tagArrays.add(tags.getString(i)) } val result = Pet( id = parsedObject.getInt("id"), name = parsedObject.getString("name"), status = parsedObject.getString("status"), photoUrls = photoArrays, tags = tagArrays ) println(result) println(result.id) println(result.name) println(result.photoUrls!!![0]) println(result.status) println(result.tags!!![0]) return result } catch (e: MalformedURLException) { e.printStackTrace() } catch (e: IOException) { e.printStackTrace() } catch (e: JSONException) { e.printStackTrace() } return null } data class Pet( var id: Int?, var name: String?, var photoUrls: List<String>?, var tags: List<String>?, var status: String? ) data class Tag(var id: Int?, var name: String?) fun getPet(id: String): Pet? { val https_url = "https:!//petstore.swagger.io/v2/pet/$id" val url: URL try { url = URL(https_url) val con = url.openConnection() as HttpsURLConnection val br = BufferedReader(InputStreamReader(con.inputStream)) var response = "" var input: String? = br.readLine() while (input !!= null) { println(input) response += input input = br.readLine() } br.close() val moshi = Moshi.Builder().build() val jsonAdapter = moshi.adapter<Pet>(Pet!::class.java) val pet = jsonAdapter.fromJson(response) println(pet) return pet } catch (e: MalformedURLException) { e.printStackTrace() } catch (e: IOException) { e.printStackTrace() } return null } data class Pet( var id: Int?, var name: String?, var photoUrls: List<String>?, var tags: List<Tag>?, var status: String? ) data class Tag(var id: Int?, var name: String?) fun getPet(id: String): Pet? { val client = OkHttpClient.Builder().build() val request = Request.Builder().url("https:!//petstore.swagger.io/v2/pet/$id").build() client.newCall(request).execute().use { val moshi = Moshi.Builder().build() val jsonAdapter = moshi.adapter<Pet>(Pet!::class.java) val pet = jsonAdapter.fromJson(it.body()!?.string()!!!) println(pet) return pet } } data class Pet( var id: Int?, var name: String?, var photoUrls: List<String>?, var tags: List<Tag>?, var status: String? ) data class Tag(var id: Int?, var name: String?)
  72. r.io/v2/pet/$id" tpsURLConnection eader(con.inputStream)) (Pet!::class.java) nse) g?) fun getPet(id: String): Pet?

    { val client = OkHttpClient.Builder().build() val request = Request.Builder().url("https:!//petstore.swagger.io/v2/pet/$id").build() client.newCall(request).execute().use { val moshi = Moshi.Builder().build() val jsonAdapter = moshi.adapter<Pet>(Pet!::class.java) val pet = jsonAdapter.fromJson(it.body()!?.string()!!!) println(pet) return pet } } data class Pet( var id: Int?, var name: String?, var photoUrls: List<String>?, var tags: List<Tag>?, var status: String? ) data class Tag(var id: Int?, var name: String?)
  73. r.io/v2/pet/$id" tpsURLConnection eader(con.inputStream)) (Pet!::class.java) nse) g?) fun getPet(id: String): Pet?

    { val client = OkHttpClient.Builder().build() val request = Request.Builder().url("https:!//petstore.swagger.io/v2/pet/$id").build() client.newCall(request).execute().use { val moshi = Moshi.Builder().build() val jsonAdapter = moshi.adapter<Pet>(Pet!::class.java) val pet = jsonAdapter.fromJson(it.body()!?.string()!!!) println(pet) return pet } } data class Pet( var id: Int?, var name: String?, var photoUrls: List<String>?, var tags: List<Tag>?, var status: String? ) data class Tag(var id: Int?, var name: String?) interface PetInterface { @GET("pet/{id}") fun getPet(@Path("id") id: String?) : Call<Pet> } .getPet(“42")
  74. Swagger Codegen

  75. SWAGGER CODEGEN

  76. On Github: swagger-api/swagger-codegen Generator & Templates Several templates already available

    Command line tool SWAGGER CODEGEN Swagger Codegen java -jar swagger-codegen-cli-2.3.1.jar generate \ -i swagger.yaml \ --api-package com.yelp.codegen.sample.api \ --model-package com.yelp.codegen.sample.model \ --group-id com.yelp.codegen.sample \ --artifact-id sample-codegen \ --artifact-version 0.0.1 \ -l spring \ -o sample-codegen
  77. {{#model}}{{#description}} /** * {{description}} **/{{/description}} @ApiModel(description = "{{{description}}}") public class

    {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} { {{#vars}}{{#isEnum}} public enum {{datatypeWithEnum}} { {{#allowableValues}}{{#values}} {{•}}, {{/values}}{{/allowableValues}} }; @SerializedName("{{baseName}}") private {{{datatypeWithEnum}}} {{name}} = {{{defaultValue}}};{{/isEnum}}{{^isEnum}} @SerializedName("{{baseName}}") private {{{datatype}}} {{name}} = {{{defaultValue}}};{{/isEnum}}{{/vars}} {{#vars}} /**{{#description}} * {{{description}}}{{/description}}{{#minimum}} * minimum: {{minimum}}{{/minimum}}{{#maximum}} * maximum: {{maximum}}{{/maximum}} **/ @ApiModelProperty({{#required}}required = {{required}}, {{/required}}value = "{{{description}}}") public {{{datatypeWithEnum}}} {{getter}}() { return {{name}}; } public void {{setter}}({{{datatypeWithEnum}}} {{name}}) { this.{{name}} = {{name}}; }
  78. {{#model}}{{#description}} /** * {{description}} **/{{/description}} @ApiModel(description = "{{{description}}}") public class

    {{classname}} {{#parent}}extends {{{p {{#vars}}{{#isEnum}} public enum {{datatypeWithEnum}} { {{#allowableValues}}{{#values}} {{•}}, {{/valu }; @SerializedName("{{baseName}}") private {{{datatypeWithEnum}}} {{name}} = {{{def
  79. {{#model}}{{#description}} /** * {{description}} **/{{/description}} @ApiModel(description = "{{{description}}}") public class

    {{classname}} {{#parent}}extends {{{p {{#vars}}{{#isEnum}} public enum {{datatypeWithEnum}} { {{#allowableValues}}{{#values}} {{•}}, {{/valu }; @SerializedName("{{baseName}}") private {{{datatypeWithEnum}}} {{name}} = {{{def
  80. Swagger Gradle
 Codegen

  81. SWAGGER GRADLE CODEGEN

  82. Plug it inside your gradle build Input/Output aware Simpler API

    for the developer SWAGGER GRADLE CODEGEN Yelp/swagger-gradle-codegen A Gradle Plugin
  83. SWAGGER GRADLE CODEGEN Yelp/swagger-gradle-codegen Opinionated ✓ Kotlin ✓ RxJava2 ✓

    Retrofit ✓ Moshi ✓ ThreeTenABP
  84. None
  85. definitions: Pet: type: object required: - name - photoUrls properties:

    id: type: integer format: int64 name: type: string photoUrls: type: array items: type: string status: type: string description: pet status in the store enum: - available - sold category: $ref: “#/definitions/Category" 
 Category: type: object properties: id: type: integer format: int64 name: type: string
  86. Category: type: object properties: id: type: integer format: int64 name:

    type: string
  87. Category: type: object properties: id: type: integer format: int64 name:

    type: string class Category()
  88. Category: type: object properties: id: type: integer format: int64 name:

    type: string data class Category()
  89. Category: type: object properties: id: type: integer format: int64 name:

    type: string data class Category( var id, var name )
  90. Category: type: object properties: id: type: integer format: int64 name:

    type: string data class Category( var id: Long, var name: String )
  91. Category: type: object properties: id: type: integer format: int64 name:

    type: string data class Category( var id: Long?, var name: String? )
  92. Category: type: object properties: id: type: integer format: int64 name:

    type: string data class Category( var id: Long? = null, var name: String? = null )
  93. Category: type: object properties: id: type: integer format: int64 name:

    type: string data class Category( @Json(name = "id") var id: Long? = null, @Json(name = "name") var name: String? = null )
  94. Category: type: object properties: id: type: integer format: int64 name:

    type: string import com.squareup.moshi.Json data class Category( @Json(name = "id") var id: Long? = null, @Json(name = "name") var name: String? = null )
  95. Category: type: object description: properties: id: type: integer description: format:

    int64 name: type: string description: import com.squareup.moshi.Json data class Category( @Json(name = "id") var id: Long? = null, @Json(name = "name") var name: String? = null )
  96. Category: type: object description: A Category used to group pets

    properties: id: type: integer description: Unique ID of the Category format: int64 name: type: string description: Name of this category import com.squareup.moshi.Json data class Category( @Json(name = "id") var id: Long? = null, @Json(name = "name") var name: String? = null )
  97. Category: type: object description: A Category used to group pets

    properties: id: type: integer description: Unique ID of the Category format: int64 name: type: string description: Name of this category import com.squareup.moshi.Json /** * A Category used to group pets * @property id Unique ID of the Category * @property name Name of this category */ data class Category( @Json(name = "id") var id: Long? = null, @Json(name = "name") var name: String? = null )
  98. None
  99. definitions: Pet: type: object required: - name - photoUrls properties:

    id: type: integer format: int64 name: type: string photoUrls: type: array items: type: string status: type: string enum: - available - sold category: $ref: “#/definitions/Category" 

  100. definitions: Pet: type: object required: - name - photoUrls properties:

    id: type: integer format: int64 name: type: string photoUrls: type: array items: type: string status: type: string enum: - available - sold category: $ref: “#/definitions/Category" 
 package com.yelp.codegen.samples.models import com.squareup.moshi.Json data class Pet ( @Json(name = "name") var name: String, @Json(name = "photoUrls") var photoUrls: List<String>, @Json(name = "category") var category: Category? = null, @Json(name = "id") var id: Long? = null, @Json(name = "status") var status: Pet.StatusEnum? = null ) { enum class StatusEnum(val value: String){ @Json(name = "available") AVAILABLE("available"), @Json(name = "sold") SOLD("sold") } }
  101. definitions: Pet: type: object required: - name - photoUrls properties:

    id: type: integer format: int64 name: type: string photoUrls: type: array items: type: string status: type: string enum: - available - sold category: $ref: “#/definitions/Category" 
 package com.yelp.codegen.samples.models import com.squareup.moshi.Json data class Pet ( @Json(name = "name") var name: String, @Json(name = "photoUrls") var photoUrls: List<String>, @Json(name = "category") var category: Category? = null, @Json(name = "id") var id: Long? = null, @Json(name = "status") var status: Pet.StatusEnum? = null ) { enum class StatusEnum(val value: String){ @Json(name = "available") AVAILABLE("available"), @Json(name = "sold") SOLD("sold") } }
  102. definitions: Pet: type: object required: - name - photoUrls properties:

    id: type: integer format: int64 name: type: string photoUrls: type: array items: type: string status: type: string enum: - available - sold category: $ref: “#/definitions/Category" 
 package com.yelp.codegen.samples.models import com.squareup.moshi.Json data class Pet ( @Json(name = "name") var name: String, @Json(name = "photoUrls") var photoUrls: List<String>, @Json(name = "category") var category: Category? = null, @Json(name = "id") var id: Long? = null, @Json(name = "status") var status: Pet.StatusEnum? = null ) { enum class StatusEnum(val value: String){ @Json(name = "available") AVAILABLE("available"), @Json(name = "sold") SOLD("sold") } }
  103. definitions: Pet: type: object required: - name - photoUrls properties:

    id: type: integer format: int64 name: type: string photoUrls: type: array items: type: string status: type: string enum: - available - sold category: $ref: “#/definitions/Category" 
 package com.yelp.codegen.samples.models import com.squareup.moshi.Json data class Pet ( @Json(name = "name") var name: String, @Json(name = "photoUrls") var photoUrls: List<String>, @Json(name = "category") var category: Category? = null, @Json(name = "id") var id: Long? = null, @Json(name = "status") var status: Pet.StatusEnum? = null ) { enum class StatusEnum(val value: String){ @Json(name = "available") AVAILABLE("available"), @Json(name = "sold") SOLD("sold") } }
  104. definitions: Pet: type: object required: - name - photoUrls properties:

    id: type: integer format: int64 name: type: string photoUrls: type: array items: type: string status: type: string enum: - available - sold category: $ref: “#/definitions/Category" 
 package com.yelp.codegen.samples.models import com.squareup.moshi.Json data class Pet ( @Json(name = "name") var name: String, @Json(name = "photoUrls") var photoUrls: List<String>, @Json(name = "category") var category: Category? = null, @Json(name = "id") var id: Long? = null, @Json(name = "status") var status: Pet.StatusEnum? = null ) { enum class StatusEnum(val value: String){ @Json(name = "available") AVAILABLE("available"), @Json(name = "sold") SOLD("sold") } }
  105. definitions: Pet: type: object required: - name - photoUrls properties:

    id: type: integer format: int64 name: type: string photoUrls: type: array items: type: string status: type: string enum: - available - sold category: $ref: “#/definitions/Category" 
 package com.yelp.codegen.samples.models import com.squareup.moshi.Json data class Pet ( @Json(name = "name") var name: String, @Json(name = "photoUrls") var photoUrls: List<String>, @Json(name = "category") var category: Category? = null, @Json(name = "id") var id: Long? = null, @Json(name = "status") var status: Pet.StatusEnum? = null ) { enum class StatusEnum(val value: String){ @Json(name = "available") AVAILABLE("available"), @Json(name = "sold") SOLD("sold") } }
  106. definitions: Pet: type: object required: - name - photoUrls properties:

    id: type: integer format: int64 name: type: string photoUrls: type: array items: type: string status: type: string enum: - available - sold category: $ref: “#/definitions/Category" 
 package com.yelp.codegen.samples.models import com.squareup.moshi.Json /** * Represents a specific Pet in the store * @property category Optional category of the pet * @property id Unique ID of this Pet * @property name Name of this specific pet * @property photoUrls Photo URLs for this Pet on the bucket * @property status Pet status in the store */ data class Pet ( @Json(name = "name") var name: String, @Json(name = "photoUrls") var photoUrls: List<String>, @Json(name = "category") var category: Category? = null, @Json(name = "id") var id: Long? = null, @Json(name = "status") var status: Pet.StatusEnum? = null ) { /** * Pet status in the store * Values: AVAILABLE, SOLD */ enum class StatusEnum(val value: String){ @Json(name = "available") AVAILABLE("available"), @Json(name = "sold") SOLD("sold") } }
  107. None
  108. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters: - name: petId in: path description: ID of pet to return required: true type: integer format: int64 responses: '200': description: successful operation schema: $ref: "#/definitions/Pet" '404': description: Pet not found
  109. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters: - name: petId in: path description: ID of pet to return required: true type: integer format: int64 responses: '200': description: successful operation schema: $ref: "#/definitions/Pet" '404': description: Pet not found interface DefaultApi { }
  110. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters: - name: petId in: path description: ID of pet to return required: true type: integer format: int64 responses: '200': description: successful operation schema: $ref: "#/definitions/Pet" '404': description: Pet not found interface DefaultApi { fun getPetById() }
  111. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters: - name: petId in: path description: ID of pet to return required: true type: integer format: int64 responses: '200': description: successful operation schema: $ref: "#/definitions/Pet" '404': description: Pet not found interface DefaultApi { fun getPetById( @retrofit2.http.Path("petId") petId: Long ) }
  112. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters: - name: petId in: path description: ID of pet to return required: true type: integer format: int64 responses: '200': description: successful operation schema: $ref: "#/definitions/Pet" '404': description: Pet not found interface DefaultApi { @GET("/pet/{petId}") fun getPetById( @retrofit2.http.Path("petId") petId: Long ) }
  113. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters: - name: petId in: path description: ID of pet to return required: true type: integer format: int64 responses: '200': description: successful operation schema: $ref: "#/definitions/Pet" '404': description: Pet not found interface DefaultApi { @GET("/pet/{petId}") fun getPetById( @retrofit2.http.Path("petId") petId: Long ): Single<Pet> }
  114. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters: - name: petId in: path description: ID of pet to return required: true type: integer format: int64 responses: '200': description: successful operation schema: $ref: "#/definitions/Pet" '404': description: Pet not found interface DefaultApi { @Headers( "X-Operation-ID: getPetById" ) @GET("/pet/{petId}") fun getPetById( @retrofit2.http.Path("petId") petId: Long ): Single<Pet> }
  115. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters: - name: petId in: path description: ID of pet to return required: true type: integer format: int64 responses: '200': description: successful operation schema: $ref: "#/definitions/Pet" '404': description: Pet not found interface DefaultApi { /** * Find pet by ID * Returns a single pet * @param petId ID of pet to return (required) */ @Headers( "X-Operation-ID: getPetById" ) @GET("/pet/{petId}") fun getPetById( @retrofit2.http.Path("petId") petId: Long ): Single<Pet> }
  116. paths: /pet/{petId}: get: summary: Find pet by ID description: Returns

    a single pet operationId: getPetById produces: - application/json parameters: - name: petId in: path description: ID of pet to return required: true type: integer format: int64 responses: '200': description: successful operation schema: $ref: "#/definitions/Pet" '404': description: Pet not found package com.yelp.codegen.generatecodesamples.apis import com.yelp.codegen.generatecodesamples.models.Pet import io.reactivex.Single import retrofit2.http.GET import retrofit2.http.Headers interface DefaultApi { /** * Find pet by ID * Returns a single pet * @param petId ID of pet to return (required) */ @Headers( "X-Operation-ID: getPetById" ) @GET("/pet/{petId}") fun getPetById( @retrofit2.http.Path("petId") petId: Long ): Single<Pet> }
  117. Build an app module with specs locally Build a pure-Kotlin

    module with a specs locally Build a library project that contains your models/apis Integrate your library with your CI system SWAGGER GRADLE CODEGEN Yelp/swagger-gradle-codegen Use cases
  118. None
  119. buildscript { repositories { gradlePluginPortal() } dependencies { classpath "com.yelp.codegen:plugin:1.0.0"

    } }
  120. buildscript { repositories { gradlePluginPortal() } dependencies { classpath "com.yelp.codegen:plugin:1.0.0"

    } } generateSwagger { }
  121. buildscript { repositories { gradlePluginPortal() } dependencies { classpath "com.yelp.codegen:plugin:1.0.0"

    } } generateSwagger { inputFile = file("../sample_specs.json") }
  122. buildscript { repositories { gradlePluginPortal() } dependencies { classpath "com.yelp.codegen:plugin:1.0.0"

    } } generateSwagger { inputFile = file("../sample_specs.json") outputDir = file("./src/main/java/") }
  123. buildscript { repositories { gradlePluginPortal() } dependencies { classpath "com.yelp.codegen:plugin:1.0.0"

    } } generateSwagger { platform = "kotlin" packageName = "com.yelp.codegen.samples" specName = "petstore" specVersion = "1.0.0" inputFile = file("../sample_specs.json") outputDir = file("./src/main/java/") }
  124. buildscript { repositories { gradlePluginPortal() } dependencies { classpath "com.yelp.codegen:plugin:1.0.0"

    } } generateSwagger { platform = "kotlin" packageName = "com.yelp.codegen.samples" specName = "petstore" specVersion = "1.0.0" inputFile = file("../sample_specs.json") outputDir = file("./src/main/java/") }
  125. buildscript { repositories { gradlePluginPortal() } dependencies { classpath "com.yelp.codegen:plugin:1.0.0"

    } } generateSwagger { platform = "kotlin" packageName = "com.yelp.codegen.samples" specName = "petstore" specVersion = "1.0.0" inputFile = file("../sample_specs.json") outputDir = file("./src/main/java/") }
  126. buildscript { repositories { gradlePluginPortal() } dependencies { classpath "com.yelp.codegen:plugin:1.0.0"

    } } generateSwagger { platform = "kotlin" packageName = "com.yelp.codegen.samples" specName = "petstore" specVersion = "1.0.0" inputFile = file("../sample_specs.json") outputDir = file("./src/main/java/") } preBuild.dependsOn(tasks.getByName(“generateSwagger"))
  127. None
  128. None
  129. None
  130. Code Generation @ Yelp

  131. None
  132. None
  133. None
  134. Mobile API Service ~400 endpoints BizApp Service ~100 endpoints

  135. implementation "com.yelp.android.apis:mobileapi:13.20190320212515.0" implementation "com.yelp.android.apis:bizapp:13.20190320212515.0"

  136. implementation "com.yelp.android.apis:mobileapi:13.20190320212515.0" implementation "com.yelp.android.apis:bizapp:13.20190320212515.0"

  137. e pet of pet to return (required) ion-ID: getPetById") ")

    trofit2.http.Path("petId") petId: Long): Single<Pet> eup.moshi.Json "name") var name: String, "photoUrls") var photoUrls: List<String>, "category") var category: Category? = null, "id") var id: Long? = null, "status") var status: Pet.StatusEnum? = null tatusEnum(val value: String){ me = "available") AVAILABLE("available"), me = "sold") SOLD("sold")
  138. Challenges & Future

  139. Breaking changes Defining names Accessing the Raw Response SWAGGER GRADLE

    CODEGEN Yelp/swagger-gradle-codegen Challenges interface DefaultApi { /** * Find the owner of a pet. !*/ @GET("/pet/owner") fun getPetById( @retrofit2.http.Path("name") name: String @retrofit2.http.Path("surname") surname: String ): Single<Owner> } interface DefaultApi { /** * Find the owner of a pet. !*/ @GET("/pet/owner") fun getPetById( @retrofit2.http.Path("surname") surname: String @retrofit2.http.Path("name") name: String ): Single<Owner> } data class IdToPredictedBizInfoForPhotoUploadSuggestionMapToBusinessReviewMap( !!... ) interface DefaultApi { /** * Find the owner of a pet. !*/ @GET("/pet/owner") fun getPetById( @retrofit2.http.Path("surname") surname: String @retrofit2.http.Path("name") name: String ): Single<Owner> } interface DefaultApi { /** * Find the owner of a pet. !*/ @GET("/pet/owner") fun getPetById( @retrofit2.http.Path("surname") surname: String @retrofit2.http.Path("name") name: String ): Single<Result<Owner!>> }
  140. Support Inheritance Coroutines iOS Template Getting a Corgi SWAGGER GRADLE

    CODEGEN Yelp/swagger-gradle-codegen Future
  141. POST-/thank/you

  142. We are hiring! www.yelp.com/careers

  143. Questions?