TripPin Časť 5 - Stránkovanie

Tento viacdielny návod zahŕňa vytvorenie nového rozšírenia zdroja údajov pre Power Query. Výukový program je určený na postupné — každej lekcie, ktorá stavia na konektore vytvorenom v predchádzajúcich lekciách a postupne pridáva nové možnosti do konektora.

V tejto lekcii budete:

  • Pridanie podpory stránkovania do konektora

Mnohé rest api vrátia údaje na "stránkach", čo vyžaduje, aby klienti urobili viacero žiadostí o šitie výsledkov dohromady. Hoci existujú niektoré spoločné konvencie pre stránkovanie (napríklad RFC 5988),vo všeobecnosti sa líši od API k API. Našťastie TripPin je služba OData a štandard OData definuje spôsob, ako vykonávať stránkovanie pomocou hodnôt odata.nextLink vrátených v tele odpovede.

Na zjednodušenie predchádzajúcich iterácií konektora TripPin.Feed funkcia nevedela o stránke. Jednoducho sa znávrtovalo všetko, čo JSON bolo vrátené zo žiadosti a naformátovalo ju ako tabuľku. Tí, ktorí sú oboznámení s protokolom OData, si mohli všimnúť, že vo formáte odpovede bolo urobených niekoľko nesprávnych predpokladov (napríklad za predpokladu, že existuje pole obsahujúce pole obsahujúce pole value záznamov).

V tejto lekcii zlepšíte svoju logiku spracovania odpovedí tým, že ju budete informovať. Budúce tutoriály urobia logiku spracovania stránok robustnejšou a schopnou zvládnuť viaceré formáty odpovedí (vrátane chýb zo služby).

Poznámka

Nemusíte implementovať svoju vlastnú paging logiku s konektormi založenými na OData.Feed, pretože to všetko zvládne za vás automaticky.

Kontrolný zoznam stránkovania

Pri implementácii podpory stránkovania budete musieť vedieť o rozhraní API nasledujúce informácie:

  • Ako požadujete ďalšiu stránku údajov?
  • Zahŕňa stránkovanie mechanizmus výpočet hodnôt, alebo extrahujete URL adresu pre ďalšiu stránku z odpovede?
  • Ako viete, kedy prestať stránkovať?
  • Existujú parametre súvisiace s stránkovaním, o ktorých by ste mali vedieť? (napríklad "veľkosť strany")

