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

Simple HTTP with Retrofit 2 (Droidcon NYC 2015)

Simple HTTP with Retrofit 2 (Droidcon NYC 2015)

Retrofit has been simplifying HTTP calls for years and this new version is no different. In addition to fixing some long-standing annoyances, there are a handful of new features which make it more powerful than ever.

This talk will focus on how the new APIs in Retrofit aid in making HTTP calls as simple as possible for your app. The integration with OkHttp and Okio APIs will be covered to ensure a full understanding of the HTTP stack. Common use-cases and design patterns through more advanced functionality will end the talk.

No prior Retrofit, OkHttp, or Okio exposure needed. The content may quickly cover or skip some introductory aspects in order to allow focus on more actionable and useful content.

Video: https://youtu.be/KIAoQbAu3eA

Jake Wharton

August 27, 2015
Tweet

More Decks by Jake Wharton

Other Decks in Programming

Transcript

  1. Retrofit 2 will be out by the end of this

    year " " — Jake Wharton
  2. Retrofit 2 will be out by the end of this

    year " " Droidcon NYC 2014 — Jake Wharton
  3. Retrofit 2 will be out by the end of this

    year " " Droidcon NYC 2015 — Jake Wharton
  4. Retrofit 1 • Made open source on October 13th, 2010

    • Originally a Bob Lee joint • Took over / stole stewardship mid-2012
  5. Retrofit 1 • Made open source on October 13th, 2010

    • Originally a Bob Lee joint • Took over / stole stewardship mid-2012 • Released 1.0 on May 13th, 2013
  6. Retrofit 1 • Made open source on October 13th, 2010

    • Originally a Bob Lee joint • Took over / stole stewardship mid-2012 • Released 1.0 on May 13th, 2013 • 18 releases post-1.0 with tons of features / fixes
  7. The Good • Interface service declarations • Method and parameter

    annotations customize request • Pluggable HTTP client and serialization
  8. Pluggable client and serialization interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 List<Contributor> repoContributors(


    @Path("owner") String owner,
 @Path("repo") String repo);
 } builder.setConverter(new GsonConverter()); builder.setConverter(new JacksonConverter());
  9. Pluggable client and serialization interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 ContributorResponse repoContributors(


    @Path("owner") String owner,
 @Path("repo") String repo);
 } builder.setConverter(new ProtoConverter()); builder.setConverter(new WireConverter());
  10. Pluggable client and serialization interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 ContributorResponse repoContributors(


    @Path("owner") String owner,
 @Path("repo") String repo);
 } builder.setConverter(new ProtoConverter()); builder.setConverter(new WireConverter()); builder.setConverter(new SimpleXMLConverter());
  11. Pluggable client and serialization interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 ContributorResponse repoContributors(


    @Path("owner") String owner,
 @Path("repo") String repo);
 } builder.setConverter(new ProtoConverter()); builder.setConverter(new WireConverter()); builder.setConverter(new SimpleXMLConverter()); builder.setConverter(new CustomConverter());
  12. The Good • Interface service declarations • Method and parameter

    annotations customize request • Pluggable HTTP client and serialization • Synchronous, asynchronous, and RxJava execution
  13. Sync, async, and RxJava interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 List<Contributor> repoContributors(


    @Path("owner") String owner,
 @Path("repo") String repo);
 } List<Contributor> contributors = gitHubService.repoContributors("square", "retrofit");
  14. Sync, async, and RxJava interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 void repoContributors(


    @Path("owner") String owner,
 @Path("repo") String repo,
 Callback<List<Contributor>> cb);
 } service.repoContributors("square", "retrofit", new Callback<List<Contributor>>() {
 @Override void success(List<Contributor> contributors, Response response) {
 // ...
 }
 
 @Override void failure(RetrofitError error) {
 // ...
 }
 });
  15. Sync, async, and RxJava interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Observable<List<Contributor>> repoContributors(


    @Path("owner") String owner,
 @Path("repo") String repo);
 } gitHubService.repoContributors("square", "retrofit")
 .subscribe(new Action1<List<Contributor>>() {
 @Override public void call(List<Contributor> contributors) {
 // ...
 }
 });
  16. The Good • Interface service declarations • Method and parameter

    annotations customize request • Pluggable HTTP client and serialization • Synchronous, asynchronous, and RxJava execution
  17. No access to body and response interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")


    List<Contributor> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);
 }X
  18. No access to body and response interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")


    List<Contributor> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);
 @GET("/repos/{owner}/{repo}/contributors")
 Response repoContributors2(
 @Path("owner") String owner,
 @Path("repo") String repo);
 }X
  19. The Not-So-Good • Request/Response (and friends) model classes • No

    access to serialized body and response data • Rigid execution mechanisms
  20. Rigid execution mechanisms interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 List<Contributor> repoContributors(
 @Path("owner")

    String owner,
 @Path("repo") String repo); @GET("/repos/{owner}/{repo}/contributors")
 void repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo,
 Callback<List<Contributor>> cb);
 }
  21. The Not-So-Good • Request/Response (and friends) model classes • No

    access to serialized body and response data • Rigid execution mechanisms • Inefficient converter usage
  22. Inefficient converter usage interface Converter {
 Object fromBody(TypedInput body, Type

    type);
 TypedOutput toBody(Object object);
 } Type TypeAdapter TypedInput/Output JsonAdapter ObjectReader/Writer Parser ProtoAdapter
  23. Inefficient converter usage interface Converter {
 Object fromBody(TypedInput body, Type

    type);
 TypedOutput toBody(Object object);
 } Type TypeAdapter TypedInput/Output JsonAdapter ObjectReader/Writer Parser ProtoAdapter
  24. The Not-So-Good • Request/Response (and friends) model classes • No

    access to serialized body and response data • Rigid execution mechanisms • Inefficient converter usage • Simple custom parameter types support
  25. Simple custom parameter types interface GitHubService {
 @GET("/search/repositories")
 RepositoriesResponse searchRepos(


    @Query("q") String query,
 @Query("since") Date since);
 }X /search/repositories?q=retrofit&since=2015-08-27
  26. Simple custom parameter types interface GitHubService {
 @GET("/search/repositories")
 RepositoriesResponse searchRepos(


    @Query("q") String query,
 @Query("since") Date since);
 }X /search/repositories?q=retrofit&since=2015-08-27 /search/repositories?q=retrofit&since=20150827
  27. The Not-So-Good • Request/Response (and friends) model classes • No

    access to serialized body and response data • Rigid execution mechanisms • Inefficient converter usage • Simple custom parameter types support
  28. Call • Models a single request/response pair • Separates request

    creation from response handling • Each instance can only be used once...
  29. Call • Models a single request/response pair • Separates request

    creation from response handling • Each instance can only be used once... • ...instances can be cloned
  30. Call • Models a single request/response pair • Separates request

    creation from response handling • Each instance can only be used once... • ...instances can be cloned • Supports both synchronous and asynchronous execution.
  31. Call • Models a single request/response pair • Separates request

    creation from response handling • Each instance can only be used once... • ...instances can be cloned • Supports both synchronous and asynchronous execution. • Can be (actually) canceled
  32. Call interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,


    @Path("repo") String repo);
 } Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit");
  33. Call Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit"); 
 response = call.execute();

    // This will throw IllegalStateException:
 response = call.execute(); Call<List<Contributor>> call2 = call.clone();
 // This will not throw:
 response = call2.execute();
  34. Call Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit"); 
 call.enqueue(new Callback<List<Contributor>>() {


    @Override void onResponse(/* ... */) {
 // ...
 }
 
 @Override void onFailure(Throwable t) {
 // ...
 }
 });
  35. Response Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit"); call.enqueue(new Callback<List<Contributor>>() {
 @Override

    void onResponse(/* ... */) {
 // ...
 }X
 
 @Override void failure(Throwable t) {
 // ...
 }X
 });
  36. Response Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit"); call.enqueue(new Callback<List<Contributor>>() {
 @Override

    void onResponse(Response<List<Contributor>> response) {
 // ...
 }X
 
 @Override void failure(Throwable t) {
 // ...
 }X
 });
  37. Response Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit"); call.enqueue(new Callback<List<Contributor>>() {
 @Override

    void onResponse(Response<List<Contributor>> response) {
 // ...
 }
 
 @Override void failure(Throwable t) {
 // ...
 }
 });
  38. Response class Response<T> {
 int code();
 String message(); Headers headers();


    
 boolean isSuccess(); T body();
 ResponseBody errorBody();
 }X
  39. Response class Response<T> {
 int code();
 String message(); Headers headers();


    
 boolean isSuccess(); T body();
 ResponseBody errorBody(); com.squareup.okhttp.Response raw();
 }X
  40. Dynamic Query Param interface SomeService {
 @GET("/some/endpoint")
 Call<SomeResponse> someEndpoint(
 @Query("dynamic")

    String dynamic);
 } someService.someEndpoint("query"); // GET /some/endpoint?dynamic=query HTTP/1.1
  41. Dynamic Query Param Map interface SomeService {
 @GET("/some/endpoint")
 Call<SomeResponse> someEndpoint(


    @QueryMap Map<String, String> dynamic);
 } someService.someEndpoint( Collections.singletonMap("dynamic", "query")); // GET /some/endpoint?dynamic=query HTTP/1.1
  42. Omit Dynamic Query Param interface SomeService {
 @GET("/some/endpoint")
 Call<SomeResponse> someEndpoint(


    @Query("dynamic") String dynamic);
 } someService.someEndpoint(null); // GET /some/endpoint HTTP/1.1
  43. Fixed+Dynamic Query Params interface SomeService {
 @GET("/some/endpoint?fixed=query")
 Call<SomeResponse> someEndpoint(
 @Query("dynamic")

    String dynamic);
 } someService.someEndpoint("query"); // GET /some/endpoint?fixed=query&dynamic=query HTTP/1.1
  44. Fixed Header interface SomeService {
 @GET("/some/endpoint") @Headers("Accept-Encoding: application/json")
 Call<SomeResponse> someEndpoint();


    } someService.someEndpoint(); // GET /some/endpoint HTTP/1.1 // Accept-Encoding: application/json
  45. Dynamic Header interface SomeService {
 @GET("/some/endpoint")
 Call<SomeResponse> someEndpoint( @Header("Location") String

    location);
 } someService.someEndpoint("Droidcon NYC 2015"); // GET /some/endpoint HTTP/1.1 // Location: Droidcon NYC 2015
  46. Omit Dynamic Header interface SomeService {
 @GET("/some/endpoint")
 Call<SomeResponse> someEndpoint( @Header("Location")

    String location);
 } someService.someEndpoint(null); // GET /some/endpoint HTTP/1.1
  47. Fixed+Dynamic Header interface SomeService {
 @GET("/some/endpoint") @Headers("Accept-Encoding: application/json")
 Call<SomeResponse> someEndpoint(

    @Header("Location") String location);
 } someService.someEndpoint("Droidcon NYC 2015"); // GET /some/endpoint HTTP/1.1 // Accept-Encoding: application/json // Location: Droidcon NYC 2015
  48. Post Without Body interface SomeService {
 @POST("/some/endpoint")
 Call<SomeResponse> someEndpoint();
 }

    someService.someEndpoint(); // POST /some/endpoint?fixed=query HTTP/1.1 // Content-Length: 0
  49. Post With Body interface SomeService {
 @POST("/some/endpoint")
 Call<SomeResponse> someEndpoint( @Body

    SomeRequest body);
 } someService.someEndpoint(); // POST /some/endpoint HTTP/1.1 // Content-Length: 3 // Content-Type: greeting // // Hi!
  50. Form Encoded Fields interface SomeService {
 @FormUrlEncoded @POST("/some/endpoint")
 Call<SomeResponse> someEndpoint(

    @Field("name1") String name1, @Field("name2") String name2);
 } someService.someEndpoint("value1", "value2"); // POST /some/endpoint HTTP/1.1 // Content-Length: 25 // Content-Type: application/x-www-form-urlencoded // // name1=value1&name2=value2
  51. Omit Form Encoded Field interface SomeService {
 @FormUrlEncoded @POST("/some/endpoint")
 Call<SomeResponse>

    someEndpoint( @Field("name1") String name1, @Field("name2") String name2);
 } someService.someEndpoint("value1", null); // POST /some/endpoint HTTP/1.1 // Content-Length: 12 // Content-Type: application/x-www-form-urlencoded // // name1=value1
  52. Form Encoded Field Map interface SomeService {
 @FormUrlEncoded @POST("/some/endpoint")
 Call<SomeResponse>

    someEndpoint( @FieldMap Map<String, String> names);
 } someService.someEndpoint( ImmutableMap.of("name1", "value1", "name2", "value2")); // POST /some/endpoint HTTP/1.1 // Content-Length: 25 // Content-Type: application/x-www-form-urlencoded // // name1=value1&name2=value2
  53. Multipart Parts interface SomeService {
 @Multipart @POST("/some/endpoint")
 Call<SomeResponse> someEndpoint( @Part("name1")

    String name1, @Part("name2") String name2);
 } someService.someEndpoint("value1", "value2"); // POST /some/endpoint HTTP/1.1 // Content-Length: 102 // Content-Type: application/form-data // // ...
  54. Omit Multipart Part interface SomeService {
 @Multipart @POST("/some/endpoint")
 Call<SomeResponse> someEndpoint(

    @Part("name1") String name1, @Part("name2") String name2);
 } someService.someEndpoint("value1", null); // POST /some/endpoint HTTP/1.1 // Content-Length: 56 // Content-Type: application/form-data // // ...
  55. Multipart Part Map interface SomeService {
 @Multipart @POST("/some/endpoint")
 Call<SomeResponse> someEndpoint(

    @PartMap Map<String, String> names);
 } someService.someEndpoint( ImmutableMap.of("name1", "value1", "name2", "value2")); // POST /some/endpoint HTTP/1.1 // Content-Length: 102 // Content-Type: application/form-data // // ...
  56. Dynamic URL interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String

    owner,
 @Path("repo") String repo);
 } Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit"); Response<List<Contributor>> response = call.execute();
  57. Dynamic URL interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String

    owner,
 @Path("repo") String repo);
 } Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit"); Response<List<Contributor>> response = call.execute(); // HTTP/1.1 200 OK // Link: <https://api.github.com/repositories/892275/contributors? page=2>; rel="next", <https://api.github.com/repositories/892275/ contributors?page=3>; rel="last" // ...
  58. Dynamic URL Response<List<Contributor>> response = call.execute(); // HTTP/1.1 200 OK

    // Link: <https://api.github.com/repositories/892275/contributors? page=2>; rel="next", <https://api.github.com/repositories/892275/ contributors?page=3>; rel="last" // ...
  59. Dynamic URL Response<List<Contributor>> response = call.execute(); // HTTP/1.1 200 OK

    // Link: <https://api.github.com/repositories/892275/contributors? page=2>; rel="next", <https://api.github.com/repositories/892275/ contributors?page=3>; rel="last" // ... String links = response.headers().get("Link");
  60. Dynamic URL Response<List<Contributor>> response = call.execute(); // HTTP/1.1 200 OK

    // Link: <https://api.github.com/repositories/892275/contributors? page=2>; rel="next", <https://api.github.com/repositories/892275/ contributors?page=3>; rel="last" // ... String links = response.headers().get("Link"); String nextLink = nextFromGitHubLinks(links);
  61. Dynamic URL Response<List<Contributor>> response = call.execute(); // HTTP/1.1 200 OK

    // Link: <https://api.github.com/repositories/892275/contributors? page=2>; rel="next", <https://api.github.com/repositories/892275/ contributors?page=3>; rel="last" // ... String links = response.headers().get("Link"); String nextLink = nextFromGitHubLinks(links); // https://api.github.com/repositories/892275/contributors?page=2
  62. Dynamic URL interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String

    owner,
 @Path("repo") String repo); 
 @GET
 Call<List<Contributor>> repoContributorsPaginate(
 @Url String url);
 }X
  63. Retrofit 2 • Call encapsulates single request/response interaction • Parameterized

    Response object • Dynamic URL parameter • Multiple, efficient converters
  64. Retrofit 2 • Call encapsulates single request/response interaction • Parameterized

    Response object • Dynamic URL parameter • Multiple, efficient converters • Multiple, pluggable execution mechanisms
  65. Execution Mechanisms interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String

    owner,
 @Path("repo") String repo); 
 @GET("/repos/{owner}/{repo}/contributors")
 Observable<List<Contributor>> repoContributors2(
 @Path("owner") String owner,
 @Path("repo") String repo); 
 @GET("/repos/{owner}/{repo}/contributors")
 Future<List<Contributor>> repoContributors3(
 @Path("owner") String owner,
 @Path("repo") String repo);
 }X
  66. Execution Mechanisms interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(..); 
 @GET("/repos/{owner}/{repo}/contributors")


    Observable<List<Contributor>> repoContributors2(..); 
 @GET("/repos/{owner}/{repo}/contributors")
 Future<List<Contributor>> repoContributors3(..);
 }X Call
  67. Execution Mechanisms interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(..); 
 @GET("/repos/{owner}/{repo}/contributors")


    Observable<List<Contributor>> repoContributors2(..); 
 @GET("/repos/{owner}/{repo}/contributors")
 Future<List<Contributor>> repoContributors3(..);
 }X Call
  68. Execution Mechanisms interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(..); 
 @GET("/repos/{owner}/{repo}/contributors")


    Observable<List<Contributor>> repoContributors2(..); 
 @GET("/repos/{owner}/{repo}/contributors")
 Future<List<Contributor>> repoContributors3(..);
 }X Call RxJava? No!
  69. Execution Mechanisms interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(..); 
 @GET("/repos/{owner}/{repo}/contributors")


    Observable<List<Contributor>> repoContributors2(..); 
 @GET("/repos/{owner}/{repo}/contributors")
 Future<List<Contributor>> repoContributors3(..);
 }X Call RxJava? No! Call? Yes!
  70. Execution Mechanisms interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(..); 
 @GET("/repos/{owner}/{repo}/contributors")


    Observable<List<Contributor>> repoContributors2(..); 
 @GET("/repos/{owner}/{repo}/contributors")
 Future<List<Contributor>> repoContributors3(..);
 }X Observable
  71. Execution Mechanisms interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(..); 
 @GET("/repos/{owner}/{repo}/contributors")


    Observable<List<Contributor>> repoContributors2(..); 
 @GET("/repos/{owner}/{repo}/contributors")
 Future<List<Contributor>> repoContributors3(..);
 }X Observable RxJava? Yes!
  72. Execution Mechanisms interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(..); 
 @GET("/repos/{owner}/{repo}/contributors")


    Observable<List<Contributor>> repoContributors2(..); 
 @GET("/repos/{owner}/{repo}/contributors")
 Future<List<Contributor>> repoContributors3(..);
 }X Future
  73. Execution Mechanisms interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(..); 
 @GET("/repos/{owner}/{repo}/contributors")


    Observable<List<Contributor>> repoContributors2(..); 
 @GET("/repos/{owner}/{repo}/contributors")
 Future<List<Contributor>> repoContributors3(..);
 }X Future RxJava? No!
  74. Execution Mechanisms interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(..); 
 @GET("/repos/{owner}/{repo}/contributors")


    Observable<List<Contributor>> repoContributors2(..); 
 @GET("/repos/{owner}/{repo}/contributors")
 Future<List<Contributor>> repoContributors3(..);
 }X Future RxJava? No! Call? No!
  75. Execution Mechanisms interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(..); 
 @GET("/repos/{owner}/{repo}/contributors")


    Observable<List<Contributor>> repoContributors2(..); 
 @GET("/repos/{owner}/{repo}/contributors")
 Future<List<Contributor>> repoContributors3(..);
 }X Future RxJava? No! Call? No! Throw!
  76. Retrofit 2 • Call encapsulates single request/response interaction • Parameterized

    Response object • Dynamic URL parameter • Multiple, efficient converters • Multiple, pluggable execution mechanisms
  77. Powered by OkHttp • In 2012 we needed client abstractions.

    • In 2012 we needed request/response abstractions.
  78. Powered by OkHttp • In 2012 we needed client abstractions.

    • In 2012 we needed request/response abstractions. • In 2012 we needed header abstractions.
  79. Powered by OkHttp • In 2012 we needed client abstractions.

    • In 2012 we needed request/response abstractions. • In 2012 we needed header abstractions. • It's 2015. OkHttp is small, lean, focused, and full-featured.
  80. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody <T> MyService RequestBody

    ResponseBody Socket execute() myEndpoint() Moshi BufferedSink BufferedSource <T>
  81. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody <T> MyService RequestBody

    ResponseBody Socket execute() myEndpoint() Moshi BufferedSink BufferedSource <T>
  82. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody <T> MyService RequestBody

    ResponseBody Socket execute() myEndpoint() Moshi BufferedSink BufferedSource <T>
  83. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody <T> MyService RequestBody

    ResponseBody Socket execute() myEndpoint() Moshi BufferedSink BufferedSource <T>
  84. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody <T> MyService RequestBody

    ResponseBody Socket execute() myEndpoint() Moshi BufferedSink BufferedSource <T>
  85. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody <T> MyService RequestBody

    ResponseBody Socket execute() myEndpoint() Moshi BufferedSink BufferedSource <T>
  86. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody <T> MyService RequestBody

    ResponseBody Socket execute() myEndpoint() Moshi BufferedSink BufferedSource <T>
  87. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody <T> MyService RequestBody

    ResponseBody Socket execute() myEndpoint() Moshi BufferedSink BufferedSource <T>
  88. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody <T> MyService RequestBody

    ResponseBody Socket execute() myEndpoint() Moshi BufferedSink BufferedSource <T>
  89. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody <T> MyService RequestBody

    ResponseBody Socket execute() myEndpoint() Moshi BufferedSink BufferedSource <T>
  90. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody <T> MyService RequestBody

    ResponseBody Socket execute() myEndpoint() Moshi BufferedSink BufferedSource <T>
  91. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .build(); interface GitHubService

    {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);
 }
  92. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .build(); interface GitHubService

    {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);
 } GitHubService gitHubService = retrofit.create(GitHubService.class);
  93. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .build(); interface GitHubService

    {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);
 } // https://api.github.com/repos/square/retrofit/contributors
  94. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .build(); interface GitHubService

    {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);
 } // https://api.github.com/repos/square/retrofit/contributors HttpUrl
  95. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .build(); interface GitHubService

    {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);
 } // https://api.github.com/repos/square/retrofit/contributors HttpUrl .resolve()
  96. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .build(); interface GitHubService

    {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);
 }
  97. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/v3/") .build(); interface GitHubService

    {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);
 }
  98. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/v3/") .build(); interface GitHubService

    {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);
 }
  99. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/v3/") .build(); interface GitHubService

    {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);
 } // https://api.github.com/repos/square/retrofit/contributors
  100. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/v3/") .build(); interface GitHubService

    {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);
 } // https://api.github.com/repos/square/retrofit/contributors HttpUrl .resolve()
  101. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/v3/") .build(); interface GitHubService

    {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);
 }X
  102. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/v3/") .build(); interface GitHubService

    {
 @GET("repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);
 }X
  103. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/v3/") .build(); interface GitHubService

    {
 @GET("repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);
 }
  104. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/v3/") .build(); interface GitHubService

    {
 @GET("repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);
 } // https://api.github.com/v3/repos/square/retrofit/contributors
  105. Setup OkHttpClient client = new OkHttpClient(); Retrofit retrofit = new

    Retrofit.Builder() .baseUrl("https://api.github.com") .client(client) .build();
  106. Setup OkHttpClient client = new OkHttpClient(); client.interceptors().add(..); Retrofit retrofit =

    new Retrofit.Builder() .baseUrl("https://api.github.com") .client(client) .build();
  107. JSON Converter.Factory class ProtoConverterFactory { Converter<?> create(Type type); }X SomeJsonResponse

    null No! Converter<?> Yes! class GsonConverterFactory { Converter<?> create(Type type); }X
  108. Converter.Factory interface Converter<T> { interface Factory { Converter<?> create(Type type);

    }X T fromBody(ResponseBody body); RequestBody toBody(T value); }X
  109. CallAdapter.Factory Call class RxJavaCallAdapterFactory { CallAdapter<?> create(Type type); }X null

    No! JSON CallAdapter<?> Yes! class CallAdapterFactory { CallAdapter<?> create(Type type); }X
  110. Under Construction • Parameter handlers • Logging? • Finalizing mock

    module • Documentation • WebSockets! (in v2.1)