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

Retrofit

 Retrofit

Adrien Couque

January 22, 2015
Tweet

More Decks by Adrien Couque

Other Decks in Technology

Transcript

  1. Retrofit 2015 • Old way RestClient.get(this,
 App.getWebServiceBaseURL() + "/associate/annual-salaries.json",
 new

    JacksonHttpResponseHandler<List<AnnualSalary>>(
 this,
 new TypeReference<List<AnnualSalary>>() {}
 ) {
 @Override
 public void onSuccess(int statusCode,
 Header[] headers,
 String rawJsonResponse,
 List<AnnualSalary> response) {
 // …
 }
 
 @Override
 public void onRequestFailure(int statusCode,
 Header[] headers,
 Throwable throwable,
 String rawJsonData,
 List<AnnualSalary> errorResponse) {
 // …
 }
 });
  2. Retrofit 2015 • Old way: URL RestClient.get(this,
 App.getWebServiceBaseURL() + "/associate/annual-salaries.json",


    new JacksonHttpResponseHandler<List<AnnualSalary>>(
 this,
 new TypeReference<List<AnnualSalary>>() {}
 ) {
 @Override
 public void onSuccess(int statusCode,
 Header[] headers,
 String rawJsonResponse,
 List<AnnualSalary> response) {
 // TODO
 }
 
 @Override
 public void onRequestFailure(int statusCode,
 Header[] headers,
 Throwable throwable,
 String rawJsonData,
 List<AnnualSalary> errorResponse) {
 // TODO
 }
 });
  3. Retrofit 2015 • Old way: return type RestClient.get(this,
 App.getWebServiceBaseURL() +

    "/associate/annual-salaries.json",
 new JacksonHttpResponseHandler<List<AnnualSalary>>(
 this,
 new TypeReference<List<AnnualSalary>>() {}
 ) {
 @Override
 public void onSuccess(int statusCode,
 Header[] headers,
 String rawJsonResponse,
 List<AnnualSalary> response) {
 // TODO
 }
 
 @Override
 public void onRequestFailure(int statusCode,
 Header[] headers,
 Throwable throwable,
 String rawJsonData,
 List<AnnualSalary> errorResponse) {
 // TODO
 }
 });
  4. Retrofit 2015 • Old way: success RestClient.get(this,
 App.getWebServiceBaseURL() + "/associate/annual-salaries.json",


    new JacksonHttpResponseHandler<List<AnnualSalary>>(
 this,
 new TypeReference<List<AnnualSalary>>() {}
 ) {
 @Override
 public void onSuccess(int statusCode,
 Header[] headers,
 String rawJsonResponse,
 List<AnnualSalary> response) {
 // TODO
 }
 
 @Override
 public void onRequestFailure(int statusCode,
 Header[] headers,
 Throwable throwable,
 String rawJsonData,
 List<AnnualSalary> errorResponse) {
 // TODO
 }
 });
  5. Retrofit 2015 • Old way: failure RestClient.get(this,
 App.getWebServiceBaseURL() + "/associate/annual-salaries.json",


    new JacksonHttpResponseHandler<List<AnnualSalary>>(
 this,
 new TypeReference<List<AnnualSalary>>() {}
 ) {
 @Override
 public void onSuccess(int statusCode,
 Header[] headers,
 String rawJsonResponse,
 List<AnnualSalary> response) {
 // TODO
 }
 
 @Override
 public void onRequestFailure(int statusCode,
 Header[] headers,
 Throwable throwable,
 String rawJsonData,
 List<AnnualSalary> errorResponse) {
 // TODO
 }
 });
  6. Retrofit 2015 • Building the API Manager public class ApiManager

    { public interface ApiManagerService {
 @GET("/associate/annual-salaries.json")
 List<AnnualSalary> getAnnualSalaries();
 } 
 private static ApiManagerService sApiManagerService;
 
 public static ApiManagerService getApiManager() {
 if (sApiManagerService == null) {
 RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint(App.getWebServiceBaseURL())
 .build();
 sApiManagerService = adapter.create(ApiManagerService.class);
 }
 return sApiManagerService;
 }
 }
  7. Retrofit 2015 • Building the API Manager public class ApiManager

    { public interface ApiManagerService {
 @GET("/associate/annual-salaries.json")
 List<AnnualSalary> getAnnualSalaries();
 } 
 private static ApiManagerService sApiManagerService;
 
 public static ApiManagerService getApiManager() {
 if (sApiManagerService == null) {
 RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint(App.getWebServiceBaseURL())
 .build();
 sApiManagerService = adapter.create(ApiManagerService.class);
 }
 return sApiManagerService;
 }
 }
  8. Retrofit 2015 • Building the API Manager public class ApiManager

    { public interface ApiManagerService {
 @GET("/associate/annual-salaries.json")
 List<AnnualSalary> getAnnualSalaries();
 } 
 private static ApiManagerService sApiManagerService;
 
 public static ApiManagerService getApiManager() {
 if (sApiManagerService == null) {
 RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint(App.getWebServiceBaseURL())
 .build();
 sApiManagerService = adapter.create(ApiManagerService.class);
 }
 return sApiManagerService;
 }
 }
  9. Retrofit 2015 • Building the API Manager public class ApiManager

    { public interface ApiManagerService {
 @GET("/associate/annual-salaries.json")
 List<AnnualSalary> getAnnualSalaries();
 } 
 private static ApiManagerService sApiManagerService;
 
 public static ApiManagerService getApiManager() {
 if (sApiManagerService == null) {
 RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint(App.getWebServiceBaseURL())
 .build();
 sApiManagerService = adapter.create(ApiManagerService.class);
 }
 return sApiManagerService;
 }
 }
  10. Retrofit 2015 • Building the API Manager public class ApiManager

    { public interface ApiManagerService {
 @GET("/associate/annual-salaries.json")
 List<AnnualSalary> getAnnualSalaries();
 } 
 private static ApiManagerService sApiManagerService;
 
 public static ApiManagerService getApiManager() {
 if (sApiManagerService == null) {
 RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint(App.getWebServiceBaseURL())
 .build();
 sApiManagerService = adapter.create(ApiManagerService.class);
 }
 return sApiManagerService;
 }
 }
  11. Retrofit 2015 • Synchronous vs Asynchronous @GET("/associate/annual-salaries.json")
 List<AnnualSalary> getAnnualSalaries();
 


    @GET("/associate/annual-salaries.json")
 void getAnnualSalaries(Callback<List<AnnualSalary>> callback);
  12. Retrofit 2015 • Query @GET("/users")
 List<User> groupList(@Query("sort") String sort);
 


    @GET("/users")
 List<User> groupList(@QueryMap Map<String, String> options);
  13. Retrofit 2015 • Headers @Headers("Cache-Control: max-age=640000")
 @GET("/widget/list")
 List<Widget> widgetList();
 


    @Headers({
 "Accept: application/vnd.github.v3.full+json",
 "User-Agent: Retrofit-Sample-App"
 })
 @GET("/users/{username}")
 User getUser(@Path("username") String username);
  14. Retrofit 2015 • Headers RequestInterceptor requestInterceptor = new RequestInterceptor() {


    @Override
 public void intercept(RequestFacade request) {
 request.addHeader("User-Agent", "Retrofit-Sample-App");
 }
 };
 
 RestAdapter restAdapter = new RestAdapter.Builder()
 .setEndpoint("https://api.github.com")
 .setRequestInterceptor(requestInterceptor)
 .build(); sApiManagerService = restAdapter.create(ApiManagerService.class);
  15. Retrofit 2015 • RequestInterceptor RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint(App.getWSUrl())


    .setRequestInterceptor(new RequestInterceptor() {
 @Override
 public void intercept(RequestFacade request) {
 request.addQueryParam("u", getUserEmail()); 
 request.addQueryParam("t", getUserAuthToken());
 }
 }).build(); sApiManagerServicePull = adapter.create(ApiManagerServicePull.class);
  16. Retrofit 2015 • RequestInterceptor RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint(App.getWSUrl())


    .setRequestInterceptor(new RequestInterceptor() {
 @Override
 public void intercept(RequestFacade request) {
 request.addQueryParam("u", getUserEmail()); 
 request.addQueryParam("t", getUserAuthToken());
 }
 }).build(); sApiManagerServicePull = adapter.create(ApiManagerServicePull.class);
  17. Retrofit 2015 • RequestInterceptor interface RequestFacade { 
 void addHeader(String

    name, String value);
 
 void addPathParam(String name, String value);
 
 void addEncodedPathParam(String name, String value);
 
 void addQueryParam(String name, String value);
 
 void addEncodedQueryParam(String name, String value); 
 }
  18. Retrofit 2015 • Error handling public abstract class RestCallback<T> implements

    Callback<T> {
 public abstract void failure(RestError restError);
 
 @Override
 public void failure(RetrofitError error) {
 RestError restError = (RestError) error.getBodyAs(RestError.class);
 if (restError != null) {
 failure(restError);
 } else {
 failure(new RestError(error.getMessage()));
 }
 }
 } public class RestError {
 private String errorMessage;
 
 public RestError(String errorMessage) {
 this.errorMessage = errorMessage;
 }
 } { "error_message": “User not found" }
  19. Retrofit 2015 • Twitter API public interface TwitterService {
 @Headers({

    "Content-Type: application/x-www-form-urlencoded;charset=UTF-8"})
 @POST("/oauth2/token")
 Authenticated authorizeUser(
 @Header("Authorization") String authorization,
 @Header("Content-Length") String bodyLength,
 @Body TypedString grantType);
 
 @Headers({ "Content-Type: application/json" })
 @GET("/1.1/lists/statuses.json")
 List<Tweet> getTwitterStream(
 @Header("Authorization") String authorization,
 @Query("slug") String slug,
 @Query("owner_screen_name") String screenName);
 }
  20. Retrofit 2015 • Converters ObjectMapper mapper = new ObjectMapper(); 


    RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint(App.getWSUrl())
 .setConverter(new JacksonConverter(mapper))
 .build(); 
 sApiManagerService = adapter.create(ApiManagerService.class); // build.gradle: compile 'com.squareup.retrofit:converter-jackson:1.9.0'
  21. Retrofit 2015 • Jackson: fields ObjectMapper mapper = new ObjectMapper();


    mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
 
 RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint(App.getWSUrl())
 .setConverter(new JacksonConverter(mapper))
 .build();
 
 sApiManagerService = adapter.create(ApiManagerService.class);
  22. Retrofit 2015 • Jackson: property names ObjectMapper mapper = new

    ObjectMapper();
 mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
 mapper.setPropertyNamingStrategy(
 PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
 
 RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint(App.getWSUrl())
 .setConverter(new JacksonConverter(mapper))
 .build();
 
 sApiManagerService = adapter.create(ApiManagerService.class);
  23. Retrofit 2015 • Jackson: null values ObjectMapper mapper = new

    ObjectMapper();
 mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
 mapper.setPropertyNamingStrategy(
 PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); 
 RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint(App.getWSUrl())
 .setConverter(new JacksonConverter(mapper))
 .build();
 
 sApiManagerService = adapter.create(ApiManagerService.class);
  24. Retrofit 2015 • Jackson: dates ObjectMapper mapper = new ObjectMapper();


    mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
 mapper.setPropertyNamingStrategy(
 PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"));
 
 RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint(App.getWSUrl())
 .setConverter(new JacksonConverter(mapper))
 .build();
 
 sApiManagerService = adapter.create(ApiManagerService.class);
  25. Retrofit 2015 • Jackson ObjectMapper mapper = new ObjectMapper();
 mapper.setVisibility(PropertyAccessor.FIELD,

    JsonAutoDetect.Visibility.ANY);
 mapper.setPropertyNamingStrategy(
 PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"));
 if (!BuildConfig.DEBUG) {
 mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
 }
 
 RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint(App.getWSUrl())
 .setConverter(new JacksonConverter(mapper))
 .build();
 
 sApiManagerService = adapter.create(ApiManagerService.class);
  26. Retrofit 2015 • Jackson: property names @JsonProperty("id")
 protected String uuid;

    @JsonIgnore
 protected String uuid; @JsonProperty
 public String getId() {
 return uuid;
 }
  27. Retrofit 2015 • Jackson: property names @JsonProperty("id")
 protected String uuid;

    @JsonIgnore
 protected String uuid; @JsonProperty
 public String getId() {
 return uuid;
 }
  28. Retrofit 2015 • Jackson: properties @JsonIgnoreProperties({“original_id”, “updated_at”})
 public class Site

    extends ManagedObject { } @JsonProperty("updated_at")
 public void setUpdatedAt(Date updatedAt) {
 this.updatedAt = updatedAt;
 }
  29. Retrofit 2015 • Jackson: properties @JsonIgnoreProperties({“original_id”, “updated_at”})
 public class Site

    extends ManagedObject { } @JsonProperty("updated_at")
 public void setUpdatedAt(Date updatedAt) {
 this.updatedAt = updatedAt;
 }
  30. Retrofit 2015 • Multiple converters public static ApiManagerService getApiManager() {


    if (sApiManagerService == null) {
 
 RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint(App.getWSUrl()) .setConverter(new JacksonConverter(mapper))
 .build();
 
 sApiManagerService = adapter.create(ApiManagerService.class);
 }
 return sApiManagerService;
 }
 
 public static CanalApiManagerService getCanalApiManager() {
 if (sCanalApiManagerService == null) {
 RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint("https://secure-webtv.canal-plus.com")
 .setConverter(new SimpleXMLConverter()).build();
 
 sCanalApiManagerService = adapter.create(CanalApiManagerService.class);
 }
 return sCanalApiManagerService;

  31. Retrofit 2015 • Multiple converters public static ApiManagerService getApiManager() {


    if (sApiManagerService == null) {
 
 RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint(App.getWSUrl()) .setConverter(new JacksonConverter(mapper))
 .build();
 
 sApiManagerService = adapter.create(ApiManagerService.class);
 }
 return sApiManagerService;
 }
 
 public static CanalApiManagerService getCanalApiManager() {
 if (sCanalApiManagerService == null) {
 RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint("https://secure-webtv.canal-plus.com")
 .setConverter(new SimpleXMLConverter()).build();
 
 sCanalApiManagerService = adapter.create(CanalApiManagerService.class);
 }
 return sCanalApiManagerService;
 }
  32. Retrofit 2015 • Multiple converters public static ApiManagerService getApiManager() {


    if (sApiManagerService == null) {
 
 RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint(App.getWSUrl()) .setConverter(new JacksonConverter(mapper))
 .build();
 
 sApiManagerService = adapter.create(ApiManagerService.class);
 }
 return sApiManagerService;
 }
 
 public static CanalApiManagerService getCanalApiManager() {
 if (sCanalApiManagerService == null) {
 RestAdapter adapter = new RestAdapter.Builder()
 .setEndpoint("https://secure-webtv.canal-plus.com")
 .setConverter(new SimpleXMLConverter()).build();
 
 sCanalApiManagerService = adapter.create(CanalApiManagerService.class);
 }
 return sCanalApiManagerService;

  33. Retrofit 2015 • Logs RestAdapter restAdapter = new RestAdapter.Builder()
 .setEndpoint(“https://api.github.com")

    .build();
 if (BuildConfig.DEBUG) {
 restAdapter.setLogLevel(RestAdapter.LogLevel.FULL);
 } public enum LogLevel {
 NONE,
 BASIC,
 HEADERS,
 HEADERS_AND_ARGS,
 FULL;
 }
  34. Retrofit 2015 • Logs D/Retrofit﹕ ---> HTTP GET https://deco101.tortuba.com/api/v1/trips.json?since=Tue +Jan+20+21%3A29%3A54+GMT%2B01%3A00+2015&u=adrien.couque

    %40applidium.com&t=VjtC7zZxqp5thJpvShUb D/Retrofit﹕ ---> END HTTP (no body) D/Retrofit﹕ <--- HTTP 200 https://deco101.tortuba.com/api/v1/trips.json?since=Tue +Jan+20+21%3A29%3A54+GMT%2B01%3A00+2015&u=adrien.couque %40applidium.com&t=VjtC7zZxqp5thJpvShUb (810ms) D/Retrofit﹕ : HTTP/1.1 200 OK D/Retrofit﹕ Cache-Control: max-age=0, private, must-revalidate D/Retrofit﹕ CF-RAY: 1ac4d9b1275b1509-CDG D/Retrofit﹕ Connection: keep-alive D/Retrofit﹕ Content-Type: application/json; charset=utf-8 D/Retrofit﹕ Date: Wed, 21 Jan 2015 16:22:24 GMT D/Retrofit﹕ Server: cloudflare-nginx D/Retrofit﹕ Set-Cookie: __cfduid=d87f09effa9f48e43b0bc401ec5d0d7bc1421857344; expires=Thu, 21-Jan-16 16:22:24 GMT; path=/; domain=.tortuba.com; HttpOnly D/Retrofit﹕ Status: 200 OK D/Retrofit﹕ Strict-Transport-Security: max-age=31536000 D/Retrofit﹕ Transfer-Encoding: chunked D/Retrofit﹕ X-Android-Received-Millis: 1421857343782 D/Retrofit﹕ X-Android-Response-Source: NETWORK 200 D/Retrofit﹕ X-Android-Sent-Millis: 1421857343007 D/Retrofit﹕ X-Frame-Options: SAMEORIGIN D/Retrofit﹕ X-Request-Id: 1c9e3619-99d7-4fa8-a7e1-a2bcf62b0058 D/Retrofit﹕ X-Runtime: 0.088016 D/Retrofit﹕ X-Xss-Protection: 1; mode=block D/Retrofit﹕ {"trips":[]} D/Retrofit﹕ <--- END HTTP (12-byte body)
  35. Retrofit 2015 • HTTP Clients RestAdapter restAdapter = new RestAdapter.Builder()


    .setEndpoint("https://api.github.com")
 .setClient(new AndroidApacheClient())
 .build(); RestAdapter restAdapter = new RestAdapter.Builder()
 .setEndpoint("https://api.github.com")
 .setClient(new MockClient())
 .build();
  36. Retrofit 2015 • HTTP Clients RestAdapter restAdapter = new RestAdapter.Builder()


    .setEndpoint("https://api.github.com")
 .setClient(new AndroidApacheClient())
 .build(); RestAdapter restAdapter = new RestAdapter.Builder()
 .setEndpoint("https://api.github.com")
 .setClient(new MockClient())
 .build();
  37. Retrofit 2015 • MockClient public class MockClient implements Client {


    @Override
 public Response execute(Request request) throws IOException {
 Uri uri = Uri.parse(request.getUrl());
 
 List<String> pathSegments = uri.getPathSegments();
 String model = pathSegments.get(pathSegments.size() - 1).replace(".json", "");
 String path = String.format("test/%s/%s_INDEX.json", model, model);
 String responseString = convertStreamToString(App.getContext().getAssets().open(path));
 
 return new Response(
 request.getUrl(),
 200,
 "Success",
 Collections.<Header>emptyList(),
 new TypedByteArray(
 "application/json",
 responseString.getBytes()
 )
 );
 }
 }
  38. Retrofit 2015 • MockClient public class MockClient implements Client {


    @Override
 public Response execute(Request request) throws IOException {
 Uri uri = Uri.parse(request.getUrl());
 
 List<String> pathSegments = uri.getPathSegments();
 String model = pathSegments.get(pathSegments.size() - 1).replace(".json", "");
 String path = String.format("test/%s/%s_INDEX.json", model, model);
 String responseString = convertStreamToString(App.getContext().getAssets().open(path));
 
 return new Response(
 request.getUrl(),
 200,
 "Success",
 Collections.<Header>emptyList(),
 new TypedByteArray(
 "application/json",
 responseString.getBytes()
 )
 );
 }
 }
  39. Paris, 22 Janvier 2015 Applidium 20 rue Sainte-Croix de la

    Bretonnerie 75004 Paris www.applidium.com Merci