我正在为REST API编写一个库。该库必须尽可能地向用户隐藏API的内部复杂性。
我依赖于retrofit2配置为使用RxJava包装响应和GSon来解析它们。
我正在使用retrofit来提供REST服务。
@GET("search")
Observable<SearchResult> search(@Query("q") String query);
@GET("search")
Observable<SearchResult> search(@QueryMap Map<String, String> params);
@GET("search")
Observable<SearchResult> searchNext(@Query("q") String query, @Query("startKey") String startKey);
@GET("search")
Observable<SearchResult> searchNext(@QueryMap Map<String, String> params, @Query("startKey") String startKey);
搜索REST服务返回JSON
{
"count": 2334,
"nextBatchKey": "SADjdfsahoi023451sadfjlskdfj02134512",
"results": [ .... ]
}
要获得下一批次,必须使用相同的参数再次调用该服务并返回密钥。
例如,假设搜索q=foo
和limit=20
:REST API将返回匹配字符串 foo 的结果,这些字符串分段为20个结果。要获得下一批,我需要使用相同的两个参数q=foo
和limit=20
创建另一个请求,添加startKey=<the next batch key>
。
我希望/需要向库的用户隐藏这些内部机制。
在我的库中,我初始化这样的改造:
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient) // added interceptors
.baseUrl(baseUrl) // my base url
.addConverterFactory(GsonConverterFactory.create(gson)) // custom type adapter factory
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
它为我的界面生成服务,并使用Gson
解析包含RxJava
Observable
的响应。
然后我获得了服务:
MyService service = retrofit.create(MyService.class)
请注意,我不会编写此服务的代码,因为改造可以使用我的界面(MyService
)注释自动生成服务。
从图书馆用户的角度来看,所有这些都是隐藏的,他只会收到服务并使用它:
// obtain the service
MyService service = MyLibrarySDK.getService(context);
// perform the search operation
Observable<SearchResult> resultObservable =
service.search(params);
我希望使用我的库的开发人员能够像这样获得下一批:
// then later result == the SearchResult
Observable<SearchResult> nextBatch =
result.searchNext();
searchNext()
调用不带参数。这意味着我在上一次调用中创建的SearchResult
对象应在内部知道使用方法searchNext(Map parameters, String key)
时要使用的参数。
如果用户使用q=foo
执行搜索呼叫,则不会在响应中收到此信息。我需要它。
由于改造创建服务,我不知道如何拦截通过调用service.search()
传递的方法参数。
我必须解决的唯一问题是使用OkHttp
拦截器,将查询参数映射放在ThreadLocal
中,然后使用自定义Gson
TypeAdapter
来将这些参数注入SearchResult
对象。
这个解决方案应该在技术上有效,但我觉得它很难看。此外,拦截器可以运行REST API的任何方法,但我只需要搜索查询。
你有更好的/有创意/优雅的想法吗?
答案 0 :(得分:0)
不要认为result
上应该有service
,而是public class MyService {
RestClient.GitApiInterface service = RestClient.getClient();
String query;
Observable<GitResult> resultObservable;
public Observable<GitResult> getUsersByName(String query) {
this.query = query;
resultObservable = service.getUsersByName(query, 0).cache();
return resultObservable;
}
public Observable<GitResult> searchNext() {
Observable nextResultObservable = resultObservable
.flatMap(new Func1<GitResult, Observable<?>>() {
@Override
public Observable<?> call(GitResult gitResult) {
return service.getUsersByName(query, gitResult.getNextPage());
}
});
return nextResultObservable;
}
}
上有final MyService service = new MyService();
// First load
service.getUsersByName("tom");
// consecutive calls
service.searchNext();
。
尝试以下内容:
<强> MyService.java 强>
{{1}}
<强>用法强>
{{1}}
示例应用 - https://gitlab.com/wizardkrishna/retrofit2-sample
<强>参考强>
Consuming REST API using Retrofit2
Observable Caching