Odpoveď na tieto otázky bude mať vplyv na spôsob, akým implementujete svoju paging logiku. Aj keď existuje určité množstvo opakovaného použitia kódu v rámci implementácie stránkovania (napríklad použitie Table.GenerateByPage, väčšina konektorov nakoniec bude vyžadovať vlastnú logiku.

Poznámka

Táto lekcia obsahuje logiku stránkovania pre službu OData, ktorá sa riadi konkrétnym formátom. Skontrolujte dokumentáciu pre rozhranie API a zistite zmeny, ktoré budete musieť vykonať v konektore na podporu jeho stránkovania formátu.

Prehľad OData Paging

Stránkovanie OData je poháňané poznámkami nextLink obsiahnutými v dátovej záťaži odozvy. Hodnota nextLink obsahuje URL adresu na nasledujúcu stránku údajov. Budete vedieť, či existuje iná stránka údajov vyhľadáte odata.nextLink pole v najvzdialenejšom objekte v odpovedi. Ak nie je odata.nextLink žiadne pole, prečítali ste si všetky údaje.

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

Niektoré služby OData umožňujú klientom poskytnúť maximálnu preferenciu veľkosti stránky, ale je na službe, či ju bude alebo nie. Power Query by mal byť schopný zvládnuť odpovede akejkoľvek veľkosti, takže sa nemusíte obávať zadania preferencie veľkosti strany, ktorú môžete podporiť bez ohľadu na to, — čo na vás služba hodí.

Ďalšie informácie o stránkovaní založenom na serveri nájdete v špecifikácii OData.

Testovanie TripPin

Pred opravou implementácie stránkovania potvrďte aktuálne správanie rozšírenia z predchádzajúceho tutoriálu. Nasledujúci testovací dotaz načíta tabuľku Ľudia a pridá stĺpec indexu, aby sa zobrazil aktuálny počet riadkov.

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

Zapnite fiddlera a spustite dotaz v Visual Studio. Všimnite si, že dotaz vráti tabuľku s 8 riadkami (index 0 až 7).

QueryWithoutPaging.

Ak sa pozriete na telo odpovede od fiddlera, uvidíte, že v skutočnosti obsahuje @odata.nextLink pole, čo naznačuje, že je k dispozícii viac stránok údajov.

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

Implementácia stránkovania pre TripPin

Teraz budete robiť nasledujúce zmeny v rozšírení:

  1. Import spoločnej Table.GenerateByPage funkcie
  2. Pridanie GetAllPagesByNextLink funkcie, ktorá sa používa Table.GenerateByPage na lepenie všetkých strán dohromady
  3. Pridanie GetPage funkcie, ktorá dokáže čítať jednu stranu údajov
  4. Pridanie GetNextLink funkcie na extrahovanie ďalšej adresy URL z odpovede
  5. Aktualizácia TripPin.Feed na používanie nových funkcií čítačky stránok

Poznámka

Ako už bolo uvedené v tomto tutoriále, logika stránkovania sa bude líšiť medzi zdrojmi údajov. Implementácia sa tu pokúša rozdeliť logiku na funkcie, ktoré by mali byť opakovane použiteľné pre zdroje, ktoré používajú ďalšie odkazy vrátené v odpovedi.

Table.GenerateByPage

Table.GenerateByPageFunkciu je možné použiť na efektívne spojenie viacerých "strán" údajov do jednej tabuľky. Robí to opakovaným volaním funkcie odovzdanej ako getNextPage parameter, až kým nedostane null . Parameter funkcie musí mať jeden argument a vrátiť nullable table .

getNextPage = (lastPage) as nullable table => ...

Každý hovor na getNextPage volanie na volanie výstup z predchádzajúceho hovoru.

// The getNextPage function takes a single argument and is expected to return a nullable table
Table.GenerateByPage = (getNextPage as function) as table =>
    let        
        listOfPages = List.Generate(
            () => getNextPage(null),            // get the first page of data
            (lastPage) => lastPage <> null,     // stop when the function returns null
            (lastPage) => getNextPage(lastPage) // pass the previous page to the next function call
        ),
        // concatenate the pages together
        tableOfPages = Table.FromList(listOfPages, Splitter.SplitByNothing(), {"Column1"}),
        firstRow = tableOfPages{0}?
    in
        // if we didn't get back any pages of data, return an empty table
        // otherwise set the table type based on the columns of the first page
        if (firstRow = null) then
            Table.FromRows({})
        else        
            Value.ReplaceType(
                Table.ExpandTableColumn(tableOfPages, "Column1", Table.ColumnNames(firstRow[Column1])),
                Value.Type(firstRow[Column1])
            );

Niekoľko poznámok Table.GenerateByPage k:

  • getNextPageFunkcia bude musieť načítať nasledujúcu webovú adresu stránky (alebo číslo strany alebo akékoľvek iné hodnoty, ktoré sa použijú na implementáciu logiky stránkovania). Toto sa zvyčajne vykonáva pridaním meta hodnôt na stránku pred jej vrátením.
  • Stĺpce a typ tabuľky kombinovanej tabuľky (t. j. všetky strany spolu) sú odvodené z prvej strany údajov. getNextPageFunkcia by mala normalizovať každú stranu údajov.
  • Prvý hovor na getNextPage volanie na volanie null parameter.
  • getNextPage musí vrátiť hodnotu null, ak už neostali žiadne strany.

Telo vašej GetAllPagesByNextLink funkcie implementuje getNextPage argument funkcie pre Table.GenerateByPage . Zavolá funkciu GetPage a načíta url adresu pre ďalšiu stránku údajov z NextLink poľa meta záznamu z predchádzajúceho hovoru.

// 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
    );

Implementácia GetPage

Vaša GetPage funkcia použije web.contents na načítanie jednej stránky údajov zo služby TripPin a konverziu odpovede na tabuľku. Odovzdáva odpoveď z Web.Contents do GetNextLink funkcie extrahovať URL ďalšej stránky a nastaví ju do meta záznamu vrátenej tabuľky (stránky údajov).

Táto implementácia je mierne upravená verzia TripPin.Feed hovoru z predchádzajúcich tutoriálov.

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];

Vaša GetNextLink funkcia jednoducho skontroluje telo odpovede pre pole @odata.nextLink a vráti jeho hodnotu.

// In this implementation, 'response' will be 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");

Dať to všetko dohromady

Posledným krokom k implementácii logiky stránkovania je aktualizácia TripPin.Feed na používanie nových funkcií. Zatiaľ jednoducho voláte na GetAllPagesByNextLink , ale v nasledujúcich tutoriáloch budete pridávať nové možnosti (napríklad presadzovanie schémy a logiku parametra dotazu).

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

Ak znova spustíte rovnaký testovací dotaz z predchádzajúceho tutoriálu, mali by ste teraz vidieť čítačku stránok v akcii. Mali by ste tiež vidieť, že máte 20 riadkov v odpovedi namiesto 8.

QueryWithPaging.

Ak sa pozriete na požiadavky v fiddlerovi, mali by ste teraz vidieť samostatné požiadavky pre každú stránku údajov.

Fiddler.

Poznámka

Všimnete si duplicitné žiadosti o prvú stranu údajov zo služby, čo nie je ideálne. Dodatočná požiadavka je výsledkom správania motora M pri kontrole schémy. Tento problém zatiaľ ignorujte a vyriešte ho v ďalšom tutoriále, kde použijete schému vysťahovania.

Záver

Táto lekcia vám ukázala, ako implementovať podporu stránkovania pre rozhranie Rest API. Zatiaľ čo logika sa bude pravdepodobne líšiť medzi rozhraniami API, vzor, ktorý je tu zavedený, by mal byť opakovane použiteľný s menšími úpravami.

V ďalšej lekcii sa budete zaoberať tým, ako použiť explicitnú schému na vaše údaje, ktorá presahuje jednoduché text a number typy údajov, z ktoré získate Json.Document .

Ďalšie kroky

TripPin časť 6 - Schéma