Teilen über


TripPin Teil 2 - Datenverbindung für einen REST-Dienst

Dieser mehrteilige Lehrgang behandelt die Erstellung einer neuen Datenquellenerweiterung für Power Query. Der Lehrgang sollte nacheinander durchgeführt werden - jede Lektion baut auf dem in den vorangegangenen Lektionen erstellten Connector auf und fügt dem Connector schrittweise neue Funktionen hinzu.

In dieser Lektion lernen Sie Folgendes:

  • Erstellen einer Basisfunktion, die eine REST-API mit Web.Contents aufruft
  • Lernen Sie, wie man Anfrage-Header setzt und eine JSON-Antwort verarbeitet
  • Verwenden Sie Power BI Desktop, um die Antworten in ein benutzerfreundliches Format umzuwandeln

In dieser Lektion wird der OData-basierte Connector für den TripPin-Dienst (erstellt in der vorangegangenen Lektion ) in einen Connector umgewandelt, der einem Connector ähnelt, den Sie für jede RESTful-API erstellen würden. OData ist eine RESTful-API, aber eine mit festen Konventionen. Der Vorteil von OData ist, dass es ein Schema, ein Datenabrufprotokoll und eine Standardabfragesprache bietet. Wenn wir OData.Feed nicht mehr verwenden, müssen wir diese Funktionen selbst in den Connector integrieren.

Rekapitulation des OData-Connectors

Bevor Sie die OData-Funktionen aus Ihrem Connector entfernen, lassen Sie uns einen kurzen Blick darauf werfen, was er derzeit (meist hinter den Kulissen) tut, um Daten aus dem Dienst abzurufen.

Öffnen Sie das TripPin-Erweiterungsprojekt aus Teil 1 in Visual Studio Code. Öffnen Sie die Abfragedatei und fügen Sie die folgende Abfrage ein:

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

Öffnen Sie Fiddler, und bewerten Sie dann die aktuelle Power Query-Datei in Visual Studio Code.

In Fiddler gibt es drei Anforderungen an den Server:

Fiddler OData-Anforderungen.

  • /Me-die eigentliche URL, die Sie anfordern.
  • /$metadata-ein von der Funktion OData.Feed automatisch durchgeführter Aufruf zur Ermittlung von Schema- und Typinformationen über die Antwort.
  • /Me/BestFriend-eines der Felder, die (eifrig) gezogen wurden, als Sie das /Me-Singleton auflisteten. In diesem Fall führte der Anruf zu einem 204 No Content-Status.

Die M-Bewertung ist meist faul. In den meisten Fällen werden Datenwerte nur dann abgefragt, wenn sie benötigt werden. Es gibt Szenarien (wie der Fall /Me/BestFriend), in denen ein Wert eifrig gezogen wird. Dies tritt in der Regel auf, wenn Typinformationen für ein Element benötigt werden und die Engine keine andere Möglichkeit hat, den Typ zu bestimmen, als den Wert abzurufen und zu untersuchen. Einer der wichtigsten Aspekte, um einen M-Connector leistungsfähig zu machen, ist es, die Dinge träge zu machen (d. h. eifrige Pulls zu vermeiden).

Beachten Sie die Kopfzeilen, die zusammen mit den Anfragen gesendet wurden, und das JSON-Format der Antwort auf die /Me-Anfrage.

{
  "@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
}

Wenn die Abfrage fertig ausgewertet ist, sollte im Fenster PQTest-Ergebnis der Wert Record für das Singleton Me angezeigt werden.

OData-Ergebnisse.

Wenn Sie die Felder im Ausgabefenster mit den Feldern vergleichen, die in der rohen JSON-Antwort zurückgegeben werden, werden Sie eine Unstimmigkeit feststellen. Das Abfrageergebnis enthält zusätzliche Felder (Friends, Trips, GetFriendsTrips), die nirgendwo in der JSON-Antwort erscheinen. Die Funktion OData.Feed hat diese Felder automatisch an den Datensatz angehängt, basierend auf dem von $metadata zurückgegebenen Schema. Dies ist ein gutes Beispiel dafür, wie ein Connector die Antwort des Dienstes ergänzen und/oder umformatieren kann, um eine bessere Benutzererfahrung zu bieten.

Erstellen eines einfachen REST-Connectors

Sie werden nun eine neue exportierte Funktion zu Ihrem Connector hinzufügen, die Web.Contentsaufruft.

Um erfolgreiche Webanfragen an den OData-Dienst stellen zu können, müssen Sie jedoch einige Standard-OData-Headersetzen. Sie tun dies, indem Sie einen gemeinsamen Satz von Kopfzeilen als neue Variable in Ihrem Connector definieren:

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

Sie werden Ihre Implementierung der Funktion TripPin.Feed so ändern, dass sie statt OData.FeedWeb.Contents verwendet, um eine Webanforderung zu stellen, und das Ergebnis als JSON-Dokument parst.

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

Denken Sie daran, Ihren Konnektor jetzt zu erstellen, da Sie Änderungen an der Konnektordatei vorgenommen haben. Anschließend können Sie die Abfragedatei (TripPin.query.pq) auswerten. Das Ergebnis des /Me-Datensatzes ähnelt nun dem rohen JSON, das Sie in der Fiddler-Anfrage gesehen haben.

Wenn Sie Fiddler bei der Ausführung der neuen Funktion beobachten, werden Sie auch feststellen, dass die Auswertung jetzt eine einzige Webanfrage statt drei stellt. Herzlichen Glückwunsch - Sie haben eine Leistungssteigerung von 300 % erreicht! Jetzt sind alle Typ- und Schemainformationen verloren gegangen, aber darauf brauchen Sie sich jetzt noch nicht zu konzentrieren.

