Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Retrofit
Search
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
110
ML Session n°8
acq
0
64
ML Session n°7
acq
0
26
ML Session n°6
acq
0
45
ML Session n°5
acq
0
65
ML Session n°4
acq
0
43
ML Session n°3
acq
0
110
ML Session n°2
acq
1
100
ML Session n°1
acq
0
97
Other Decks in Technology
See All in Technology
「ピッケル本」日本語版は4.0(第6版)が出版されるべき / pickaxe4-nagoyark05
kakutani
2
200
目の前の楽しいが人生を変える - コミュニティの螺旋の歩き方と楽しむコツ / change your life
soudai
PRO
5
650
LLMに渡さなかった仕事
nanaism
0
1k
AIエージェントの自己改善をどう設計するか / How to Design Self-Improvement for AI Agents
22mi
25
16k
GoのInterface内部構造から学ぶ!最高パフォーマンスを出すコード設計
yappli_developers
0
190
技術的負債から考える、AI時代のエンジニアリング投資 — ビズリーチの技術的負債と向き合った経験から、変更し続けられるソフトウェアを考える/ technical-debt-con2026
visional_engineering_and_design
4
3.2k
beyond jj: config & tools ecosystem
indirect
0
5.2k
アプリをもっと"iOSアプリっぽく"する小さな工夫 / Small Touches That Make Your App Feel More Like an iOS App
matsuji
2
960
銀行勘定系システムにおける開発プロセス刷新×AIによる環境モダナイゼーション / Development Process Transformation and AI-Driven Environment Modernization
muit
1
2.4k
EventBridge に「合流」はない ― サーバーレスのワークフローを育てるということ / No Join in EventBridge
yusukeshimizu
2
200
Reactの設計論
uhyo
24
14k
新機種発売前に見直そう!端末移行で再ログインが要るアプリ・要らないアプリは何が違うのか 〜シームレスに再開できる設計と実装〜
zozotech
PRO
0
210
Featured
See All Featured
Ethics towards AI in product and experience design
skipperchong
2
380
Joys of Absence: A Defence of Solitary Play
codingconduct
1
520
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
530
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
540
BBQ
matthewcrist
89
10k
Fireside Chat
paigeccino
43
4k
Navigating Weather and Climate Data
rabernat
0
520
How to make the Groovebox
asonas
2
2.4k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
Test your architecture with Archunit
thirion
2
2.4k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
890
The Cost Of JavaScript in 2023
addyosmani
55
10k
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