Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Retrofit
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Adrien Couque
January 22, 2015
Technology
130
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Retrofit
Adrien Couque
January 22, 2015
More Decks by Adrien Couque
See All by Adrien Couque
A roadmap to psychohistory
acq
0
100
ML Session n°8
acq
0
64
ML Session n°7
acq
0
26
ML Session n°6
acq
0
40
ML Session n°5
acq
0
64
ML Session n°4
acq
0
40
ML Session n°3
acq
0
110
ML Session n°2
acq
1
95
ML Session n°1
acq
0
96
Other Decks in Technology
See All in Technology
データサイエンスを価値につなげるプロジェクト設計 〜 DS一年目が現場で得た気づき 〜
ysd113
1
250
就職⽀援サービスにおけるキャリアアドバイザーのシフトスケジューリング
recruitengineers
PRO
1
150
あなたの知らないPDFのアクセシビリティ
lycorptech_jp
PRO
0
200
2026TECHFRESH畢業分享會 - Lightning Talk - 資料也要 CI/CD? 用 Airbyte 自動化資料同步
line_developers_tw
PRO
0
1.1k
「エンジニア進化論」2028年の開発完全自動化、エンジニアはどう進化するか
cyberagentdevelopers
PRO
6
5.2k
失敗を経て、Harness Engineering で 大切にしたいことを考える / Learning from Failure: What Matters in Harness Engineering
bitkey
PRO
1
370
AAIFに入ってみた ~内から見えるコミュニティ動向~
sato4
0
240
2026 TECHFRESH 畢業分享會 - AI-Native 重塑軟體工程與虛擬講師
line_developers_tw
PRO
0
1.1k
Oracle AI Database@Google Cloud:サービス概要のご紹介
oracle4engineer
PRO
6
1.5k
小さく始める AI 活用推進 ― 日経電子版 Web チームの事例/nikkei-tech-talk47
nikkei_engineer_recruiting
0
270
脆弱性対応、どこで線を引くか
rymiyamoto
1
390
Claude Codeをどのように キャッチアップしているか
oikon48
13
8.1k
Featured
See All Featured
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.2k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
620
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.5k
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
71
40k
Ruling the World: When Life Gets Gamed
codingconduct
0
250
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
230
How to Talk to Developers About Accessibility
jct
2
230
Designing for Timeless Needs
cassininazir
1
250
30 Presentation Tips
portentint
PRO
1
320
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
240
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
170
Transcript
an introduction to Retrofit Applidium
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) { // … } });
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 } });
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 } });
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 } });
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 } });
Retrofit 2015 • New way @GET("/associate/annual-salaries.json") List<AnnualSalary> getAnnualSalaries();
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; } }
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; } }
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; } }
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; } }
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; } }
Retrofit 2015 • HTTP Verbs @GET(“/foo/bar”) @POST(“/foo/bar”) @PUT(“/foo/bar”) @PATCH(“/foo/bar”) @DELETE(“/foo/bar”)
@HEAD(“/foo/bar”)
Retrofit 2015 • Synchronous vs Asynchronous @GET("/associate/annual-salaries.json") List<AnnualSalary> getAnnualSalaries();
@GET("/associate/annual-salaries.json") void getAnnualSalaries(Callback<List<AnnualSalary>> callback);
Retrofit 2015 • Path @GET("/group/{id}/users") List<User> groupList(@Path("id") int groupId);
Retrofit 2015 • Query @GET("/users") List<User> groupList(@Query("sort") String sort);
@GET("/users") List<User> groupList(@QueryMap Map<String, String> options);
Retrofit 2015 • Body @POST("/users/new") User createUser(@Body User user);
Retrofit 2015 • Form encoding @FormUrlEncoded @POST("/user/edit") User updateUser(@Field("first_name") String
first, @Field("last_name") String last);
Retrofit 2015 • Multipart @Multipart @PUT("/user/photo") User updateUser(@Part("photo") TypedFile photo,
@Part("description") TypedString description);
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);
Retrofit 2015 • Headers @GET("/user") User getUser(@Header("Authorization") String authorization);
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);
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);
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);
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); }
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" }
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); }
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'
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);
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);
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);
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);
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);
Retrofit 2015 • Jackson: property names @JsonProperty("id") protected String uuid;
@JsonIgnore protected String uuid; @JsonProperty public String getId() { return uuid; }
Retrofit 2015 • Jackson: property names @JsonProperty("id") protected String uuid;
@JsonIgnore protected String uuid; @JsonProperty public String getId() { return uuid; }
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; }
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; }
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;
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; }
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;
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; }
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)
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();
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();
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() ) ); } }
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() ) ); } }
Retrofit 2015 • Next time: RxJava
Paris, 22 Janvier 2015 Applidium 20 rue Sainte-Croix de la
Bretonnerie 75004 Paris www.applidium.com Merci