Поделиться через


Часть 2 TripPin — соединитель данных для службы REST

В этом руководстве рассматривается создание нового расширения источника данных для Power Query. Это руководство предназначено для последовательного выполнения каждого урока— каждый урок, созданный на основе соединителя, созданного на предыдущих уроках, постепенно добавляя новые возможности в соединитель.

В этом уроке вы научитесь:

  • Создание базовой функции, которая вызывает REST API с помощью Web.Contents
  • Узнайте, как задать заголовки запросов и обработать ответ JSON
  • Использование Power BI Desktop для обработки ответа в понятном формате

Этот урок преобразует соединитель на основе OData для службы TripPin (созданный на предыдущем занятии) в соединитель, который напоминает то, что вы создали для любого API RESTful. OData — это API RESTful, но один с фиксированным набором соглашений. Преимущество 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 есть три запроса на сервер:

Запросы OData Fiddler.

  • /Me— фактический URL-адрес, который вы запрашиваете.
  • /$metadata— вызов, автоматически сделанный OData.Feed функцией для определения схемы и типа сведений об ответе.
  • /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 должно отобразиться значение записи для одноэлементного элемента Meton.

Результаты OData.

Если вы сравниваете поля в окне вывода с полями, возвращаемыми в необработанном ответе JSON, вы заметите несоответствие. Результат запроса содержит другие поля (Friends, Trips, ), GetFriendsTripsкоторые не отображаются в ответе JSON. Функция OData.Feed автоматически добавляет эти поля в запись на основе схемы, возвращаемой $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.Feedона использовала web.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

Вы заметите, что пути, которые использовались для возврата хорошо отформатированных таблиц, теперь возвращают поле верхнего уровня "значение" со встроенным [список]. Чтобы сделать его пригодным для сценариев потребления конечным пользователем, необходимо выполнить некоторые преобразования.

Вывод списка результатов.

Преобразование разработки в Power Query

Хотя вы можете создавать преобразования M вручную, большинство людей предпочитают использовать Power Query для формирования своих данных. Вы откроете расширение в Power BI Desktop и используете его для разработки запросов, чтобы превратить выходные данные в более понятный формат. Перестройте решение, скопируйте новый файл расширения в каталог пользовательских данных Подключение or и повторно запустите Power BI Desktop.

Запустите новый пустой запрос и вставьте следующий код в строку формул:

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

Обязательно включите знак =.

Управляйте выходными данными, пока не будет выглядеть исходный веб-канал OData — таблица с двумя столбцами: 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

Присвойте запросу имя ("Airlines").

Создайте пустой запрос. На этот раз используйте функцию TripPin.Feed для доступа к сущности /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

Если параметр "Уровни конфиденциальности" не заданы для параметра "Всегда игнорировать параметры уровня конфиденциальности" (также известный как "Быстрое объединение"), появится запрос на конфиденциальность.

Брандмауэр.

Запросы на конфиденциальность отображаются, когда вы объединяете данные из нескольких источников и еще не указали уровень конфиденциальности для одного или нескольких источников. Нажмите кнопку "Продолжить" и задайте уровень конфиденциальности верхнего источника общедоступным.

Конфиденциальность.

Выберите " Сохранить" и появится таблица. Хотя это еще не таблица навигации, она предоставляет основные функциональные возможности, которые необходимо превратить в один в последующий урок.

FakeNav.

Сочетание данных проверка не происходит при доступе к нескольким источникам данных из расширения. Так как все вызовы источника данных, сделанные из расширения, наследуют один и тот же контекст авторизации, предполагается, что они являются безопасными для объединения. Расширение всегда будет рассматриваться как один источник данных, когда речь идет о правилах сочетания данных. Пользователи по-прежнему получат регулярные запросы конфиденциальности при объединении источника с другими источниками M.

Если вы запускаете Fiddler и нажмите кнопку "Обновить предварительный просмотр" в Редактор запросов, обратите внимание на отдельные веб-запросы для каждого элемента в таблице навигации. Это означает, что происходит страстная оценка, которая не идеально подходит при создании таблиц навигации со многими элементами. Последующие уроки показывают, как создать правильную таблицу навигации, которая поддерживает отложенную оценку.

Заключение

На этом занятии показано, как создать простой соединитель для службы REST. В этом случае вы превратили существующее расширение OData в стандартное расширение REST (с помощью Web.Contents), но те же понятия применяются, если вы создаете новое расширение с нуля.

На следующем занятии вы получите запросы, созданные на этом занятии с помощью Power BI Desktop, и превратите их в истинную таблицу навигации в расширении.

Следующие шаги

Часть 3 TripPin — таблицы навигации