Udostępnij przez


TripPin — Część 5 — Stronicowanie

Ten wieloczęściowy samouczek obejmuje tworzenie nowego rozszerzenia źródła danych dla dodatku Power Query. Samouczek ma być wykonywany sekwencyjnie — każda lekcja opiera się na łączniku utworzonym w poprzednich lekcjach, przyrostowo dodając nowe możliwości do łącznika.

W tej lekcji wykonasz następujące czynności:

  • Dodaj funkcję stronicowania do łącznika

Wiele interfejsów API REST zwraca dane na "stronach", co wymaga od klientów wykonania wielu żądań w celu połączenia wyników. Chociaż istnieją pewne typowe konwencje dotyczące stronicowania (na przykład RFC 5988), zwykle różni się ono w zależności od interfejsu API. Na szczęście TripPin jest usługą OData, a standard OData definiuje sposób stronicowania przy użyciu wartości odata.nextLink zwróconych w treści odpowiedzi.

Aby uprościć poprzednie iteracje łącznika, TripPin.Feed funkcja nie rozpoznaje stron. Po prostu przeanalizowano dowolny JSON zwrócony z żądania i sformatowano go jako tabelę. Jeśli znasz protokół OData, możesz zauważyć, że wiele nieprawidłowych założeń zostało założeń w formacie odpowiedzi (na przykład przy założeniu , że istnieje value pole zawierające tablicę rekordów).

W tej lekcji ulepszysz logikę obsługi odpowiedzi, dostosowując ją do kontekstu strony. Przyszłe samouczki sprawiają, że logika obsługi stron jest bardziej niezawodna i umożliwia obsługę wielu formatów odpowiedzi (w tym błędów z usługi).

Uwaga / Notatka

Nie musisz implementować własnej logiki stronicowania z łącznikami opartymi na protokole OData.Feed, ponieważ automatycznie obsługuje je wszystko.

Lista kontrolna stronicowania

Podczas implementowania obsługi stronicowania należy znać następujące kwestie dotyczące interfejsu API:

  • Jak zażądać następnej strony danych?
  • Czy mechanizm stronicowania obejmuje obliczanie wartości, czy wyodrębniasz adres URL następnej strony z odpowiedzi?
  • Jak sprawdzić, kiedy zatrzymać stronicowanie?
  • Czy istnieją parametry związane z stronicowaniem, o których należy pamiętać (na przykład "rozmiar strony")?

Odpowiedź na te pytania ma wpływ na sposób implementowania logiki stronicowania. Chociaż istnieje pewna ilość kodu wielokrotnego w implementacjach stronicowania (takich jak użycie metody Table.GenerateByPage), większość łączników wymaga logiki niestandardowej.

Uwaga / Notatka

Ta lekcja zawiera logikę stronicowania dla usługi OData, która jest zgodna z określonym formatem. Zapoznaj się z dokumentacją interfejsu API, aby określić zmiany, które należy wprowadzić w łączniku, aby obsługiwać jego format stronicowania.

Omówienie stronicowania OData

Sterowanie stronicowaniem OData odbywa się za pomocą adnotacji nextLink zawartych w ładunku odpowiedzi. Wartość nextLink zawiera adres URL do następnej strony danych. Aby określić, czy istnieje inna strona danych, poszukaj pola odata.nextLink w najbardziej zewnętrznym obiekcie odpowiedzi. Jeśli nie ma odata.nextLink pola, wszystkie dane są odczytywane.

{
  "odata.context": "...",
  "odata.count": 37,
  "value": [
    { },
    { },
    { }
  ],
  "odata.nextLink": "...?$skiptoken=342r89"
}

Niektóre usługi OData umożliwiają klientom określenie preferencji maksymalnego rozmiaru strony, ale to usługa decyduje, czy ją uwzględnić. Dodatek Power Query powinien mieć możliwość obsługi odpowiedzi o dowolnym rozmiarze, więc nie musisz martwić się o określanie preferencji rozmiaru strony — możesz obsługiwać odpowiedzi o dowolnym rozmiarze, jakie dostarcza usługa.

Więcej informacji na temat stronicowania sterowanego serwerem można znaleźć w specyfikacji OData.

Testowanie TripPin

Przed naprawieniem implementacji stronicowania potwierdź bieżące działanie rozszerzenia z poprzedniego samouczka. Poniższe zapytanie testowe pobiera tabelę People i dodaje kolumnę indeksu, aby pokazać bieżącą liczbę wierszy.

let
    source = TripPin.Contents(),
    data = source{[Name="People"]}[Data],
    withRowCount = Table.AddIndexColumn(data, "Index")
in
    withRowCount

Włącz program Fiddler i uruchom zapytanie w zestawie POWER Query SDK. Zapytanie zwraca tabelę z ośmioma wierszami (indeks od 0 do 7).

Zrzut ekranu karty Wyników PQTest przedstawiający tabelę z wierszami indeksu od 0 do 7.

Jeśli spojrzysz na treść odpowiedzi z narzędzia Fiddler, zawiera ono w rzeczywistości pole @odata.nextLink, wskazujące, że jest dostępnych więcej stron danych.

{
  "@odata.context": "https://services.odata.org/V4/TripPinService/$metadata#People",
  "@odata.nextLink": "https://services.odata.org/v4/TripPinService/People?%24skiptoken=8",
  "value": [
    { },
    { },
    { }
  ]
}

Implementowanie stronicowania dla elementu TripPin

