TripPin deel 2: gegevensconnector voor een REST-service

In deze meerdelige zelfstudie wordt het maken van een nieuwe gegevensbronextensie voor Power Query. De zelfstudie is bedoeld om opeenvolgend te worden uitgevoerd voor elke les die is gebaseerd op de connector die in de vorige lessen is gemaakt, en incrementeel nieuwe mogelijkheden toe te voegen — aan uw connector.

In deze les gaat u het volgende doen:

  • Een basisfunctie maken die een functie aanroept naar een REST API web.contents
  • Meer informatie over het instellen van aanvraagheaders en het verwerken van een JSON-antwoord
  • Gebruik Power BI Desktop om het antwoord om te zetten in een gebruiksvriendelijke indeling

In deze les wordt de op OData gebaseerde connector voor de TripPin-service (gemaakt in de vorige les )omgezet naar een connector die lijkt op iets dat u voor elke RESTful-API zou maken. OData is een RESTful API, maar één met een vaste set conventies. Het voordeel van OData is dat het een schema, protocol voor het ophalen van gegevens en een standaardquerytaal biedt. Als u het gebruik van OData.Feed weggehaald, moeten we deze mogelijkheden zelf in de connector inbouwen.

Samenvatting van de OData-connector

Voordat u de OData-functies uit uw connector verwijdert, gaan we kort bekijken wat het momenteel doet (meestal achter de schermen) om gegevens op te halen uit de service.

Open het Project TripPin-connector uit deel 1 in Visual Studio. Open het querybestand en plak de volgende query:

TripPin.Feed("https://services.odata.org/v4/TripPinService/Me")

Open Fiddler en selecteer vervolgens de Startknop in Visual Studio.

In Fiddler ziet u drie aanvragen naar de server:

OData-aanvragen voor Fiddler.

  • /Me—de werkelijke URL die u aanvraagt.
  • /$metadata—een aanroep die automatisch wordt gedaan door de OData.Feed functie om het schema te bepalen en informatie over het antwoord te typen.
  • /Me/BestFriend—een van de velden die (graag) is getrokken toen u de /Me-singleton vermeldde. In dit geval heeft de aanroep tot een 204 No Content status geleid.

M-evaluatie is voornamelijk lui. In de meeste gevallen worden gegevenswaarden alleen opgehaald/opgehaald wanneer ze nodig zijn. Er zijn scenario's (zoals het geval /Me/BestFriend) waarin een waarde graag wordt binnengehaald. Dit gebeurt meestal wanneer typegegevens nodig zijn voor een lid en de engine geen andere manier heeft om het type te bepalen dan de waarde op te halen en te inspecteren. Een van de belangrijkste aspecten van het laten werken met een M-connector is een van de belangrijkste aspecten van het laten werken met een M-connector.

Let op de aanvraagheaders die samen met de aanvragen zijn verzonden en de JSON-indeling van het antwoord van de /me-aanvraag.

{
  "@odata.context": "https://services.odata.org/v4/TripPinService/$metadata#Me",
  "UserName": "aprilcline",
  "FirstName": "April",
  "LastName": "Cline",
  "MiddleName": null,
  "Gender": "Female",
  "Age": null,
  "Emails": [ "April@example.com", "April@contoso.com" ],
  "FavoriteFeature": "Feature1",
  "Features": [ ],
  "AddressInfo": [
    {
      "Address": "P.O. Box 555",
      "City": {
        "Name": "Lander",
        "CountryRegion": "United States",
        "Region": "WY"
      }
    }
  ],
  "HomeAddress": null
}

Wanneer de query klaar is met evalueren, moet in het venster M Query Output de recordwaarde voor de me-singleton worden weergegeven.

OData-resultaten.

Als u de velden in het uitvoervenster vergelijkt met de velden die worden geretourneerd in het onbewerkte JSON-antwoord, zult u merken dat er geen overeenkomende velden zijn. Het queryresultaat heeft extra velden ( , , ) die nergens Friends Trips in het GetFriendsTrips JSON-antwoord worden weergegeven. De functie OData.Feed heeft deze velden automatisch toegevoegd aan de record op basis van het schema dat door de $metadata. Dit is een goed voorbeeld van hoe een connector het antwoord van de service kan verbeteren en/of opnieuw formatteren om een betere gebruikerservaring te bieden.

