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
110
ML Session n°8
acq
0
64
ML Session n°7
acq
0
26
ML Session n°6
acq
0
43
ML Session n°5
acq
0
64
ML Session n°4
acq
0
42
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
My broken English still works: speaking at global OSS events
naruoga
0
120
平文パスワードはログに“残り” ── 肝心の侵入は“痕跡すら残らない”
kuroneko13
0
110
ハッカソンで入賞した話 @ Findy LT
asari194617
0
1.4k
AI-DLC実践録_フルサイクル開発への挑戦
miyuc
0
320
Android skills に学ぶ
kokiko
0
130
MulticaとPi Coding Agentで、小規模OSSを30本同時運用した流れ
eiei114
0
140
35分でわかるEffective Platform Engineering
nwiizo
5
570
SmartHR Engineering Team Deck
smarthr
1
3.2k
Kiro Crew入門 - 常駐エージェントの仕組みと使いどころ / Intro to Kiro Crew
k_adachi_01
1
670
Bits Agent Builder の⼊⾨と活⽤事例
nulabinc
PRO
0
260
AIペネトレーションテスト・ セキュリティ検証「AgenticSec」紹介資料
laysakura
2
9.3k
:syncing_time:
sksat
2
130
Featured
See All Featured
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
950
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
380
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
470
Fireside Chat
paigeccino
42
4k
Color Theory Basics | Prateek | Gurzu
gurzu
0
430
How Software Deployment tools have changed in the past 20 years
geshan
1
34k
Information Architects: The Missing Link in Design Systems
soysaucechin
1
1.1k
Balancing Empowerment & Direction
lara
6
1.2k
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