Teraz wprowadź następujące zmiany w rozszerzeniu:

  1. Zaimportuj wspólną Table.GenerateByPage funkcję.
  2. Dodaj funkcję GetAllPagesByNextLink, która używa Table.GenerateByPage do łączenia wszystkich stron.
  3. GetPage Dodaj funkcję, która może odczytywać jedną stronę danych.
  4. Dodaj funkcję GetNextLink aby wyodrębnić następny adres URL z odpowiedzi.
  5. Zaktualizuj TripPin.Feed , aby używać nowych funkcji czytnika stron.

Uwaga / Notatka

Jak wspomniano wcześniej w tym samouczku, logika stronicowania różni się w zależności od źródeł danych. Implementacja w tym miejscu próbuje podzielić logikę na funkcje, które powinny być wielokrotnego użytku dla źródeł, które używają następnych linków zwróconych w odpowiedzi.

Table.GenerateByPage

Aby połączyć (potencjalnie) wiele stron zwróconych przez źródło w jedną tabelę, użyj polecenia Table.GenerateByPage. Ta funkcja przyjmuje jako argument getNextPage funkcję, która powinna robić tylko to, co sugeruje jego nazwa: pobierz następną stronę danych. Table.GenerateByPage wielokrotnie wywołuje funkcję getNextPage, za każdym razem przekazując jej wyniki wygenerowane podczas ostatniego wywołania, aż powróci null aby sygnalizować, że nie ma więcej dostępnych stron.

Ponieważ ta funkcja nie jest częścią standardowej biblioteki dodatku Power Query, należy skopiować kod źródłowy do pliku pq.

Treść GetAllPagesByNextLink funkcji implementuje getNextPage argument funkcji dla Table.GenerateByPage elementu. Wywołuje GetPage funkcję i pobiera adres URL następnej strony danych z NextLink pola rekordu meta z poprzedniego wywołania.

// Read all pages of data.
// After every page, we check the "NextLink" record on the metadata of the previous request.
// Table.GenerateByPage will keep asking for more pages until we return null.
GetAllPagesByNextLink = (url as text) as table =>
    Table.GenerateByPage((previous) => 
        let
            // if previous is null, then this is our first page of data
            nextLink = if (previous = null) then url else Value.Metadata(previous)[NextLink]?,
            // if NextLink was set to null by the previous call, we know we have no more data
            page = if (nextLink <> null) then GetPage(nextLink) else null
        in
            page
    );

Implementowanie programu GetPage

Funkcja GetPage używa elementu Web.Contents do pobierania pojedynczej strony danych z usługi TripPin i konwertuje odpowiedź na tabelę. Przekazuje odpowiedź z Web.Contents do funkcji GetNextLink w celu wyodrębnienia adresu URL następnej strony i zapisuje go w rekordzie meta zwróconej tabeli (strony danych).

Ta implementacja jest nieco zmodyfikowaną wersją TripPin.Feed wywołania z poprzednich samouczków.

GetPage = (url as text) as table =>
    let
        response = Web.Contents(url, [ Headers = DefaultRequestHeaders ]),        
        body = Json.Document(response),
        nextLink = GetNextLink(body),
        data = Table.FromRecords(body[value])
    in
        data meta [NextLink = nextLink];

Funkcja GetNextLink po prostu sprawdza treść odpowiedzi dla @odata.nextLink pola i zwraca jej wartość.

// In this implementation, 'response' is the parsed body of the response after the call to Json.Document.
// Look for the '@odata.nextLink' field and simply return null if it doesn't exist.
GetNextLink = (response) as nullable text => Record.FieldOrDefault(response, "@odata.nextLink");

Łączenie tego wszystkiego

Ostatnim krokiem implementacji logiki stronicowania jest aktualizacja TripPin.Feed w celu korzystania z nowych funkcji. Na razie po prostu wywołujesz GetAllPagesByNextLink, ale w następnych samouczkach dodasz nowe funkcje, takie jak wymuszanie schematu i logika parametrów zapytania.

TripPin.Feed = (url as text) as table => GetAllPagesByNextLink(url);

Jeśli uruchomisz ponownie to samo zapytanie testowe z wcześniejszej wersji samouczka, teraz powinien zostać wyświetlony czytnik stron w akcji. Powinieneś również zauważyć, że masz 24 wiersze w odpowiedzi zamiast ośmiu.

Zrzut ekranu pokazujący kartę Wyjście wyniku PQTest z 24 wierszami danych.

Jeśli przyjrzysz się żądaniom w narzędziu fiddler, powinny być teraz widoczne oddzielne żądania dla każdej strony danych.

Zrzut ekranu przedstawiający dane wyjściowe programu Fiddler z oddzielnymi żądaniami dla każdej strony danych.

Uwaga / Notatka

Możesz zauważyć zduplikowane żądania dla pierwszej strony danych z usługi, co nie jest sytuacją idealną. Dodatkowe żądanie jest wynikiem zachowania sprawdzania schematu silnika M. Zignoruj ten problem na razie i rozwiąż go w następnym samouczku, w którym zastosujesz jawny schemat.

Podsumowanie

W tej lekcji pokazano, jak zaimplementować obsługę stronicowania dla interfejsu API REST. Chociaż logika prawdopodobnie różni się między interfejsami API, wzorzec ustanowiony tutaj powinien być wielokrotnego użytku z drobnymi modyfikacjami.

W następnej lekcji przyjrzysz się, jak zastosować jawny schemat do danych, wykraczając poza proste typy danych text i number uzyskiwane z Json.Document.

Dalsze kroki

TripPin — część 6 — schemat