Een basic REST-connector maken

U voegt nu een nieuwe geëxporteerde functie toe aan uw connector die Web.Contents aanroept.

Als u geslaagde webaanvragen naar de OData-service wilt maken, moet u echter enkele standaard OData-headers instellen. U doet dit door een algemene set headers te definiëren als een nieuwe variabele in uw connector:

DefaultRequestHeaders = [
    #"Accept" = "application/json;odata.metadata=minimal",  // column name and values only
    #"OData-MaxVersion" = "4.0"                             // we only support v4
];

U wijzigt de implementatie van uw functie zodat deze in plaats van web.contents gebruikt om een webaanvraag te maken en het resultaat TripPin.Feed OData.Feed parseert als een JSON-document.

TripPinImpl = (url as text) =>
    let
        source = Web.Contents(url, [ Headers = DefaultRequestHeaders ]),
        json = Json.Document(source)
    in
        json;

U kunt dit nu testen in Visual Studio querybestand. Het resultaat van de /Me-record lijkt nu op de onbewerkte JSON die u in de Fiddler-aanvraag hebt gezien.

Als u Fiddler bekijkt bij het uitvoeren van de nieuwe functie, zult u ook merken dat de evaluatie nu één webaanvraag doet in plaats van drie. —Gefeliciteerd, u hebt een prestatieverhoging van 300% behaald. Natuurlijk bent u nu alle informatie over het type en schema kwijt, maar u hoeft zich nog niet op dat onderdeel te richten.

Werk uw query bij voor toegang tot enkele TripPin-entiteiten/-tabellen, zoals:

  • https://services.odata.org/v4/TripPinService/Airlines
  • https://services.odata.org/v4/TripPinService/Airports
  • https://services.odata.org/v4/TripPinService/Me/Trips

U ziet dat de paden die worden gebruikt om mooi opgemaakte tabellen te retourneren, nu een veld 'waarde' op het hoogste niveau retourneren met een ingesloten [Lijst]. U moet een aantal transformaties op het resultaat doen om het bruikbaar te maken voor Power BI scenario's.

Lijst met resultaten.

<a name="authoring-transformations-in-power-query">Transformaties maken in Power Query

Hoewel het zeker mogelijk is om uw M-transformaties met de hand te schrijven, geven de meeste mensen de voorkeur aan Power Query om hun gegevens vorm te geven. U opent de extensie in Power BI Desktop en gebruikt deze om query's te ontwerpen om de uitvoer om te zetten in een gebruiksvriendelijkere indeling. Bouw uw oplossing opnieuw op, kopieer het nieuwe extensiebestand naar de map Custom Data Connectors en start de Power BI Desktop.

Start een nieuwe lege query en plak het volgende in de formulebalk:

