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

はやい・やすい・うまい!スタートアップでも使える Retrofit + RxJava で瞬間APIクッキングレシピ

はやい・やすい・うまい!スタートアップでも使える Retrofit + RxJava で瞬間APIクッキングレシピ

はやい・やすい・うまい!スタートアップでも使える Retrofit + RxJava で瞬間APIクッキングレシピ

Fumihiko Shiroyama

July 14, 2017
Tweet

More Decks by Fumihiko Shiroyama

Other Decks in Technology

Transcript

  1. ͸΍͍ɾ΍͍͢ɾ͏·͍ʂ

    ελʔτΞοϓͰ΋࢖͑Δ
    Retrofit + RxJava ͰॠؒAPIΫο
    ΩϯάϨγϐ
    @fushiroyama

    View full-size slide

  2. About Me
    • Fumihiko Shiroyama
    • Android App Developer
    • https://github.com/srym

    View full-size slide

  3. How to implement REST
    Client?
    • HTTP Client
    • Thread Executer
    • JSON Deserializer
    • Integration with RxJava

    View full-size slide

  4. Retrofit
    • A type-safe HTTP client for Android and Java
    • http://square.github.io/retrofit/
    • by Square

    View full-size slide

  5. Install
    // Retrofit
    compile "com.squareup.retrofit2:retrofit:${retrofitVersion}"
    compile "com.squareup.retrofit2:adapter-rxjava2:${retrofitVersion}"
    compile "com.squareup.retrofit2:converter-gson:${retrofitVersion}"
    // RxJava
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    compile "io.reactivex.rxjava2:rxjava:2.1.1"

    View full-size slide

  6. Retrofit
    public interface GitHubService {
    @GET("users/{user}/repos")
    Call> listRepos(@Path("user") String user);
    }

    View full-size slide

  7. Retrofit
    Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();
    GitHubService service =
    retrofit.create(GitHubService.class);

    View full-size slide

  8. Retrofit
    GitHubService service = retrofit.create(GitHubService.class);
    Call> repos = service.listRepos("srym");
    // synchronous call
    Response> response = repos.execute();
    // asynchronous call
    repos.enqueue( /* callback here */ );

    View full-size slide

  9. Integration with RxJava
    Retrofit retrofit = new Retrofit.Builder()
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .addConverterFactory(GsonConverterFactory.create(gson))
    .baseUrl("https://api.github.com/")
    .build();

    View full-size slide

  10. Change Return Type
    public interface GitHubService {
    @GET("users/{user}/repos")
    Single> listRepos(@Path("user") String user);
    }

    View full-size slide

  11. Subscribe
    Single> repos = service.listRepos("srym")
    repos
    .subscribe(
    list -> doSomethingToList(list),
    throwable -> Timber.d(throwable.getMessage(), throwable),
    () -> Timber.d("complete")
    );

    View full-size slide

  12. Link
    • RxJava+RetrofitͰAPI௨৴पΓΛ࣮૷͢Δ͏͑
    Ͱ࠷௿ݶͷ஌ࣝΛ30෼Ͱ٧ΊࠐΉ
    • http://qiita.com/FumihikoSHIROYAMA/
    items/201536d9b45ef21b6bc7

    View full-size slide

  13. Link
    • RetrofitΛ࢖ͬͨOAuth࠶ೝূΞϓϩʔν
    • http://qiita.com/FumihikoSHIROYAMA/
    items/ac1beaeaa9b4baaed939

    View full-size slide

  14. Link
    • RetrofitΛ࢖ͬͨAPIݺͼग़͠ͰϦΧόϦՄೳ
    ͳHTTPΤϥʔΛͲ͏ѻ͏͔໰୊
    • http://qiita.com/FumihikoSHIROYAMA/
    items/65d52aea1a9f324d347e

    View full-size slide

  15. What's Good about Retrofit +
    Rx
    • Easy to define
    • Easy to compose
    • Easy to test

    View full-size slide

  16. Test
    • MockWebServer
    • TestSubscriber

    View full-size slide

  17. MockWebServer
    • A scriptable web server for testing HTTP
    clients
    • https://github.com/square/okhttp/tree/
    master/mockwebserver

    View full-size slide

  18. MockWebServer
    private final MockWebServer mockWebServer
    = new MockWebServer();

    View full-size slide

  19. MockWebServer
    Dispatcher dispatcher = new Dispatcher() {
    @Override
    public MockResponse dispatch(RecordedRequest request)
    throws InterruptedException {
    return new MockResponse().setResponseCode(404);
    }
    };
    mockWebServer.setDispatcher(dispatcher);
    mockWebServer.start();

    View full-size slide

  20. MockWebServer
    @Override
    public 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);
    }

    View full-size slide

  21. MockWebServer
    Retrofit retrofit = new Retrofit.Builder()
    .baseUrl(mockWebServer.url(""))
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .addConverterFactory(GsonConverterFactory.create())
    .build();
    GitHubService gitHubService = retrofit.create(GitHubService.class);

    View full-size slide

  22. TestSubscriber
    • A TestSubscriber is a variety of Subscriber
    that you can use for unit testing, to perform
    assertions, inspect received events, or wrap a
    mocked Subscriber.
    • http://reactivex.io/RxJava/javadoc/rx/
    observers/TestSubscriber.html

    View full-size slide

  23. TestSubscriber
    restGitHubDataSource
    .listRepos("srym")
    .test();

    View full-size slide

  24. TestSubscriber
    List repos = restGitHubDataSource.listRepos("srym")
    .test()
    .await()
    .assertNoErrors()
    .assertComplete()
    .values()
    .get(0);
    assertThat(repos).isNotNull();

    View full-size slide

  25. 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

    View full-size slide

  26. Easy to compose
    • Rx's Observable is easily & flexibly combined
    • Avoid callback hells

    View full-size slide

  27. Easy to compose
    public class GitHubInfraRepository implements GitHubRepository {
    private final RemoteGitHubDataSource remoteDataSource;
    private final RepoMapper mapper;
    @Inject
    public GitHubInfraRepository(RemoteGitHubDataSource remoteDataSource,
    RepoMapper mapper) {
    this.remoteDataSource = remoteDataSource;
    this.mapper = mapper;
    }
    @Override
    public Single> listRepos(@NonNull String user) {
    return remoteDataSource
    .listRepos(user)
    .map(mapper::convert);
    }
    }

    View full-size slide

  28. Easy to compose
    private final RemoteGitHubDataSource remoteDataSource;
    private final LocalGitHubDataSource localGitHubDataSource;
    private final RepoMapper mapper;
    @Inject
    public GitHubInfraRepository(RemoteGitHubDataSource remoteDataSource,
    LocalGitHubDataSource localGitHubDataSource,
    RepoMapper mapper) {
    this.remoteDataSource = remoteDataSource;
    this.localGitHubDataSource = localGitHubDataSource;
    this.mapper = mapper;
    }

    View full-size slide

  29. Easy to compose
    @Override
    public Single> listRepos(@NonNull String user) {
    return remoteDataSource
    .listRepos(user)
    .map(mapper::convert);

    View full-size slide

  30. Easy to compose
    public Single> listRepos(@NonNull String user) {
    return localGitHubDataSource
    .listRepos(user)
    .onErrorResumeNext(
    remoteDataSource
    .listRepos(user)
    .retry(DEFAULT_RETRY)
    .doOnSuccess(localGitHubDataSource::save)
    )
    .map(mapper::convert);

    View full-size slide

  31. Android Clean Architecture
    • android10/Android-CleanArchitecture
    • https://github.com/android10/Android-
    CleanArchitecture
    • srym/Architecture
    • https://github.com/srym/Architecture

    View full-size slide