Share via


Create enhanced data connectors (preview)

[This article is prerelease documentation and is subject to change.]

When the data you want to use with your connector is structured with tables or lists, the enhanced connector protocol helps you deliver high-performance, enterprise grade connector more easily. Enhanced connectors serve as powerful knowledge source for agents and allow you to easily build canvas apps in Power Apps and compose logic using Power Automate.

Important

  • This is a preview feature.
  • Preview features aren’t meant for production use and might have restricted functionality. These features are subject to supplemental terms of use, and are available before an official release so that customers can get early access and provide feedback.

Action and enhanced connectors

Connectors created using OpenAPI (swagger) endpoints are considered action connectors. OpenAPI provides a standardized format to describe HTTP APIs of any size. It allows you to explicitly define endpoints (paths), supported HTTP methods, and request/response schemas. Each operation (a path and method combination) represents a specific callable action of the API, making it well-suited for APIs that follow RESTful principles.

For structured data sources, the fine-grained control OpenAPI provides becomes burdensome because the tabular data sources aren't usually defined by an OpenAPI endpoint. The OpenAPI definition isn't bound to metadata that describes the structured data, so it doesn't adapt to changes that add new tables, columns, or relationships to a data source. The connector generated using the static OpenAPI definition can't represent these changes until it's regenerated.

Enhanced connectors require an endpoint that provides information that describes dynamic set of tables, schemas, and capabilities. This article describes a protocol you can implement to create a ASP.NET Core Web API based on a protocol similar to OData rather than OpenAPI. This protocol is designed for tabular data and uses OData capabilities to manage filtering, sorting, paging, and relationships that OpenAPI doesn't provide.

Note

The endpoint described in this article has some similarities to OData, but doesn't implement the actual OData protocol.

Structured data

What do we mean by structured data? Data could be structured using actual database tables, but it could also use different terminology like 'site' rather than 'database' and 'list' rather than 'table'. The key point is that the data is structured into a resource hierarchy like this:

  • A dataset exposes a collection of tables
  • A table has rows and columns that contain data
  • An item represents a row of a table

Connectors using this pattern

The following are some of the enhanced connectors that use this pattern:

DB2

How it works

The enhanced connector protocol has three main parts:

  • Capabilities endpoints: Describe the datasets, tables, and columns the connector can access and what they can do.
  • Transpiler: Converts an OData style GET requests to retrieve data for the datasource. These requests use OData query options like $filter, $select, $orderby, $sort, and $top
  • CUD operation implementation: Describes how to perform Create, Update, and Delete operations on resources for the datasource

At a high level, you need to implement the following process:

  1. Create a ASP.NET Core Web API that implements the enhanced connector protocol.
  2. Deploy the ASP.NET Core Web API project to the hosting environment of your choice.
  3. Create the custom connector using the paconn command line tool.
  4. Configure authentication.
  5. Share and test the connector.

Note

The Power Fx enhanced connector sample is a Visual Studio solution published on GitHub. You can clone the repository and use the provided ASP.NET Core Web API project as a starting point for your endpoint.

Capabilities endpoints

The enhanced connector protocol depends on implementing five endpoints that describe the capabilities of your service. The following table summarizes these endpoints and includes links to the sections of this document that explain how to implement them.

Route How
GET $metadata.json/datasets Return list of datasets
GET /datasets Return dataset names
GET /datasets/{dataset}/tables Return table names
GET $metadata.json/datasets/{dataset}/tables/{tableName} Return the capabilities of a table
GET /datasets/{dataset}/tables/{tableName}/items Retrieve the table column values

ITableProvider interface

The following ITableProviderFactory and ITableProvider interfaces provide the expected methods to implement the enhanced connector protocol capabilities endpoints. Add the following code within the Services folder of your ASP.NET Core Web API project.

// Helper to get a provider for a given auth token. 
public interface ITableProviderFactory
{
    ITableProvider Get(IReadOnlyDictionary<string, string> settings);
}

/// <summary>
/// Datasource Provider. Host implements this to provide the RecordTypes for a specific source.
/// </summary>
public interface ITableProvider
{
    // Return list of datasets (logical name, display name)
    public Task<DatasetResponse.Item[]> GetDatasetsAsync(
      CancellationToken cancellationToken = default
      );

