TripPin ส่วนที่ 2 - ตัวเชื่อมต่อข้อมูลสําหรับบริการ REST

บทช่วยสอนแบบหลายส่วนนี้ครอบคลุมการสร้างส่วนขยายแหล่งข้อมูลใหม่สําหรับ Power Query บทช่วยสอนมีไว้ให้ทําตามลําดับ —บทเรียนแต่ละบทจะสร้างขึ้นบนตัวเชื่อมต่อที่สร้างขึ้นในบทเรียนที่แล้ว โดยการเพิ่มความสามารถใหม่ให้กับตัวเชื่อมต่อของคุณแบบเพิ่มหน่วย

ในบทเรียนนี้ คุณจะ:

  • สร้างฟังก์ชันพื้นฐานที่เรียกใช้ REST API โดยใช้ Web.Contents
  • เรียนรู้วิธีการตั้งค่าส่วนหัวของคําขอและประมวลผลการตอบกลับ JSON
  • ใช้ Power BI Desktop เพื่อจัดรูปการตอบกลับเป็นรูปแบบที่ใช้งานง่าย

บทเรียนนี้แปลงตัวเชื่อมต่อตาม OData สําหรับ บริการ TripPin (สร้างขึ้นใน บทเรียนก่อนหน้า) เป็นตัวเชื่อมต่อที่คล้ายกับบางสิ่งที่คุณสร้างขึ้นสําหรับ RESTful API ใด ๆ OData เป็น API RESTful แต่หนึ่งด้วยชุดแบบแผนทั่วไป ประโยชน์ของ OData คือมี Schema โพรโทคอลการเรียกข้อมูล และภาษาคิวรีมาตรฐาน การแย่งใช้งาน OData.Feed จะต้องให้เราสร้างความสามารถเหล่านี้ลงในตัวเชื่อมต่อด้วยตนเอง

การสรุปของตัวเชื่อมต่อ OData

ก่อนที่คุณจะลบฟังก์ชัน OData ออกจากตัวเชื่อมต่อของคุณ เรามาทําการทบทวนอย่างคร่าว ๆ เกี่ยวกับสิ่งที่ OData ทําในขณะนี้ (ส่วนใหญ่อยู่เบื้องหลัง) เพื่อดึงข้อมูลจากบริการ

เปิดโครงการตัวเชื่อมต่อ TripPin จาก ส่วนที่ 1 ใน Visual Studio เปิดไฟล์คิวรีและวางในคิวรีต่อไปนี้:

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

เปิด Fiddler จากนั้นเลือกปุ่ม เริ่มต้น ใน Visual Studio

ใน Fiddler คุณจะเห็นการร้องขอสามรายการไปยังเซิร์ฟเวอร์:

Fiddler OData requests.

  • /Me—URL จริงที่คุณกําลังร้องขอ
  • /$metadata—การเรียกใช้โดยอัตโนมัติโดย OData.Feed ฟังก์ชันเพื่อกําหนด schema และพิมพ์ข้อมูลเกี่ยวกับการตอบสนอง
  • /Me/BestFriend—หนึ่งในเขตข้อมูลที่ถูกดึงมา (กระตือรือร้น) เมื่อคุณแสดงรายการ /Me singleton ในกรณีนี้ การเรียกใช้จะส่งผลให้เกิด 204 No Content สถานะ

การประเมิน M ส่วนใหญ่ขี้เกียจ ในกรณีส่วนใหญ่ ค่าข้อมูลจะถูกดึง/ดึงเมื่อจําเป็นเท่านั้น มีสถานการณ์ต่าง ๆ (เช่น /Me/BestFriend) ที่ดึงค่าอย่างกระตือรือร้น ซึ่งมีแนวโน้มที่จะเกิดขึ้นเมื่อข้อมูลชนิดเป็นสิ่งจําเป็นสําหรับสมาชิก และกลไกจัดการไม่มีวิธีอื่นในการกําหนดชนิดมากกว่าที่จะดึงค่าและตรวจสอบ การทําสิ่งที่ขี้เกียจ (นั่นคือการหลีกเลี่ยงการดึงเบื้องหน้า) เป็นหนึ่งในประเด็นสําคัญที่ทําให้ตัวเชื่อมต่อ M ทํางานได้

โปรดสังเกตส่วนหัวของคําขอที่ถูกส่งพร้อมกับคําขอและรูปแบบ JSON ของการตอบสนองของคําขอ /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
}

เมื่อคิวรีเสร็จสิ้นการประเมิน หน้าต่างเอาต์พุตคิวรี M ควรแสดงค่า บันทึก สําหรับ Me singleton

OData results.

