Я пишу библиотеку для REST API. Библиотека должна будет максимально скрывать от пользователя внутреннюю сложность API.
Я полагаюсь на retrofit2, настроенный на использование RxJava для упаковки ответов и GSon для их анализа.
Я использую дооснащение для службы 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, но мне он нужен только для поисковых запросов.
Есть ли у вас лучшая / креативная / элегантная идея?
MyService
, который вводит необходимые данные в модель результатов, либо создайте пользовательскийCallAdapter
, который анализируетRequest
из параметровCall
. он получает и генерирует желаемые объекты результата на его основе (возможный вариант реализацииRxJavaCallAdapterFactory
). - person corsair992   schedule 27.03.2016