    // Provider list of the tables.
    public Task<GetTablesResponse> GetTablesAsync(
      string dataset, 
      CancellationToken cancellationToken = default);

    public Task<RecordType> GetTableAsync(
      string dataset, 
      string tableName, 
      CancellationToken cancellationToken = default);

    public Task<TableValue> GetTableValueAsync(
      string dataset, 
      string tableName, 
      CancellationToken cancellationToken = default);
}

Implement your ASP.NET Core Web API with a separation between the front-end (REST API) and the back-end (data source provider). The back-end is abstracted via the ITableProvider interface, which you can implement to connect to any tabular data source.

Classes used

In the ASP.NET Core Web API application you create, add the Microsoft.PowerFx.Connectors and Microsoft.PowerFx.Core NuGet packages so that you have access to types that are used in ITableProvider, such as RecordType and TableValue

Some other types you need aren't currently included in the PowerFx NuGet packages. Find them within the Power Fx enhanced connector sample power-fx-enhanced-connector/CdpHelpers/Protocol folder using the same Microsoft.PowerFx.Connectors namespace. See the table describing these types.

Return list of datasets

This endpoint in the service provides a lightweight, JSON‐formatted catalog of all top‐level data containers—what you might think of in SQL as running SELECT name FROM sys.databases. By fetching only the names and access URLs of each dataset, clients can dynamically discover which logical units (databases) the service exposes without hard‐coding any identifiers. This design not only drives metadata‐first UI or code‐generation workflows—letting users pick a dataset and then drill into its tables or views—but also respects authorization rules by only returning those datasets the caller is permitted to see.

Implement this route in your controller to provide data about the datasets available:

GET $metadata.json/datasets

Note

This route isn't included in the ITableProvider interface.

Return a DatasetMetadata instance that has the following properties:

Name Type Description
DatasetFormat String Describes the format of Dataset string. For Example for SQL it can be "{server},{database}"
IsDoubleEncoding Boolean Indicates whether the metadata blob is encoded twice (for example: a JSON payload wrapped as a JSON-encoded string), requiring two decoding passes to retrieve the raw metadata.
Parameters IReadOnlyCollection<MetadataParameter> See MetadataParameter
Tabular MetadataTabular See MetadataTabular

Note

In the Power Fx enhanced connector sample, CdpSampleWebApi/Controllers/CdpController.cs DatasetMetadata is renamed to DatasetMetadataResponse. This name would be consistent with names used in the ITableProvider interface if it was included.

MetadataParameter

This metadata describes how client applications should collect, validate, and encode each query parameter when calling your dataset endpoint. By setting these properties, you ensure:

  • User interfaces can render clear labels and tooltips for each parameter.
  • Required fields are enforced at design time, preventing runtime errors.
  • Input values are validated against the declared type (string, integer, boolean, and so on).
  • URL encoding is applied correctly so special characters don't break the request.

Set the DatasetMetadata.Parameters property with a MetadataParameter instance that contains these properties:

Name Type Description
Description String A human-readable explanation of what this parameter represents and how it affects the dataset request. For example: this value is server name or database name in SQL context.
Name String The exact parameter name clients must include in the query string or request body
Required String Indicates whether the client must supply this parameter. If true, omitting the parameter results in an error; if false, a default or fallback behavior might apply.
Type String The data type of the parameter value, such as string, integer, boolean, which tells clients how to validate and convert the input before issuing the request.
UrlEncoding String Specifies whether the parameter value should be URL‐encoded once (single) or twice (double).
XMsDynamicValues MetadataDynamicValues See MetadataDynamicValues
XMsSummary String A concise summary used in UI tooltips or documentation to help users understand the purpose of this parameter at a glance.

MetadataDynamicValues

This metadata tells client applications how to retrieve and render a live list of valid options for a given parameter—enabling dropdowns, pickers, or search-as-you-type experiences in your UI. By setting these properties, you ensure:

  • Clients know which endpoint or path to call to fetch the current list of values
  • The response payload is parsed correctly to extract both the underlying values and their display titles
  • Parameter inputs stay in sync with your service's available options, reducing errors and improving user experience

When setting the DatasetMetadata.Parameters collection, set the XMsDynamicValues property to a MetadataDynamicValues instance. This class has the following string properties:

Name Description
Path The relative URL or OData path clients call to fetch the list of dynamic values (For example: /datasets/{dataset name}/tables).
ValueCollection The JSON property name in the response payload that contains the array of items (For example: value or items).
ValuePath The JSON path (relative to each item) to extract the actual parameter value (For example: id or name.value).
ValueTitle The JSON path (relative to each item) to extract the user-facing display text for each option (For example: displayName or title).

MetadataTabular

This metadata tells client code how to present and access your service's tabular data. By setting these properties, you ensure that user interfaces display terminology and generate URLs correctly for your specific backend. For example, a SQL-based service would use Table/Tables, whereas a SharePoint connector would use List/Lists; and proper URL-encoding settings guarantee that resource paths are built correctly.

Set the DatasetMetadata.Tabular property with a MetadataTabular instance that contains these string properties:

Name Description
DisplayName Display name for Dataset. For example Database/WebSite.
Source It can be mru or singleton. If your service only ever has one logical data container, then /datasets effectively becomes a singleton endpoint. In a multi‐dataset scenario, you might still not want to overwhelm clients with every possible dataset at once. Instead, you track usage history and have /datasets return only the top N datasets ordered by last access time (or last modification). This way users see the Most Recently Used (mru) up front, and can later drill into a full list endpoint or enable paging if they need more.
TableDisplayName The display name of the table like datasource, like 'Table' or 'List'.
TablePluralName The plural name of the table like datasource, like 'Tables' or 'Lists'.
UrlEncoding Can be single or double.

Return dataset names

Implement this route in your controller to provide collection of names for each dataset:

GET /datasets

Implement the ITableProvider.GetDatasetsAsync method to return a DatasetResponse instance that has a value property with an array of Item instances.

Each Item has string Name and DisplayName properties.

Note

Connectors aren't required to provide multiple datasets. When there's only one dataset, the convention is to set both the Name and DisplayName properties of the single item to default.

Return table names

Implement this route in your controller to provide collection of names for tables in a dataset:

GET /datasets/{dataset}/tables

Implement the ITableProvider.GetTablesAsync method to return a GetTablesResponse instance. This class has a Value property that returns a List<RawTablePoco>.

RawTablePoco has the two string properties: Name and DisplayName.

Note

'POCO' stands for 'Plain Old CLR Objects' and is used as a way to format response data in ASP.NET Core Web API.

Return the capabilities of a table

Implement this route in your controller to return data about the capabilities of tables in a dataset:

GET $metadata.json/datasets/{dataset}/tables/{tableName}

Implement the ITableProvider.GetTableAsync method to return a RecordType then convert that value into a GetTableResponse. The RecordType.ToTableResponse method provides an example showing how. You should add the CdpHelpers/RecordTypeExtensions.cs file to your project to use it.

GetTableResponse has the following properties:

Name Type Description
capabilities CapabilitiesPoco Gets or sets the table capabilities, such as filtering and sorting support. See Describe table capabilities
name String Gets or sets the name of the table.
permissions String Gets or sets the permissions for the table (for example: "read-write").
schema TableSchemaPoco Gets or sets the schema of the table. See Describe table column capabilities

Describe table capabilities

The GetTableResponse.capabilities property describes the capabilities of a table using the CapabilitiesPoco class.

The CapabilitiesPoco class has the following properties to describe the capabilities of a table.

Name Type Description
filterFunctionSupport string[] Gets or sets the supported filter functions (for example: eq, and, or).
filterRestrictions Filter The Filter class has a boolean filterable property to describe whether or not the table supports any filtering at all. When filterable is true, the nonFilterableProperties property contains an array of table column names that aren't filterable.
isOnlyServerPagable bool Gets or sets a value indicating whether the table is only server pageable.
odataVersion int Gets or sets the OData version (for example: 3).
serverPagingOptions string[] Gets or sets the server paging options (for example: top, skiptoken).
sortRestrictions Sort The Sort class has a boolean sortable property to describe whether or not the table supports any sorting at all. When sortable is true, the unsortableProperties property contains an array of table column names that aren't sortable.

Describe table column capabilities

The GetTableResponse.schema property describes the capabilities of table columns using the TableSchemaPoco class.

Note

This section describes a set of classes that have simple and complex properties. The properties with complex type create a hierarchy that describes the capabilities of the columns for a table.

