Bagikan melalui


TripPin bagian 2 - Konektor data untuk layanan REST

Tutorial multi-bagian ini mencakup pembuatan ekstensi sumber data baru untuk Power Query. Tutorial ini dimaksudkan untuk dilakukan secara berurutan—setiap pelajaran dibangun pada konektor yang dibuat dalam pelajaran sebelumnya, secara bertahap menambahkan kemampuan baru ke konektor Anda.

Dalam pelajaran ini, Anda akan:

  • Membuat fungsi dasar yang memanggil REST API menggunakan Web.Contents
  • Pelajari cara mengatur header permintaan dan memproses respons JSON
  • Menggunakan Power BI Desktop untuk membungkus respons ke dalam format yang mudah digunakan

Pelajaran ini mengonversi konektor berbasis OData untuk layanan TripPin (dibuat dalam pelajaran sebelumnya) menjadi konektor yang menyerupai sesuatu yang akan Anda buat untuk API RESTful apa pun. OData adalah RESTful API, tetapi satu dengan serangkaian konvensi tetap. Keuntungan dari OData adalah menyediakan skema, protokol pengambilan data, dan bahasa kueri standar. Menghilangkan penggunaan OData.Feed akan mengharuskan kita untuk membangun kemampuan ini ke dalam konektor sendiri.

Rekap konektor OData

Sebelum Anda menghapus fungsi OData dari konektor Anda, mari kita lakukan tinjauan cepat tentang apa yang saat ini dilakukannya (sebagian besar di belakang layar) untuk mengambil data dari layanan.

Buka proyek ekstensi TripPin dari Bagian 1 di Visual Studio Code. Buka file Kueri dan tempelkan dalam kueri berikut ini:

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

Buka Fiddler lalu evaluasi file Power Query saat ini di Visual Studio Code.

Di Fiddler, ada tiga permintaan ke server:

Permintaan Fiddler OData.

  • /Me—URL aktual yang Anda minta.
  • /$metadata—panggilan yang secara otomatis dilakukan oleh OData.Feed fungsi untuk menentukan skema dan mengetik informasi tentang respons.
  • /Me/BestFriend—salah satu bidang yang (bersemangat) ditarik ketika Anda mencantumkan singleton /Me. Dalam hal ini panggilan menghasilkan 204 No Content status.

Evaluasi M sebagian besar malas. Dalam kebanyakan kasus, nilai data hanya diambil/ditarik saat diperlukan. Ada skenario (seperti kasus /Me/BestFriend) di mana nilai ditarik dengan bersemangat. Ini cenderung terjadi ketika informasi jenis diperlukan untuk anggota, dan mesin tidak memiliki cara lain untuk menentukan jenis daripada mengambil nilai dan memeriksanya. Membuat hal-hal malas (yaitu, menghindari tarikan yang bersemangat) adalah salah satu aspek utama untuk membuat konektor M berkinerja.

Perhatikan header permintaan yang dikirim bersama dengan permintaan dan format JSON dari respons permintaan /Me.

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

Saat kueri selesai mengevaluasi, jendela hasil PQTest akan menampilkan nilai Rekaman untuk singleton Me.

Hasil OData.

Jika Anda membandingkan bidang di jendela output dengan bidang yang dikembalikan dalam respons JSON mentah, Anda melihat ketidakcocokan. Hasil kueri memiliki bidang lain (Friends, Trips, GetFriendsTrips) yang tidak muncul di mana pun dalam respons JSON. Fungsi OData.Feed secara otomatis menambahkan bidang ini ke rekaman berdasarkan skema yang dikembalikan oleh $metadata. Ini adalah contoh yang baik tentang bagaimana konektor dapat menambah dan/atau memformat ulang respons dari layanan untuk memberikan pengalaman pengguna yang lebih baik.

Membuat konektor REST dasar

Sekarang Anda akan menambahkan fungsi baru yang diekspor ke konektor Anda yang memanggil Web.Contents.

Namun, untuk dapat membuat permintaan web yang berhasil ke layanan OData, Anda harus mengatur beberapa header OData standar. Anda akan melakukan ini dengan menentukan sekumpulan header umum sebagai variabel baru di konektor Anda:

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

Anda mengubah implementasi fungsi Anda TripPin.Feed sehingga daripada menggunakan OData.Feed, ia menggunakan Web.Contents untuk membuat permintaan web, dan mengurai hasilnya sebagai dokumen JSON.

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

Ingatlah untuk membangun konektor Anda sekarang setelah Anda membuat perubahan pada file konektor. Kemudian Anda dapat mengevaluasi file kueri (TripPin.query.pq). Hasil rekaman /Me sekarang menyerupan JSON mentah yang Anda lihat dalam permintaan Fiddler.

Jika Anda menonton Fiddler saat menjalankan fungsi baru, Anda juga akan melihat bahwa evaluasi sekarang membuat satu permintaan web, bukan tiga. Selamat—Anda telah mencapai peningkatan performa 300%! Anda sekarang telah kehilangan semua jenis dan informasi skema, tetapi belum perlu fokus pada bagian itu.

