TripPin parte 4 - Caminhos da fonte de dados

Este tutorial de várias partes aborda a criação de uma nova extensão de fonte de dados para o Power Query. O tutorial deve ser seguido sequencialmente; cada lição se baseia no conector criado nas lições anteriores, adicionando incrementalmente novos recursos a ele.

Nesta lição, você vai:

  • Simplificar a lógica de conexão para o conector
  • Melhorar a experiência da tabela de navegação

Esta lição simplifica o conector criado na lição anterior ao remover os parâmetros de função necessários e melhorar a experiência do usuário movendo-se para uma tabela de navegação gerada dinamicamente.

Para obter uma explicação detalhada de como as credenciais são identificadas, consulte a seção Caminhos da fonte de dados de Manipulação de autenticação.

Caminhos da fonte de dados

Ao invocar uma função de fonte de dados, o mecanismo M identifica as credenciais a serem usadas durante uma avaliação fazendo uma pesquisa com base nos valores Tipo de Fonte de Dados e Caminho da Fonte de Dados.

Na lição anterior, você compartilhou duas funções de fonte de dados, ambas com um único parâmetro 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);

Na primeira vez que você executar uma consulta que usa uma das funções, receberá um prompt de credencial com listas suspensas que permite selecionar um caminho e um tipo de autenticação.

Credenciais com caminhos.

Se você executar a mesma consulta novamente, com os mesmos parâmetros, o mecanismo M poderá localizar as credenciais armazenadas em cache e nenhum prompt de credencial será mostrado. Se você modificar o argumento url para sua função para que o caminho base não corresponda mais, um novo prompt de credencial será exibido para o novo caminho.

Você pode ver todas as credenciais armazenadas em cache na tabela Credenciais na janela Saída da Consulta M.

Guia Credenciais.

Dependendo do tipo de alteração, modificar os parâmetros da função provavelmente resultará em um erro de credencial.

Simplificando o conector

Agora, você simplificará seu conector ao remover os parâmetros para sua função de fonte de dados (TripPin.Contents). Você também removerá o qualificador shared para TripPin.Feed e deixará como uma função somente interna.

Uma das filosofias de design do Power Query é manter a caixa de diálogo da fonte de dados inicial o mais simples possível. Se possível, você deverá fornecer ao usuário opções no nível do Navegador, em vez da caixa de diálogo de conexão. Se um valor fornecido pelo usuário pode ser determinado programaticamente, considere adicioná-lo como o nível superior da tabela de navegação em vez de um parâmetro de função.

Por exemplo, ao se conectar a um banco de dados relacional, talvez seja necessário nomes de servidor, banco de dados e tabela. Depois de conhecer o servidor ao qual se conectar e as credenciais forem fornecidas, você poderá usar a API do banco de dados para buscar uma lista de bancos de dados e uma lista de tabelas contidas em cada banco de dados. Nesse caso, para manter a caixa de diálogo de conexão inicial o mais simples possível, apenas o nome do servidor deve ser um parâmetro necessário — Database e Table seriam níveis da tabela de navegação.

Como o serviço TripPin tem um ponto de extremidade de URL fixo, você não precisa solicitar nenhum valor ao usuário. Você removerá o parâmetro url da função e definirá uma variável BaseUrl no conector.

BaseUrl = "https://services.odata.org/v4/TripPinService/";

[DataSource.Kind="TripPin", Publish="TripPin.Publish"]
shared TripPin.Contents = () => TripPinNavTable(BaseUrl) as table;

Você manterá a função TripPin.Feed, mas não a tornará mais compartilhada, não a associará a um Tipo de Fonte de Dados e simplificará sua declaração. A partir deste ponto, você só a usará internamente neste documento de seção.

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

Se você atualizar a chamada TripPin.Contents() em seu arquivo TripPin.query.pq e executá-la no Visual Studio Code, verá um novo prompt de credencial. Observe que agora há um único valor de Caminho da Fonte de Dados — TripPin.

Credenciais sem caminhos.

Melhorando a tabela de navegação

No primeiro tutorial, você usou as funções internas OData para se conectar ao serviço TripPin. Isso deu a você uma tabela de navegação perfeita, com base no documento do serviço TripPin, sem nenhum código adicional. A função OData.Feed fez automaticamente o trabalho difícil para você. Como você está "preparando-a" com Web.Contents em vez de OData.Feed, será necessário recriar essa tabela de navegação por conta própria.

Navegador OData.

Você também pode fazer as seguintes alterações:

  1. Definir uma lista de itens a serem mostrados na tabela de navegação
  2. Eliminar as funções específicas da entidade (GetAirlineTables e GetAirportsTable)

Gerando uma tabela de navegação a partir de uma lista

Você listará as entidades que deseja expor na tabela de navegação e criará a URL apropriada para acessá-las. Como todas as entidades estão no mesmo caminho raiz, você poderá criar essas URLs dinamicamente.

Para simplificar o exemplo, você só vai expor os três conjuntos de entidades (Companhias Aéreas, Aeroportos, Pessoas), que seriam expostos como Tabelas em M, e ignorar o singleton (Me) que seria exposto como um Registro. Você ignorará a adição das funções até uma lição posterior.

RootEntities = {
    "Airlines",
    "Airports",
    "People"
};

Em seguida, atualize sua função TripPinNavTable para criar uma coluna de cada vez na tabela. A coluna [Dados] de cada entidade é recuperada chamando TripPin.Feed com a URL completa para a entidade.

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;

Ao criar caminhos de URL dinamicamente, verifique onde estão as barras (/)! Observe que Uri.Combine usa as seguintes regras ao combinar caminhos:

  • Quando o parâmetro relativeUri começar com um /, ele substituirá todo o caminho do parâmetro baseUri
  • Se o parâmetro relativeUri não começar com um / e baseUri terminar com um /, o caminho será acrescentado
  • Se o parâmetro relativeUri não começar com um / e baseUri não terminar com um /, o último segmento do caminho será substituído

A imagem a seguir mostra exemplos disso:

Exemplo de Uri.Combine.

Removendo as funções específicas da entidade

Para facilitar a manutenção do conector, você removerá as funções de formatação específicas da entidade usadas na lição anterior – GetAirlineTables e GetAirportsTable. Em vez disso, você atualizará TripPin.Feed para processar a resposta JSON de uma maneira que funcionará para todas as suas entidades. Especificamente, você usa o campo value do conteúdo JSON do OData retornado e o converte de uma lista de registros em uma tabela.

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;

Observação

Uma desvantagem de usar uma abordagem genérica para processar suas entidades é que você perde a boa formatação e as informações de tipo para as entidades. Uma seção posterior neste tutorial mostra como impor o esquema nas chamadas à API REST.

Conclusão

Neste tutorial, você limpou e simplificou o conector corrigindo o valor do Caminho da Fonte de Dados e passando para um formato mais flexível para sua tabela de navegação. Depois de concluir essas etapas (ou usar o código de exemplo neste diretório), a função TripPin.Contents retorna uma tabela de navegação no Power BI Desktop.

Navegador.

Próximas etapas

TripPin parte 5 – Paginação