ถ้าคุณเปรียบเทียบเขตข้อมูลในหน้าต่างเอาต์พุตกับเขตข้อมูลที่ส่งกลับในการตอบสนอง JSON ดิบ คุณจะสังเกตเห็นว่าไม่ตรงกัน ผลลัพธ์ของคิวรีมีเขตข้อมูลเพิ่มเติม (Friends, , Trips, GetFriendsTrips) ที่ไม่ปรากฏที่ใดเลยในการตอบสนอง JSON ฟังก์ชัน OData.Feed จะผนวกเขตข้อมูลเหล่านี้เข้ากับระเบียนโดยยึดตาม schema ที่ส่งกลับโดย$metadata โดยอัตโนมัติ นี่คือตัวอย่างที่ดีของวิธีการที่ตัวเชื่อมต่ออาจเสริม และ/หรือจัดรูปแบบการตอบสนองจากบริการใหม่เพื่อให้ประสบการณ์ใช้งานของผู้ใช้ดียิ่งขึ้น

การสร้างตัวเชื่อมต่อ REST พื้นฐาน

ตอนนี้คุณจะเพิ่มฟังก์ชันที่ส่งออกใหม่ไปยังตัวเชื่อมต่อของคุณที่เรียกใช้ Web.Contents

เพื่อให้สามารถทําการร้องขอเว็บที่สําเร็จไปยังบริการ OData อย่างไรก็ตามคุณจะต้องตั้งค่าส่วนหัว OData มาตรฐานบางอย่าง คุณสามารถทําได้โดยการกําหนดชุดส่วนหัวทั่วไปเป็นตัวแปรใหม่ในตัวเชื่อมต่อของคุณ:

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

คุณจะเปลี่ยนการใช้งานฟังก์ชันของคุณTripPin.Feedเพื่อให้แทนที่จะใช้ OData.FeedWeb.Contents เพื่อสร้างการร้องขอเว็บ และแยกวิเคราะห์ผลลัพธ์เป็นเอกสาร JSON

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

ขณะนี้คุณสามารถทดสอบสิ่งนี้ได้ใน Visual Studio โดยใช้ไฟล์คิวรี ขณะนี้ผลลัพธ์ของระเบียน /Me มีลักษณะคล้ายกับ JSON ดิบที่คุณเห็นในคําขอ Fiddler

หากคุณดู Fiddler เมื่อเรียกใช้ฟังก์ชันใหม่ คุณจะสังเกตเห็นว่าขณะนี้การประเมินสร้างคําขอเว็บเดียวแทนที่จะเป็นสาม ขอแสดงความยินดี - คุณมีประสิทธิภาพการทํางานเพิ่มขึ้น 300%! แน่นอนว่า ตอนนี้คุณทําข้อมูลชนิดและข้อมูล Schema หายไปทั้งหมด แต่ไม่จําเป็นต้องมุ่งเน้นไปที่ส่วนนั้น

อัปเดตคิวรีของคุณเพื่อเข้าถึงเอนทิตี/ตาราง TripPin บางอย่าง เช่น:

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

คุณจะสังเกตเห็นว่าเส้นทางที่ใช้ในการส่งกลับตารางที่จัดรูปแบบอย่างดีในขณะนี้ส่งกลับเขตข้อมูล "ค่า" ระดับบนสุดที่มี [รายการ] แบบฝังตัว คุณจะต้องทําการแปลงข้อมูลบางอย่างบนผลลัพธ์เพื่อทําให้สามารถใช้งานได้สําหรับสถานการณ์ Power BI

List results.

การเขียนการแปลงใน Power Query

ในขณะที่เป็นไปได้ที่จะสร้างการแปลง M ของคุณด้วยมือ แต่คนส่วนใหญ่ต้องการใช้ Power Query ในการจัดรูปแบบข้อมูลของพวกเขา คุณจะเปิดส่วนขยายของคุณใน Power BI Desktop และใช้เพื่อออกแบบคิวรีเพื่อเปลี่ยนเอาต์พุตให้อยู่ในรูปแบบที่เป็นมิตรกับผู้ใช้มากขึ้น สร้างโซลูชันของคุณใหม่ คัดลอกไฟล์ส่วนขยายใหม่ไปยังไดเรกทอรี custom Data เชื่อมต่อ ors ของคุณ และเปิด Power BI Desktop อีกครั้ง

เริ่มคิวรี่ว่างเปล่าใหม่ และวางรายการต่อไปนี้ลงในแถบสูตร:

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

ตรวจสอบให้แน่ใจว่ามีเครื่องหมาย =

จัดการเอาต์พุตจนกว่าจะมีลักษณะเหมือนตัวดึงข้อมูล OData ต้นฉบับ ซึ่งเป็นตารางที่มีสองคอลัมน์: AirlineCode และ Name

Formatted airlines.

คิวรีที่เป็นผลลัพธ์ควรมีลักษณะดังนี้:

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

ตั้งชื่อคิวรี ("Airlines")