Perbarui kueri Anda untuk mengakses beberapa Entitas/Tabel TripPin, seperti:

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

Anda akan melihat bahwa jalur yang digunakan untuk mengembalikan tabel yang diformat dengan baik sekarang mengembalikan bidang "nilai" tingkat atas dengan [Daftar] yang disematkan. Anda harus melakukan beberapa transformasi pada hasilnya untuk membuatnya dapat digunakan untuk skenario konsumsi pengguna akhir.

Mencantumkan hasil.

Transformasi penulisan di Power Query

Meskipun dimungkinkan untuk menulis transformasi M Anda dengan tangan, sebagian besar orang lebih suka menggunakan Power Query untuk membentuk data mereka. Anda akan membuka ekstensi di Power BI Desktop dan menggunakannya untuk mendesain kueri untuk mengubah output menjadi format yang lebih ramah pengguna. Bangun kembali solusi Anda, salin file ekstensi baru ke direktori Koneksi or Data Kustom Anda, dan luangkan ulang Power BI Desktop.

Mulai Kueri Kosong baru, dan tempelkan yang berikut ini ke bilah rumus:

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

Pastikan untuk menyertakan tanda = .

Manipulasi output hingga terlihat seperti umpan OData asli—tabel dengan dua kolom: AirlineCode dan Name.

Maskapai yang diformat.

Kueri yang dihasilkan akan terlihat seperti ini:

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

Beri nama kueri ("Maskapai").

Buat Kueri Kosong baru. Kali ini, gunakan TripPin.Feed fungsi untuk mengakses entitas /Airports. Terapkan transformasi hingga Anda mendapatkan sesuatu yang mirip dengan berbagi yang ditunjukkan di bawah ini. Kueri yang cocok juga dapat ditemukan di bawah ini—beri nama kueri ini ("Bandara") juga.

Bandara yang diformat.

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"

Anda dapat mengulangi proses ini untuk lebih banyak jalur di bawah layanan. Setelah Anda siap, lanjutkan ke langkah berikutnya untuk membuat tabel navigasi (tiruan).

Mensimulasikan tabel navigasi

Sekarang Anda akan membangun tabel (menggunakan kode M) yang menyajikan entitas TripPin yang diformat dengan baik.

Mulai Kueri Kosong baru dan munculkan Editor Lanjutan.

Tempelkan kueri berikut:

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

Jika Anda belum mengatur pengaturan Tingkat Privasi Anda ke "Selalu abaikan Pengaturan tingkat privasi" (juga dikenal sebagai "Gabungkan Cepat") Anda akan melihat permintaan privasi.

Firewall.

Perintah privasi muncul saat Anda menggabungkan data dari beberapa sumber dan belum menentukan tingkat privasi untuk satu atau beberapa sumber. Pilih tombol Lanjutkan dan atur tingkat privasi sumber teratas ke Publik.

Privasi.

Pilih Simpan dan tabel Anda akan muncul. Meskipun ini belum menjadi tabel navigasi, tabel ini menyediakan fungsionalitas dasar yang Anda butuhkan untuk mengubahnya menjadi satu dalam pelajaran berikutnya.

FakeNav.

Pemeriksaan kombinasi data tidak terjadi saat mengakses beberapa sumber data dari dalam ekstensi. Karena semua panggilan sumber data yang dilakukan dari dalam ekstensi mewarisi konteks otorisasi yang sama, diasumsikan bahwa mereka "aman" untuk digabungkan. Ekstensi Anda akan selalu diperlakukan sebagai sumber data tunggal dalam hal aturan kombinasi data. Pengguna masih akan menerima permintaan privasi reguler saat menggabungkan sumber Anda dengan sumber M lainnya.

Jika Anda menjalankan Fiddler dan memilih tombol Pratinjau Refresh di Editor Kueri, perhatikan permintaan web terpisah untuk setiap item di tabel navigasi Anda. Ini menunjukkan bahwa evaluasi yang bersemangat terjadi, yang tidak ideal saat membangun tabel navigasi dengan banyak elemen. Pelajaran berikutnya menunjukkan cara membangun tabel navigasi yang tepat yang mendukung evaluasi malas.

Kesimpulan

Pelajaran ini menunjukkan kepada Anda cara membangun konektor sederhana untuk layanan REST. Dalam hal ini, Anda mengubah ekstensi OData yang ada menjadi ekstensi REST standar (menggunakan Web.Contents), tetapi konsep yang sama berlaku jika Anda membuat ekstensi baru dari awal.

Dalam pelajaran berikutnya, Anda akan mengambil kueri yang dibuat dalam pelajaran ini menggunakan Power BI Desktop dan mengubahnya menjadi tabel navigasi sejati dalam ekstensi.

Langkah berikutnya

TripPin Bagian 3 - Tabel Navigasi