แชร์ผ่าน


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

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

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

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

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

สรุปของขั้วต่อ OData

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

เปิดโครงการส่วนขยาย TripPin จาก ส่วนที่ 1 ใน Visual Studio Code เปิดแฟ้มแบบสอบถาม และวางในแบบสอบถามต่อไปนี้:

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

เปิด Fiddler แล้วประเมินไฟล์ Power Query ปัจจุบันใน Visual Studio Code

ใน Fiddler มีคําขอสามรายการไปยังเซิร์ฟเวอร์:

ภาพหน้าจอของหน้าจอเอาต์พุต Fiddler ที่มีคําขอ OData สามรายการปรากฏขึ้น

  • /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
}

เมื่อคิวรีเสร็จสิ้นการประเมิน หน้าต่างผลลัพธ์ PQTest ควรแสดงค่า เรกคอร์ด สําหรับซิงเกิลตัน Me

สกรีนช็อตของผลลัพธ์ PQTest ที่แสดงค่า เรกคอร์ด สําหรับซิงเกิลตัน Me

หากคุณเปรียบเทียบฟิลด์ในหน้าต่างเอาต์พุตกับฟิลด์ที่ส่งคืนในการตอบกลับ 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;

อย่าลืมสร้างตัวเชื่อมต่อของคุณตอนนี้เมื่อคุณทําการเปลี่ยนแปลงไฟล์ตัวเชื่อมต่อ จากนั้นคุณสามารถประเมินไฟล์แบบสอบถาม (TripPin.query.pq) ผลลัพธ์ของเรคคอร์ด /Me ตอนนี้คล้ายกับ JSON ดิบที่อยู่ในคําขอ Fiddler

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

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

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

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

ภาพหน้าจอของผลลัพธ์ PQTest พร้อมฟิลด์ค่าที่มีรายการฝังตัว

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

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

เริ่มแบบสอบถามเปล่าใหม่ และวางบรรทัดต่อไปนี้ลงในแถบสูตร

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

อย่าลืมใส่เครื่องหมาย =

จัดการผลลัพธ์จนกว่าจะดูเหมือนตัวดึงข้อมูล OData ดั้งเดิม ซึ่งเป็นตารางที่มีสองคอลัมน์ ได้แก่ AirlineCode และ Name

สกรีนช็อตของตาราง Power Query ที่มีคอลัมน์ AirlineCode และ Name

แบบสอบถามที่เป็นผลลัพธ์ควรมีลักษณะดังนี้:

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

ตั้งชื่อแบบสอบถาม ("สายการบิน")

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

สกรีนช็อตของตาราง Power Query ที่มีตารางที่แปลงแล้ว

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

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

สกรีนช็อตของพร้อมท์ความเป็นส่วนตัวของ Power Query

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

สกรีนช็อตของกล่องโต้ตอบ ระดับความเป็นส่วนตัว ที่คุณตั้งค่าระดับความเป็นส่วนตัวของแหล่งข้อมูลบนสุดเป็น สาธารณะ

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

สกรีนช็อตของตารางที่มีข้อมูล TripPin

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

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

บทสรุป

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

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

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

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