Потребление разбитого на страницы API в реактивном стиле - PullRequest
0 голосов
/ 20 июня 2019

Я пытаюсь понять, как использовать разбитый на страницы API в реактивном стиле, открывая поток элементов вместо страниц, которые дает мне API.

Что у меня есть - API с разбивкой по страницам

Slack API (и многие другие) обрабатывают разбиение на страницы с какой-либо формой объекта метаданных, так что при запросе к /api/stuff вы получаете объект, подобный этому:

{
    "items": [ <list of first page you requested> ],
    "meta": {
        "cursor": "<a cursor string to get the next page>"
    }
}

Затем вы можете запросить следующую страницу с помощью GET /api/stuff?cursor=<the cursor from above>, и в ответе вы получите новый курсор, и поэтому вы можете продолжать идти до тех пор, пока не получите ответ, где курсор пуст - это была последняя доступная страница.

Что я хочу - поток элементов

В Reactor я хотел бы предоставить метод с типом возврата Flux<Item>, то есть поток всех элементов, где потребитель не можетнужно знать или заботиться о том, чтобы элементы действительно выбирались по одной странице за раз.

По сути, я хотел бы сделать что-то, что принимает начальное состояние и метод с подписью State -> Mono<Tuple2<Collection<Item>, State>> (или эквивалентный)и дает мне Flux<Item>последовательное извлечение новых страниц, пока State не покажет, что мы закончили.

Я пытался сформулировать что-то, используя Flux.create или Flux.generate, но кажется, что их варианты использования немного отличаются от моих.

Как мне туда добраться?

1 Ответ

0 голосов
/ 20 июня 2019

Я новичок в реакторе, но я думаю, что это то, что expand () для:

Вот полная демонстрация, где getFirstPage() и getNextPage() имитируют слабый API. getNextPage() возвращает последнюю страницу, когда курсор достигает значения 5.

public class Slack {
    public static void main(String[] args) {
        getFirstPage().expand(page -> getNextPage(page))
                      .flatMapIterable(page -> page.getResult())
                      .subscribe(System.out::println);
    }

    private static Mono<Page> getFirstPage() {
        System.out.println("getting first page");
        return Mono.just(new Page(Arrays.asList("page0-1", "page0-2"), 1));
    }

    private static Mono<Page> getNextPage(Page page) {
        System.out.println("getting page " + page.getCursor());
        if (page.getCursor() == null) {
            return Mono.empty();
        }
        Integer nextCursor = (page.getCursor() == 5) ? null : page.getCursor() + 1;
        return Mono.just(new Page(Arrays.asList("page" + page.getCursor() + "-1", "page" + page.getCursor() + "-2"), nextCursor));
    }

    static class Page {
        private List<String> result;
        private Integer cursor;

        public Page(List<String> result, Integer cursor) {
            this.result = result;
            this.cursor = cursor;
        }

        public List<String> getResult() {
            return result;
        }

        public Integer getCursor() {
            return cursor;
        }
    }
}
...