Aktualisieren Sie Ihre Abfrage, um auf einige der TripPin-Entitäten/Tabellen zuzugreifen, z. B:

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

Sie werden feststellen, dass die Pfade, die früher schön formatierte Tabellen zurückgaben, jetzt ein "Wert"-Feld der obersten Ebene mit einer eingebetteten [Liste] zurückgeben. Sie müssen einige Transformationen an dem Ergebnis vornehmen, um es für Endverbraucherszenarios nutzbar zu machen.

Listenergebnisse.

Erstellung von Transformationen in Power Query

Es ist zwar möglich, Ihre M-Transformationen von Hand zu verfassen, aber die meisten Leute ziehen es vor, ihre Daten mit Power Query zu bearbeiten. Sie öffnen Ihre Erweiterung in Power BI Desktop und verwenden sie zum Entwerfen von Abfragen, um die Ausgabe in ein benutzerfreundlicheres Format zu bringen. Erstellen Sie Ihre Lösung neu, kopieren Sie die neue Erweiterungsdatei in Ihr Verzeichnis Custom Data Connectors und starten Sie Power BI Desktop neu.

Starten Sie eine neue leere Abfrage, und fügen Sie Folgendes in die Formelleiste ein:

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

Achten Sie darauf, dass Sie das =-Zeichen einschließen.

Manipulieren Sie die Ausgabe, bis sie wie der ursprüngliche OData-Feed aussieht - eine Tabelle mit zwei Spalten: AirlineCode und Name.

Formatierte Fluggesellschaften.

Die resultierende Abfrage sollte in etwa so aussehen:

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

Geben Sie der Abfrage einen Namen ("Airlines").

Erstellen Sie eine neue leere Abfrage. Verwenden Sie dieses Mal die TripPin.Feed-Funktion, um auf die Entität /Airports zuzugreifen. Wenden Sie so lange Transformationen an, bis Sie etwas erhalten, das dem unten gezeigten Anteil ähnelt. Die passende Abfrage finden Sie ebenfalls unten - geben Sie dieser Abfrage ebenfalls einen Namen ("Flughäfen").

Formatierte Flughäfen.

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"

Sie können diesen Vorgang für weitere Pfade im Rahmen des Dienstes wiederholen. Sobald Sie fertig sind, können Sie mit dem nächsten Schritt fortfahren und eine (Schein-)Navigationstabelle erstellen.

Simulieren einer Navigationstabelle

Jetzt werden Sie eine Tabelle erstellen (mit M-Code), die Ihre schön formatierten TripPin-Entitäten darstellt.

Starten Sie eine neue leere Abfrage und rufen Sie den erweiterten Editor auf.

Fügen Sie die folgende Abfrage ein:

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

Wenn Sie Ihre Privatsphäre-Einstellungen nicht auf "Privatsphäre-Einstellungen immer ignorieren" (auch bekannt als "Schnelles Kombinieren") eingestellt haben, sehen Sie eine Eingabeaufforderung zum Datenschutz.

Firewall.

Datenschutzaufforderungen werden angezeigt, wenn Sie Daten aus mehreren Quellen kombinieren und noch keine Datenschutzstufe für eine oder mehrere Quellen festgelegt haben. Wählen Sie die Schaltfläche Weiter und stellen Sie die Datenschutzstufe der obersten Quelle auf Öffentlichein.

Datenschutz:

Wählen Sie Speichern und Ihre Tabelle wird angezeigt. Dies ist zwar noch keine Navigationstabelle, aber sie bietet die grundlegenden Funktionen, die Sie benötigen, um sie in einer späteren Lektion in eine solche zu verwandeln.

FakeNav.

Datenkombinationsprüfungen finden nicht statt, wenn von einer Erweiterung aus auf mehrere Datenquellen zugegriffen wird. Da alle Datenquellenaufrufe, die innerhalb der Erweiterung erfolgen, denselben Berechtigungskontext erben, wird davon ausgegangen, dass sie "sicher" zu kombinieren sind. Ihre Nebenstelle wird immer als eine einzige Datenquelle behandelt, wenn es um Regeln für die Datenkombination geht. Die Benutzer würden weiterhin die üblichen Datenschutzhinweise erhalten, wenn sie Ihre Quelle mit anderen M-Quellen kombinieren.

Wenn Sie Fiddler ausführen und im Abfrage-Editor auf die Schaltfläche Refresh Preview klicken, sehen Sie separate Webanfragen für jedes Element in Ihrer Navigationstabelle. Dies zeigt an, dass eine eifrige Auswertung stattfindet, was beim Aufbau von Navigationstabellen mit vielen Elementen nicht ideal ist. In den folgenden Lektionen wird gezeigt, wie man eine richtige Navigationstabelle erstellt, die eine träge Auswertung unterstützt.

Zusammenfassung

In dieser Lektion haben Sie gelernt, wie man einen einfachen Connector für einen REST-Dienst erstellt. In diesem Fall haben Sie eine vorhandene OData-Erweiterung in eine Standard-REST-Erweiterung umgewandelt (unter Verwendung von Web.Contents), aber die gleichen Konzepte gelten auch, wenn Sie eine neue Erweiterung von Grund auf erstellen würden.

In der nächsten Lektion werden Sie die Abfragen, die Sie in dieser Lektion mit Power BI Desktop erstellt haben, in eine echte Navigationstabelle innerhalb der Erweiterung umwandeln.

Nächste Schritte

TripPin Teil 3 - Navigationstabellen