= TripPin.Feed(&quot;https://services.odata.org/v4/TripPinService/Airlines")

Zorg ervoor dat u het teken = op te nemen.

Manipuler de uitvoer totdat deze lijkt op de oorspronkelijke OData-feed — van een tabel met twee kolommen: AirlineCode en Name.

Opgemaakte luchtvaartmaatschappij.

De resulterende query ziet er als de volgende uit:

let
    Source = TripPin.Feed("https://services.odata.org/v4/TripPinService/Airlines"),
    value = Source[value],
    toTable = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    expand = Table.ExpandRecordColumn(toTable, "Column1", {"AirlineCode", "Name"}, {"AirlineCode", "Name"})
in
    expand

Geef de query een naam ('Luchtvaartmaatschappij').

Maak een nieuwe lege query. Deze keer gebruikt u de TripPin.Feed functie om toegang te krijgen tot de entiteit /Airports. Pas transformaties toe totdat u iets ziet dat lijkt op de share die hieronder wordt weergegeven. De overeenkomende query kan ook hieronder worden — gevonden. Geef deze query ook een naam ('Airports').

Opgemaakte luchthavens.

let
    Source = TripPin.Feed("https://services.odata.org/v4/TripPinService/Airports"),
    value = Source[value],
    #"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    #"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"Name", "IcaoCode", "IataCode", "Location"}, {"Name", "IcaoCode", "IataCode", "Location"}),
    #"Expanded Location" = Table.ExpandRecordColumn(#"Expanded Column1", "Location", {"Address", "Loc", "City"}, {"Address", "Loc", "City"}),
    #"Expanded City" = Table.ExpandRecordColumn(#"Expanded Location", "City", {"Name", "CountryRegion", "Region"}, {"Name.1", "CountryRegion", "Region"}),
    #"Renamed Columns" = Table.RenameColumns(#"Expanded City",{{"Name.1", "City"}}),
    #"Expanded Loc" = Table.ExpandRecordColumn(#"Renamed Columns", "Loc", {"coordinates"}, {"coordinates"}),
    #"Added Custom" = Table.AddColumn(#"Expanded Loc", "Latitude", each [coordinates]{1}),
    #"Added Custom1" = Table.AddColumn(#"Added Custom", "Longitude", each [coordinates]{0}),
    #"Removed Columns" = Table.RemoveColumns(#"Added Custom1",{"coordinates"}),
    #"Changed Type" = Table.TransformColumnTypes(#"Removed Columns",{{"Name", type text}, {"IcaoCode", type text}, {"IataCode", type text}, {"Address", type text}, {"City", type text}, {"CountryRegion", type text}, {"Region", type text}, {"Latitude", type number}, {"Longitude", type number}})
in
    #"Changed Type"

U kunt dit proces herhalen voor aanvullende paden onder de service. Wanneer u klaar bent, gaat u verder met de volgende stap van het maken van een (mock-) navigatietabel.

Een navigatietabel simuleren

U gaat nu een tabel bouwen (met behulp van M-code) die uw netjes opgemaakte TripPin-entiteiten west.

Start een nieuwe lege query en open de Geavanceerde editor.

Plak de volgende query:

let
    source = #table({"Name", "Data"}, {
        { "Airlines", Airlines },
        { "Airports", Airports }
    })
in
    source

Als u de instelling Privacyniveaus niet hebt ingesteld op Instellingen voor privacyniveau altijd negeren (ook wel 'Snel combineren' genoemd), ziet u een privacyprompt.

Firewall.

Privacyprompts worden weergegeven wanneer u gegevens uit meerdere bronnen combineert en nog geen privacyniveau hebt opgegeven voor de bron(en). Selecteer de knop Doorgaan en stel het privacyniveau van de bovenste bron in op Openbaar.

Privacy.

Selecteer Opslaan. De tabel wordt weergegeven. Hoewel dit nog geen navigatietabel is, biedt het de basisfunctionaliteit die u nodig hebt om deze in een volgende les om te zetten in een navigatietabel.

FakeNav.

Gegevenscombinatiecontroles worden niet uitgevoerd bij het openen van meerdere gegevensbronnen vanuit een extensie. Omdat alle aanroepen van gegevensbron vanuit de extensie dezelfde autorisatiecontext overnemen, wordt ervan uitgegaan dat ze 'veilig' zijn om te combineren. Uw extensie wordt altijd behandeld als één gegevensbron als het gaat om regels voor gegevenscombinaties. Gebruikers ontvangen nog steeds de normale privacyprompts wanneer ze uw bron combineren met andere M-bronnen.

Als u Fiddler uitvoert en op de knop Voorbeeld vernieuwen in de Query-editor klikt, ziet u afzonderlijke webaanvragen voor elk item in de navigatietabel. Dit geeft aan dat er een gretige evaluatie plaatsvindt, wat niet ideaal is bij het bouwen van navigatietabellen met veel elementen. Volgende lessen laten zien hoe u een juiste navigatietabel bouwt die luie evaluatie ondersteunt.

Conclusie

In deze les hebt u geleerd hoe u een eenvoudige connector voor een REST-service maakt. In dit geval hebt u een bestaande OData-extensie omgezet in een standaard REST-extensie (met behulp van Web.Contents),maar dezelfde concepten zijn van toepassing als u een nieuwe extensie maakt.

In de volgende les neemt u de query's die in deze les zijn gemaakt met behulp van Power BI Desktop en zet u deze om in een echte navigatietabel binnen de extensie.

Volgende stappen

TripPin Deel 3 - Navigatietabellen