このマルチパート チュートリアルでは、Power Query 用の新しいデータ ソース拡張機能の作成について説明します。 このチュートリアルは順番に行う予定です。各レッスンは、前のレッスンで作成したコネクタに基づいて構築され、コネクタに新しい機能を段階的に追加します。
このレッスンでは、次の操作を行います。
- コネクタの接続ロジックを簡略化する
- ナビゲーション テーブルのエクスペリエンスを向上させる
このレッスンでは、必要な関数パラメーターを削除し、動的に生成されたナビゲーション テーブルに移動してユーザー エクスペリエンスを向上させることで、 前のレッスン で構築されたコネクタを簡略化します。
資格情報の識別方法の詳細については、「認証の処理」の「データ ソース パス」セクションを参照してください。
データ ソース パス
データ ソース関数を呼び出すと、M エンジンは、データ ソースの種類とデータ ソース パスの値に基づいて検索を実行することで、評価中に使用する資格情報を識別します。
前の レッスン では、2 つのデータ ソース関数を 1 つの Uri.Type パラメーターで共有しました。
[DataSource.Kind="TripPin"]
shared TripPin.Feed = Value.ReplaceType(TripPinImpl, type function (url as Uri.Type) as any);
[DataSource.Kind="TripPin", Publish="TripPin.Publish"]
shared TripPin.Contents = Value.ReplaceType(TripPinNavTable, type function (url as Uri.Type) as any);
いずれかの関数を使用するクエリを初めて実行すると、ドロップダウンと共に資格情報プロンプトが表示されます。 このプロンプトでは、パスと認証の種類を選択できます。
同じパラメーターを使用して同じクエリを再度実行すると、M エンジンはキャッシュされた資格情報を検索でき、資格情報プロンプトは表示されません。 基本パスが一致しなくなったように関数に url 引数を変更すると、新しいパスに対して新しい資格情報プロンプトが表示されます。
キャッシュされた資格情報は、[ M クエリ出力 ] ウィンドウの [資格情報] テーブルに表示されます。
変更の種類によっては、関数のパラメーターを変更すると、資格情報エラーが発生する可能性があります。
コネクタの簡略化
次に、データ ソース関数 (TripPin.Contents) のパラメーターを削除してコネクタを簡略化します。 また、sharedのTripPin.Feed修飾子を削除し、内部専用関数のままにしておく必要もあります。
Power Query の設計哲学の 1 つは、最初のデータ ソース ダイアログをできるだけシンプルにすることです。 可能であれば、接続ダイアログではなく、ナビゲーター レベルでユーザーに選択肢を提供する必要があります。 ユーザー指定の値をプログラムで決定できる場合は、関数パラメーターではなく、ナビゲーション テーブルの最上位レベルとして追加することを検討してください。
たとえば、リレーショナル データベースに接続するときに、サーバー名、データベース名、テーブル名が必要な場合があります。 接続先のサーバーがわかったら、資格情報が提供されたら、データベースの API を使用して、データベースの一覧と、各データベースに含まれるテーブルの一覧をフェッチできます。 この場合、最初の接続ダイアログを可能な限りシンプルにするために、サーバー名のみを必須パラメーターにする必要があります。Database と Table はナビゲーション テーブルのレベルになります。
TripPin サービスには固定 URL エンドポイントがあるため、ユーザーに値の入力を求める必要はありません。 関数から URL パラメーターを削除し、コネクタで BaseUrl 変数を定義する必要があります。
BaseUrl = "https://services.odata.org/v4/TripPinService/";
[DataSource.Kind="TripPin", Publish="TripPin.Publish"]
shared TripPin.Contents = () => TripPinNavTable(BaseUrl) as table;
TripPin.Feed関数は保持されますが、共有されなくなり、データ ソースの種類に関連付けなくなり、その宣言が簡略化されます。 この時点から、このセクション ドキュメント内でのみ内部的に使用します。
TripPin.Feed = (url as text) =>
let
source = Web.Contents(url, [ Headers = DefaultRequestHeaders ]),
json = Json.Document(source)
in
json;
TripPin.Contents() ファイルでTripPin.query.pq呼び出しを更新し、Visual Studio Code で実行すると、新しい資格情報プロンプトが表示されます。 また、1 つのデータ ソース パス値である TripPin も追加されました。
ナビゲーション テーブルの改善
最初の チュートリアルでは、組み込みの OData 関数を使用して TripPin サービスに接続しました。 これらの関数は、TripPin サービス ドキュメントに基づく見栄えの良いナビゲーション テーブルを提供し、コードを追加する必要はありません。
OData.Feed 関数は自動的にハードワークを行いました。
OData.Feed ではなく Web.Contents を使用して "荒らしている" ため、このナビゲーション テーブルを自分で再作成する必要があります。
次の変更を行います。
- ナビゲーション テーブルに表示する項目の一覧を定義する
- エンティティ固有の関数 (
GetAirlineTablesとGetAirportsTable) を使用しない
リストからのナビゲーション テーブルの生成
ナビゲーション テーブルで公開するエンティティを一覧表示し、それらにアクセスするための適切な URL を作成する必要があります。 すべてのエンティティは同じルート パスの下に存在するため、これらの URL を動的に構築できます。
この例を簡略化するために、M のテーブルとして公開される 3 つのエンティティ セット (Airlines、Airports、People) のみを公開し、レコードとして公開されるシングルトン (Me) をスキップします。 関数の追加は、後のレッスンまでスキップできます。
RootEntities = {
"Airlines",
"Airports",
"People"
};
その後、 TripPinNavTable 関数を更新して、テーブルを一度に 1 列ずつ作成します。 各エンティティの [データ] 列は、エンティティへの完全な URL で TripPin.Feed を呼び出すことによって取得されます。
TripPinNavTable = (url as text) as table =>
let
entitiesAsTable = Table.FromList(RootEntities, Splitter.SplitByNothing()),
rename = Table.RenameColumns(entitiesAsTable, {{"Column1", "Name"}}),
// Add Data as a calculated column
withData = Table.AddColumn(rename, "Data", each TripPin.Feed(Uri.Combine(url, [Name])), Uri.Type),
// Add ItemKind and ItemName as fixed text values
withItemKind = Table.AddColumn(withData, "ItemKind", each "Table", type text),
withItemName = Table.AddColumn(withItemKind, "ItemName", each "Table", type text),
// Indicate that the node should not be expandable
withIsLeaf = Table.AddColumn(withItemName, "IsLeaf", each true, type logical),
// Generate the nav table
navTable = Table.ToNavigationTable(withIsLeaf, {"Name"}, "Name", "Data", "ItemKind", "ItemName", "IsLeaf")
in
navTable;
URL パスを動的に構築するときは、フォワードスラッシュ (/) の場所が明確であることを確認してください。 Uri.Combine では、パスを結合するときに次の規則が使用されます。
-
relativeUriパラメーターが /で始まると、baseUriパラメーターのパス全体が置き換えられます。 -
relativeUriパラメーターが / で始まらない場合で、baseUriが / で終わる場合、パスが付加されます。 -
relativeUriパラメーターが /で始まらない場合、かつ /で終わらない場合、パスの最後のセグメントが置き換えられます。
次の図は、これらのルールの例を示しています。
エンティティ固有の関数を削除する
コネクタの保守を容易にするには、前のレッスンで使用したエンティティ固有の書式設定関数 (GetAirlineTables と GetAirportsTable) を削除する必要があります。 代わりに、すべてのエンティティに対して機能する方法で JSON 応答を処理するように TripPin.Feed を更新します。 具体的には、返された OData JSON ペイロードの value フィールドを取得し、レコードの一覧からテーブルに変換します。
TripPin.Feed = (url as text) =>
let
source = Web.Contents(url, [ Headers = DefaultRequestHeaders ]),
json = Json.Document(source),
// The response is a JSON record - the data we want is a list of records in the "value" field
value = json[value],
asTable = Table.FromList(value, Splitter.SplitByNothing()),
// expand all columns from the record
fields = Record.FieldNames(Table.FirstValue(asTable, [Empty = null])),
expandAll = Table.ExpandRecordColumn(asTable, "Column1", fields)
in
expandAll;
注
エンティティを処理する一般的なアプローチを使用する欠点は、エンティティの適切な書式設定と型情報が失われることです。 このチュートリアルの後のセクションでは、REST API 呼び出しにスキーマを適用する方法について説明します。
Conclusion
このチュートリアルでは、データ ソース パスの値を修正し、ナビゲーション テーブルのより柔軟な形式に移行することで、コネクタをクリーンアップして簡略化しました。 これらの手順を完了した後 (またはこのディレクトリのサンプル コードを使用)、 TripPin.Contents 関数は Power BI Desktop でナビゲーション テーブルを返します。