TableSchemaPoco.items
 Items.properties
  ColumnInfo.capabilities
   ColumnCapabilitiesPoco

The TableSchemaPoco class has the following properties to describe the capabilities of a table.

Name Type Description
type string Gets or sets the type of the schema (default is "array").
items Items Gets or sets the items definition, which describes the columns of the table.

The Items class has the following properties:

Name Type Description
type string Gets or sets the type of the items (default is "object").
properties Dictionary<string,ColumnInfo> Gets or sets the dictionary of column properties, keyed by column name.

The ColumnInfo class has the following properties:

Name Type Description
title string Gets or sets the title of the column.
description string Gets or sets the description of the column.
type string Gets or sets the type of the column (for example: integer, string).
sort string Gets or sets the sort capabilities for the column (for example: asc, desc).
capabilities ColumnCapabilitiesPoco Gets or sets the filter capabilities for the column.

The ColumnCapabilitiesPoco class has the following properties:

Name Type Description
filterFunctions string[] Gets or sets the supported filter functions for the column (for example: eq, and, or).

Retrieve the table column values

Implement this route in your controller to return table column values:

GET /datasets/{dataset}/tables/{tableName}/items

Implement the ITableProvider.GetTableValueAsync method to return a TableValue then convert that value into a GetItemsResponse

GetItemsResponse has only a single value property that is a List<Dictionary<string, object>> containing the keys and values for the respective table properties.

Transpiler

The ASP.NET Core Web API you create needs to allow users to specify optional OData query string parameters when this route is used:

GET /datasets/{dataset}/tables/{tableName}/items

The service needs to support the capabilities advertised for the table and the columns.

The CdpSampleWebApi/Services/ODataQueryModel.cs is a lightweight model-binding container for a subset of OData system query options. Its purpose:

  • Model binding: ASP.NET automatically populates its properties from query string parameters named $select, $filter, $top, and $orderby thanks to the [FromQuery(Name="...")] attributes. For example: /entities?$select=id,name&$top=10.

  • Raw capture only: It doesn't parse or validate OData expressions; it preserves the client-supplied text so downstream code (For example: a data layer or a relay to another API) can decide how to interpret, validate, or forward them.

  • Conditional packaging: ToStrDict() converts only the provided values (and $top only if > 0) into a dictionary, useful for:

    • Reconstructing or forwarding the same OData query options to another service.
    • Logging/auditing.
    • Building a query string programmatically.
  • Naming/casing choices: top and orderby are lowercase to mirror the OData keywords exactly (style/analyzer warnings suppressed at file top). Select and Filter use PascalCase (mixed style), but the binding still works because of the explicit Name override.

  • Scope: It intentionally omits other OData options ($skip, $expand, $count, $search, and others), keeping the surface minimal. Potential enhancements (if needed):

    • Make top nullable (int?) to distinguish between "absent" and "explicit 0".
    • Add $skip, $expand, or other query parameters as requirements grow.
    • Add validation or parsing (For example: approve fields in $select, expression parsing for $filter).
    • Normalize property naming for consistency.

In short, ODataQueryModel class is a simple pass-through carrier of selected OData query options, enabling safe, explicit, and testable access to them inside controller actions or services.

Create, update, and delete operation implementation

As you can see, the enhanced connector protocol outlines specific ways to retrieve information about the capabilities of your data sets and retrieve data. The next phase is to provide capabilities to add, change, or remove table rows.

Creating rows

Your service should use POST HTTP method with the same resource path used to retrieve records. The payload is sent with the body of the request.

POST /datasets/{dataset}/tables/{tableName}/items

Updating and deleting rows

Updating or deleting rows requires some way to identify the record you want to change or remove. This depends on the nature of your data source, but you should use the same resource paths. To change a record, use PATCH.

PATCH /datasets/{dataset}/tables/{tableName}/items/{primary key}

To delete a record, use DELETE.

DELETE /datasets/{dataset}/tables/{tableName}/items/{primary key}

Limitations

The following are areas where common tabular data capabilities aren't enabled using the tabular data connection protocol.

Relationships

It isn't currently possible to model relationships between tables.

Data types are limited

Only types supported by Swagger 2.0 will work.

Next steps

Learn about the Enhanced connector sample.