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

E68309f117985270285ade8082f4877d?s=128

Jake Wharton

August 27, 2015
Tweet

Transcript

  1. Retrofit Two Jake Wharton

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

    year " " — Naïve Man
  3. Retrofit 2 will be out by the end of this

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

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

    year " " Droidcon NYC 2015 — Jake Wharton
  6. Retrofit 1

  7. Retrofit 1 • Made open source on October 13th, 2010

  8. Retrofit 1 • Made open source on October 13th, 2010

    • Originally a Bob Lee joint
  9. Retrofit 1 • Made open source on October 13th, 2010

    • Originally a Bob Lee joint • Took over / stole stewardship mid-2012
  10. 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
  11. 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
  12. The Good

  13. The Good • Interface service declarations • Method and parameter

    annotations customize request
  14. Interface and annotations interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 List<Contributor> repoContributors(
 @Path("owner")

    String owner,
 @Path("repo") String repo);
 }
  15. The Good • Interface service declarations • Method and parameter

    annotations customize request • Pluggable HTTP client and serialization
  16. Pluggable client and serialization builder.setClient(new UrlConnectionClient()); builder.setClient(new ApacheClient()); builder.setClient(new OkClient());

  17. Pluggable client and serialization builder.setClient(new UrlConnectionClient()); builder.setClient(new ApacheClient()); builder.setClient(new OkClient());

    builder.setClient(new CustomClient());
  18. Pluggable client and serialization interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 List<Contributor> repoContributors(


    @Path("owner") String owner,
 @Path("repo") String repo);
 }
  19. 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());
  20. Pluggable client and serialization interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 ContributorResponse repoContributors(


    @Path("owner") String owner,
 @Path("repo") String repo);
 }
  21. 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());
  22. 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());
  23. 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());
  24. The Good • Interface service declarations • Method and parameter

    annotations customize request • Pluggable HTTP client and serialization • Synchronous, asynchronous, and RxJava execution
  25. 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");
  26. 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) {
 // ...
 }
 });
  27. 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) {
 // ...
 }
 });
  28. The Good • Interface service declarations • Method and parameter

    annotations customize request • Pluggable HTTP client and serialization • Synchronous, asynchronous, and RxJava execution
  29. The Not-So-Good

  30. The Not-So-Good • Request/Response (and friends) model classes

  31. Request/Response model classes

  32. The Not-So-Good • Request/Response (and friends) model classes • No

    access to serialized body and response data
  33. 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
  34. 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
  35. The Not-So-Good • Request/Response (and friends) model classes • No

    access to serialized body and response data • Rigid execution mechanisms
  36. 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);
 }
  37. Rigid execution mechanisms interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Observable<List<Contributor>> repoContributors(
 @Path("owner")

    String owner,
 @Path("repo") String repo);
 }
  38. Rigid execution mechanisms interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 ListenableFuture<List<Contributor>> repoContributors(
 @Path("owner")

    String owner,
 @Path("repo") String repo);
 }
  39. Rigid execution mechanisms interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 CompletableFuture<List<Contributor>> repoContributors(
 @Path("owner")

    String owner,
 @Path("repo") String repo);
 }
  40. The Not-So-Good • Request/Response (and friends) model classes • No

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

    type);
 TypedOutput toBody(Object object);
 }
  42. Inefficient converter usage interface Converter {
 Object fromBody(TypedInput body, Type

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

    type);
 TypedOutput toBody(Object object);
 } Type TypeAdapter TypedInput/Output JsonAdapter ObjectReader/Writer Parser ProtoAdapter
  44. 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
  45. Simple custom parameter types interface GitHubService {
 @GET("/search/repositories")
 RepositoriesResponse searchRepos(


    @Query("q") String query,
 @Query("since") Date since);
 }X
  46. 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
  47. 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
  48. 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
  49. Retrofit 2

  50. Retrofit 2 • Call encapsulates single request/response interaction

  51. Call • Models a single request/response pair

  52. Call • Models a single request/response pair • Separates request

    creation from response handling
  53. Call • Models a single request/response pair • Separates request

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

    creation from response handling • Each instance can only be used once... • ...instances can be cloned
  55. 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.
  56. 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
  57. Call interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 List<Contributor> repoContributors(
 @Path("owner") String owner,


    @Path("repo") String repo); }X
  58. Call interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,


    @Path("repo") String repo);
 }X
  59. Call interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,


    @Path("repo") String repo);
 }
  60. 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");
  61. Call Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit");

  62. Call Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit"); 
 response = call.execute();

  63. Call Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit"); 
 response = call.execute();

    // This will throw IllegalStateException:
 response = call.execute();
  64. 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();
  65. Call Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit");

  66. Call Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit"); 
 call.enqueue(new Callback<List<Contributor>>() {


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

    call.execute();
  68. Call Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit"); call.enqueue( ); // or...

    call.execute(); // later... call.cancel();
  69. Retrofit 2 • Call encapsulates single request/response interaction • Parameterized

    Response object
  70. Response Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit"); response = call.execute();

  71. Response Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit"); Response<List<Contributor>> response = call.execute();

  72. Response Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit"); Response<List<Contributor>> response = call.execute();

  73. 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
 });
  74. 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
 });
  75. 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) {
 // ...
 }
 });
  76. Response class Response<T> {
 }X

  77. Response class Response<T> {
 int code();
 String message(); Headers headers();


    }X
  78. Response class Response<T> {
 int code();
 String message(); Headers headers();


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


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


    
 boolean isSuccess(); T body();
 ResponseBody errorBody(); com.squareup.okhttp.Response raw();
 }X
  81. Retrofit 2 • Call encapsulates single request/response interaction • Parameterized

    Response object
  82. If it isn't broken...

  83. Fixed Query Param interface SomeService {
 @GET("/some/endpoint?fixed=query")
 Call<SomeResponse> someEndpoint();
 }

    someService.someEndpoint(); // GET /some/endpoint?fixed=query HTTP/1.1
  84. 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
  85. 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
  86. 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
  87. 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
  88. Path Replacement interface SomeService {
 @GET("/some/endpoint/{foo}")
 Call<SomeResponse> someEndpoint(
 @Path("thing") String

    thing);
 } someService.someEndpoint("bar"); // GET /some/endpoint/bar HTTP/1.1
  89. 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
  90. 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
  91. Omit Dynamic Header interface SomeService {
 @GET("/some/endpoint")
 Call<SomeResponse> someEndpoint( @Header("Location")

    String location);
 } someService.someEndpoint(null); // GET /some/endpoint HTTP/1.1
  92. 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
  93. Post Without Body interface SomeService {
 @POST("/some/endpoint")
 Call<SomeResponse> someEndpoint();
 }

    someService.someEndpoint(); // POST /some/endpoint?fixed=query HTTP/1.1 // Content-Length: 0
  94. 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!
  95. 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
  96. 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
  97. 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
  98. 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 // // ...
  99. 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 // // ...
  100. 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 // // ...
  101. If it isn't broken...

  102. Retrofit 2 • Call encapsulates single request/response interaction • Parameterized

    Response object • Dynamic URL parameter
  103. Dynamic URL interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String

    owner,
 @Path("repo") String repo);
 }
  104. 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();
  105. 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" // ...
  106. 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" // ...
  107. 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");
  108. 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);
  109. 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
  110. Dynamic URL interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String

    owner,
 @Path("repo") String repo);
 }X
  111. 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
  112. Dynamic URL String nextLink = nextFromGitHubLinks(links); // https://api.github.com/repositories/892275/contributors?page=2

  113. Dynamic URL String nextLink = nextFromGitHubLinks(links); // https://api.github.com/repositories/892275/contributors?page=2 Call<List<Contributor>> nextCall

    = gitHubService.repoContributorsPaginate(nextLink);
  114. Retrofit 2 • Call encapsulates single request/response interaction • Parameterized

    Response object • Dynamic URL parameter • Multiple, efficient converters
  115. Converters interface SomeProtoService {
 @GET("/some/proto/endpoint")
 Call<SomeProtoResponse> someProtoEndpoint(); }X interface SomeJsonService

    {
 @GET("/some/json/endpoint")
 Call<SomeJsonResponse> someJsonEndpoint();
 }X
  116. Converters interface SomeService {
 @GET("/some/proto/endpoint")
 Call<SomeProtoResponse> someProtoEndpoint(); 
 @GET("/some/json/endpoint")
 Call<SomeJsonResponse>

    someJsonEndpoint();
 }X 
 
 SomeProtoResponse
  117. Converters interface SomeService {
 @GET("/some/proto/endpoint")
 Call<SomeProtoResponse> someProtoEndpoint(); 
 @GET("/some/json/endpoint")
 Call<SomeJsonResponse>

    someJsonEndpoint();
 }X SomeProtoResponse
  118. Converters interface SomeService {
 @GET("/some/proto/endpoint")
 Call<SomeProtoResponse> someProtoEndpoint(); 
 @GET("/some/json/endpoint")
 Call<SomeJsonResponse>

    someJsonEndpoint();
 }X SomeProtoResponse Proto? Yes!
  119. Converters interface SomeService {
 @GET("/some/proto/endpoint")
 Call<SomeProtoResponse> someProtoEndpoint(); 
 @GET("/some/json/endpoint")
 Call<SomeJsonResponse>

    someJsonEndpoint();
 }X SomeJsonResponse
  120. Converters interface SomeService {
 @GET("/some/proto/endpoint")
 Call<SomeProtoResponse> someProtoEndpoint(); 
 @GET("/some/json/endpoint")
 Call<SomeJsonResponse>

    someJsonEndpoint();
 }X SomeJsonResponse Proto? No!
  121. Converters interface SomeService {
 @GET("/some/proto/endpoint")
 Call<SomeProtoResponse> someProtoEndpoint(); 
 @GET("/some/json/endpoint")
 Call<SomeJsonResponse>

    someJsonEndpoint();
 }X SomeJsonResponse Proto? No! JSON? Yes!
  122. Retrofit 2 • Call encapsulates single request/response interaction • Parameterized

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

    owner,
 @Path("repo") String repo);
 }X
  124. 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
  125. 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
  126. 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
  127. 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!
  128. 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!
  129. 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
  130. 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!
  131. 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
  132. 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!
  133. 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!
  134. 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!
  135. Retrofit 2 • Call encapsulates single request/response interaction • Parameterized

    Response object • Dynamic URL parameter • Multiple, efficient converters • Multiple, pluggable execution mechanisms
  136. Powered by OkHttp

  137. Powered by OkHttp • In 2012 we needed client abstractions.

  138. Powered by OkHttp • In 2012 we needed client abstractions.

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

    • In 2012 we needed request/response abstractions. • In 2012 we needed header abstractions.
  140. 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.
  141. Powered by OkHttp

  142. Powered by OkHttp & Okio bit.ly/ok-libs

  143. Retrofit

  144. Retrofit OkHttp

  145. Retrofit OkHttp Socket

  146. Retrofit OkHttp BufferedSource BufferedSink Socket

  147. Retrofit OkHttp BufferedSource BufferedSink RequestBody ResponseBody Socket

  148. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody Socket

  149. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody Socket Moshi

  150. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody Socket Moshi BufferedSink

    BufferedSource <T>
  151. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody <T> RequestBody ResponseBody

    Socket Moshi BufferedSink BufferedSource <T>
  152. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody <T> MyService RequestBody

    ResponseBody Socket Moshi BufferedSink BufferedSource <T>
  153. Retrofit OkHttp MoshiConverter BufferedSource BufferedSink RequestBody ResponseBody <T> MyService RequestBody

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

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

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

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

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

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

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

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

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

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

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

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

  166. 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);
 }
  167. 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);
  168. 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
  169. 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
  170. 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()
  171. 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);
 }
  172. 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);
 }
  173. 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);
 }
  174. 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
  175. 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()
  176. 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
  177. 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
  178. 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);
 }
  179. 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
  180. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .build();

  181. Setup OkHttpClient client = new OkHttpClient(); Retrofit retrofit = new

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

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

  184. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .addConverterFactory(GsonConverterFactory.create()) .build();

  185. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(ProtoConverterFactory.create()) .build();

  186. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .addConverterFactory(ProtoConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build();

  187. Setup Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .addConverterFactory(ProtoConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create())

    .build();
  188. Extensibility • Converter.Factory • CallAdapter.Factory

  189. Converter.Factory interface SomeService {
 @GET("/some/proto/endpoint")
 Call<SomeProtoResponse> someProtoEndpoint(); 
 @GET("/some/json/endpoint")
 Call<SomeJsonResponse>

    someJsonEndpoint();
 }X SomeJsonResponse Proto? No! JSON? Yes!
  190. Converter.Factory interface Converter<T> { interface Factory { Converter<?> create(Type type);

    } }X SomeJsonResponse Proto? No! JSON? Yes!
  191. Converter.Factory SomeJsonResponse Proto? No! JSON? Yes!

  192. Converter.Factory class ProtoConverterFactory { Converter<?> create(Type type); }X SomeJsonResponse null

    No! JSON? Yes!
  193. JSON Converter.Factory class ProtoConverterFactory { Converter<?> create(Type type); }X SomeJsonResponse

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

    }X }X
  195. Converter.Factory interface Converter<T> { interface Factory { Converter<?> create(Type type);

    }X T fromBody(ResponseBody body); RequestBody toBody(T value); }X
  196. Extensibility • Converter.Factory • CallAdapter.Factory

  197. CallAdapter.Factory interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(..); 
 @GET("/repos/{owner}/{repo}/contributors")
 Observable<List<Contributor>>

    repoContributors2(..);
 }X Call RxJava? No! Call? Yes!
  198. CallAdapter.Factory interface CallAdapter<T> { interface Factory { CallAdapter<?> create(Type type);

    }
 }X Call RxJava? No! Call? Yes!
  199. CallAdapter.Factory Call RxJava? No! Call? Yes!

  200. CallAdapter.Factory Call Call? Yes! class RxJavaCallAdapterFactory { CallAdapter<?> create(Type type);

    }X null No!
  201. CallAdapter.Factory Call class RxJavaCallAdapterFactory { CallAdapter<?> create(Type type); }X null

    No! JSON CallAdapter<?> Yes! class CallAdapterFactory { CallAdapter<?> create(Type type); }X
  202. CallAdapter.Factory interface CallAdapter<T> { interface Factory { CallAdapter<?> create(Type type);

    }X }X
  203. CallAdapter.Factory interface CallAdapter<T> { interface Factory { CallAdapter<?> create(Type type);

    }X Type responseType(); Object adapt(Call<T> value); }X
  204. Extensibility • Converter.Factory • CallAdapter.Factory

  205. Under Construction

  206. Under Construction • Parameter handlers

  207. Under Construction • Parameter handlers • Logging?

  208. Under Construction • Parameter handlers • Logging? • Finalizing mock

    module
  209. Under Construction • Parameter handlers • Logging? • Finalizing mock

    module • Documentation
  210. Under Construction • Parameter handlers • Logging? • Finalizing mock

    module • Documentation • WebSockets! (in v2.1)
  211. Release?

  212. Release? dependencies {
 compile 'com.squareup.retrofit:retrofit:2.0.0-beta1' compile 'com.squareup.retrofit:converter-gson:2.0.0-beta1' compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1' }

  213. jakewharton jakewharton twitter.com/ google.com/+ .com Retrofit Two jakewharton