สร้างคิวรี่ว่างเปล่าใหม่ ในครั้งนี้ ให้ใช้ TripPin.Feed ฟังก์ชันเพื่อเข้าถึงเอนทิตี /Airports นําการแปลงไปใช้จนกว่าคุณจะได้สิ่งที่คล้ายกับการแชร์ที่แสดงด้านล่าง นอกจากนี้ยังสามารถค้นหาคิวรีที่ตรงกันได้ที่ด้านล่าง — ตั้งชื่อคิวรีนี้ ("สนามบิน") เช่นกัน

Formatted airports.

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"

คุณสามารถทําซ้ํากระบวนการนี้สําหรับเส้นทางเพิ่มเติมภายใต้บริการ เมื่อคุณพร้อมแล้ว ย้ายไปยังขั้นตอนถัดไปของการสร้างตารางนําทาง (จําลอง)

การจําลองตารางนําทาง

ในตอนนี้ คุณกําลังจะสร้างตาราง (โดยใช้รหัส M) ที่แสดงเอนทิตี TripPin ที่ได้รับการจัดรูปแบบอย่างดีของคุณ

เริ่มคิวรี่ว่างเปล่าใหม่และแสดงเครื่องมือแก้ไขขั้นสูง

วางในคิวรีต่อไปนี้:

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

ถ้าคุณไม่ได้ตั้งค่าระดับความเป็นส่วนตัวของคุณเป็น "ละเว้นการตั้งค่าระดับความเป็นส่วนตัวเสมอ" (หรือที่เรียกว่า "การรวมด่วน") คุณจะเห็นพร้อมท์ความเป็นส่วนตัว

Firewall.

พร้อมท์ความเป็นส่วนตัวปรากฏขึ้นเมื่อคุณกําลังรวมข้อมูลจากหลายแหล่งข้อมูล และยังไม่ได้ระบุระดับความเป็นส่วนตัวสําหรับแหล่งข้อมูล เลือกปุ่ม ดําเนินการต่อ และตั้งค่าระดับความเป็นส่วนตัวของแหล่งข้อมูลด้านบนเป็นสาธารณะ

Privacy.

เลือก บันทึก และตารางของคุณจะปรากฏขึ้น แม้ว่านี่จะยังไม่ใช่ตารางการนําทาง แต่ก็มีฟังก์ชันพื้นฐานที่คุณจําเป็นต้องเปลี่ยนเป็นหนึ่งในบทเรียนที่ตามมา

FakeNav.

การตรวจสอบชุดข้อมูลจะไม่เกิดขึ้นเมื่อเข้าถึงแหล่งข้อมูลหลายแหล่งจากภายในส่วนขยาย เนื่องจากการเรียกใช้แหล่งข้อมูลทั้งหมดที่เกิดขึ้นจากภายในส่วนขยายจะสืบทอดบริบทการรับรองความถูกต้องเดียวกัน จึงสันนิษฐานว่าการเรียกนั้นเป็น "ปลอดภัย" ในการรวม ส่วนขยายของคุณจะถือว่าเป็นแหล่งข้อมูลเดียวเสมอเมื่อถึงกฎการรวมข้อมูล ผู้ใช้จะยังคงได้รับพร้อมท์ความเป็นส่วนตัวปกติเมื่อรวมแหล่งข้อมูลของคุณกับแหล่งข้อมูล M อื่น ๆ

ถ้าคุณเรียกใช้ Fiddler และคลิกปุ่ม รีเฟรชตัวอย่าง ในตัวแก้ไขคิวรี คุณจะสังเกตเห็นการร้องขอเว็บแยกต่างหากสําหรับแต่ละรายการในตารางนําทางของคุณ ซึ่งแสดงว่าการประเมินผลกระหายเกิดขึ้น ซึ่งไม่เหมาะสมเมื่อสร้างตารางการนําทางที่มีองค์ประกอบจํานวนมาก บทเรียนที่ตามมาจะแสดงวิธีการสร้างตารางนําทางที่เหมาะสมที่สนับสนุนการประเมินขี้เกียจ

บทสรุป

บทเรียนนี้แสดงวิธีการสร้างตัวเชื่อมต่ออย่างง่ายสําหรับบริการ REST ในกรณีนี้ คุณได้เปลี่ยนส่วนขยาย OData ที่มีอยู่เป็นส่วนขยาย REST มาตรฐาน (โดยใช้ Web.Contents) แต่แนวคิดเดียวกันจะนําไปใช้ถ้าคุณกําลังสร้างส่วนขยายใหม่ตั้งแต่เริ่มต้น

ในบทเรียนถัดไป คุณจะได้ใช้คิวรีที่สร้างขึ้นในบทเรียนนี้โดยใช้ Power BI Desktop และเปลี่ยนคิวรีเหล่านั้นให้เป็นตารางการนําทางที่แท้จริงภายในส่วนขยาย

ขั้นตอนถัดไป

TripPin ส่วนที่ 3 - ตารางนําทาง