はやい・やすい・うまい!スタートアップでも使える Retrofit + RxJava で瞬間APIクッキングレシピ
͍ɾ͍͢ɾ͏·͍ʂ ελʔτΞοϓͰ͑ΔRetrofit + RxJava ͰॠؒAPIΫοΩϯάϨγϐ@fushiroyama
View Slide
About Me• Fumihiko Shiroyama• Android App Developer• https://github.com/srym
How to implement RESTClient?• HTTP Client• Thread Executer• JSON Deserializer• Integration with RxJava
Retrofit
Retrofit• A type-safe HTTP client for Android and Java• http://square.github.io/retrofit/• by Square
Install// Retrofitcompile "com.squareup.retrofit2:retrofit:${retrofitVersion}"compile "com.squareup.retrofit2:adapter-rxjava2:${retrofitVersion}"compile "com.squareup.retrofit2:converter-gson:${retrofitVersion}"// RxJavacompile 'io.reactivex.rxjava2:rxandroid:2.0.1'compile "io.reactivex.rxjava2:rxjava:2.1.1"
Retrofitpublic interface GitHubService {@GET("users/{user}/repos")Call> listRepos(@Path("user") String user);}
RetrofitRetrofit retrofit = new Retrofit.Builder().baseUrl("https://api.github.com/").build();GitHubService service =retrofit.create(GitHubService.class);
RetrofitGitHubService service = retrofit.create(GitHubService.class);Call> repos = service.listRepos("srym");// synchronous callResponse> response = repos.execute();// asynchronous callrepos.enqueue( /* callback here */ );
Integration with RxJavaRetrofit retrofit = new Retrofit.Builder().addCallAdapterFactory(RxJava2CallAdapterFactory.create()).addConverterFactory(GsonConverterFactory.create(gson)).baseUrl("https://api.github.com/").build();
Change Return Typepublic interface GitHubService {@GET("users/{user}/repos")Single> listRepos(@Path("user") String user);}
SubscribeSingle> repos = service.listRepos("srym")repos.subscribe(list -> doSomethingToList(list),throwable -> Timber.d(throwable.getMessage(), throwable),() -> Timber.d("complete"));
Link• RxJava+RetrofitͰAPI௨৴पΓΛ࣮͢Δ͏͑Ͱ࠷ݶͷࣝΛ30Ͱ٧ΊࠐΉ• http://qiita.com/FumihikoSHIROYAMA/items/201536d9b45ef21b6bc7
Link• RetrofitΛͬͨOAuth࠶ೝূΞϓϩʔν• http://qiita.com/FumihikoSHIROYAMA/items/ac1beaeaa9b4baaed939
Link• RetrofitΛͬͨAPIݺͼग़͠ͰϦΧόϦՄೳͳHTTPΤϥʔΛͲ͏ѻ͏͔• http://qiita.com/FumihikoSHIROYAMA/items/65d52aea1a9f324d347e
What's Good about Retrofit +Rx• Easy to define• Easy to compose• Easy to test
Test• MockWebServer• TestSubscriber
MockWebServer• A scriptable web server for testing HTTPclients• https://github.com/square/okhttp/tree/master/mockwebserver
MockWebServerprivate final MockWebServer mockWebServer= new MockWebServer();
MockWebServerDispatcher dispatcher = new Dispatcher() {@Overridepublic MockResponse dispatch(RecordedRequest request)throws InterruptedException {return new MockResponse().setResponseCode(404);}};mockWebServer.setDispatcher(dispatcher);mockWebServer.start();
MockWebServer@Overridepublic MockResponse dispatch(RecordedRequest request) {if (request == null || request.getPath() == null) {return new MockResponse().setResponseCode(400);}if (request.getPath().matches("/users/.+/repos")) {return new MockResponse().setBody(readJsonFromResources("users_repos.json")).setResponseCode(200);}return new MockResponse().setResponseCode(404);}
MockWebServerRetrofit retrofit = new Retrofit.Builder().baseUrl(mockWebServer.url("")).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).addConverterFactory(GsonConverterFactory.create()).build();GitHubService gitHubService = retrofit.create(GitHubService.class);
TestSubscriber• A TestSubscriber is a variety of Subscriberthat you can use for unit testing, to performassertions, inspect received events, or wrap amocked Subscriber.• http://reactivex.io/RxJava/javadoc/rx/observers/TestSubscriber.html
TestSubscriberrestGitHubDataSource.listRepos("srym").test();
TestSubscriberList repos = restGitHubDataSource.listRepos("srym").test().await().assertNoErrors().assertComplete().values().get(0);assertThat(repos).isNotNull();
TestSubscriber• https://github.com/srym/Architecture• https://github.com/srym/Architecture/blob/master/app/src/test/java/us/shiroyama/android/architecture/infrastructure/repository/datasource/remote/RestGitHubDataSourceTest.java
Easy to compose• Rx's Observable is easily & flexibly combined• Avoid callback hells
Easy to composepublic class GitHubInfraRepository implements GitHubRepository {private final RemoteGitHubDataSource remoteDataSource;private final RepoMapper mapper;@Injectpublic GitHubInfraRepository(RemoteGitHubDataSource remoteDataSource,RepoMapper mapper) {this.remoteDataSource = remoteDataSource;this.mapper = mapper;}@Overridepublic Single> listRepos(@NonNull String user) {return remoteDataSource.listRepos(user).map(mapper::convert);}}
Easy to composeprivate final RemoteGitHubDataSource remoteDataSource;private final LocalGitHubDataSource localGitHubDataSource;private final RepoMapper mapper;@Injectpublic GitHubInfraRepository(RemoteGitHubDataSource remoteDataSource,LocalGitHubDataSource localGitHubDataSource,RepoMapper mapper) {this.remoteDataSource = remoteDataSource;this.localGitHubDataSource = localGitHubDataSource;this.mapper = mapper;}
Easy to compose@Overridepublic Single> listRepos(@NonNull String user) {return remoteDataSource.listRepos(user).map(mapper::convert);
Easy to composepublic Single> listRepos(@NonNull String user) {return localGitHubDataSource.listRepos(user).onErrorResumeNext(remoteDataSource.listRepos(user).retry(DEFAULT_RETRY).doOnSuccess(localGitHubDataSource::save)).map(mapper::convert);
Android Clean Architecture• android10/Android-CleanArchitecture• https://github.com/android10/Android-CleanArchitecture• srym/Architecture• https://github.com/srym/Architecture