Call Dataverse API from SPFx Web Part
In today's data-driven world, it is essential to have seamless integration between different platforms in order to maximize productivity and efficiency. Dataverse is a scalable data service and application platform that allows users to securely store and manage business data used by various applications.
By accessing Dataverse data directly from SharePoint, Outlook, and Teams, users can not only enhance their experience with real-time insights but also reduce the need for redundant storage and synchronization of data. This integration enables users to interact with important business information without leaving their familiar SharePoint, Outlook, or Teams environment, creating a more connected and efficient workflow.
In this post, I will provide a step-by-step guide on how to build a service that retrieves data from Dataverse and performs operations using the SharePoint Framework (SPFX). This solution can be used in SharePoint, Outlook, and Teams environments.
Prerequisites
Before deploying the SPFx solution to interact with Dataverse ensure you have the following:
- Dataverse Environment. Access to a Dataverse environment with necessary permissions to read account entity.
- Microsoft 365 tenant with appropriate licenses for Dataverse, SharePoint, Outlook, and Microsoft Teams.
- Account with the SharePoint Admin or Global Administrator role assigned to deploy the SPFx solution.
💡 For more details see Set up your Microsoft 365 tenant and Set up your SharePoint Framework development environment articles.
The SharePoint Framework (SPFx) is a powerful development tool that allows developers to create custom solutions that integrate seamlessly across different platforms, including SharePoint, Microsoft Teams, and Outlook.
📝 With SharePoint Framework, you can build responsive and mobile-friendly applications and web parts that are consistent across different environments.
Target Solution
The web part we will create must meet the following requirements:
- Execute and display the result of the [WhoAmI(https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/reference/whoami?view=dataverse-latest){target="_blank} request.
- Display list of entities (accounts).
- Support SharePoint, Outlook, and Microsoft Teams as a hosted platform.
As you can see, this is a simple web part. Let's code!
Web Part
Using the Yeoman generator for the SharePoint Framework I created a new web part solution and removed any unnecessary components, keeping only the minimum required for the purpose of this article.
💡 Source code: spfx-dataverse.
The structure of the solution is as follows:
- src/components contains a single root component and minimal styles
- src/model contains definition of the data that the web part works with
- src/services contains the service to interact with the Dataverse API
- src/webparts contains the web part
As you can see, this is a very simple web part.
Permissions
To call the Dataverse API on behalf of a user, we need to declare the required permissions. Open the config/package-solution.json file and add the webApiPermissionRequests under the solution section.
{
"solution": {
"webApiPermissionRequests": [
{
"resource": "Microsoft Dataverse",
"scope": "user_impersonation"
}
]
}
}
📝 Once the solution has been deployed to the App Catalog, the administrator needs to approve the API permissions for the SPFx solution.
Service
To work with the API, we will create a new service with native SPFx Service Scope that is designed to manage dependencies and optimize resource utilization in web parts and extensions.
Service scopes provide a way to create and manage shared services, promoting reusability and consistency across different components. By using service scopes, developers can define and register services at different levels, such as application, web part, or component, allowing for granular control over service life cycles and dependencies. This approach enhances modularity and simplifies testing and maintenance through the isolation of services and their configurations.
💡 Service Scope is a powerful tool in SPFx that contributes to the development of robust, scalable, and maintainable SharePoint solutions.
We'll create src/services/DataverseService.ts file with the following code:
For ease of reading, some parts of the code have been omitted. The full version of the code is available on GitHub: DataverseService.ts
import { ServiceKey, ServiceScope } from "@microsoft/sp-core-library";
import { jwtDecode, JwtPayload } from "jwt-decode";
// omitted
export default class DataverseService implements IDataverseService {
// Service key to consume the service
public static readonly serviceKey: ServiceKey<DataverseService> = ServiceKey.create<DataverseService>('VitalyZhukovDataverseService', DataverseService);
public constructor(serviceScope: ServiceScope) {
serviceScope.whenFinished(() => {
// Initializing token provider and http client
this._aadTokenProviderFactory = serviceScope.consume(AadTokenProviderFactory.serviceKey);
this._httpClient = serviceScope.consume(HttpClient.serviceKey);
});
}
public async whoAmI(): Promise<IWhoAmI> {
const url = `${this._instanceUrl}/api/data/v9.2/WhoAmI`;
return this.get<IWhoAmI>(url);
}
public async getEntityList(entityPluralName: string, fields: string[]): Promise<any> {
const url = `${this._instanceUrl}/api/data/v9.2/${entityPluralName}?$select=${fields.join(",")}`;
const data = await this.get<any>(url);
return data?.value || [];
}
/**
* Execute GET-requests to the Dataverse API
* @param url Endpoint address to proceed the request
* @returns Response in JSON format
*/
public async get<T>(url: string): Promise<T> {
// Getting token
const token = await this.getToken();
// Perform request
const response = await this._httpClient.get(url, AadHttpClient.configurations.v1, { headers: { Authorization: `Bearer ${token}` } });
// Cast response to JSON-object
const data = await response.json();
if (response.ok) {
return data;
}
else {
throw data;
}
}
// omitted
/**
* Retrieve token to interact with the Dataverse API
* @returns JWT
*/
private async getToken(): Promise<string | undefined> {
if (this.tokenExpired) {
// Getting instance of the AAD Token Provider
this._provider = this._provider || await this._aadTokenProviderFactory.getTokenProvider();
// Retrieve OBO Token
this._token = await this._provider.getToken(this._instanceUrl);
// Decode JWT to check expiration timestamp
this._decodedToken = jwtDecode<JwtPayload>(this._token);
}
return this._token;
}
}
Service Instance
Once registered, we can access the service instance by using the consume method of the Service Scope. This approach allows your components to efficiently and consistently access the necessary services, promoting reusability and modularity.
Open the web part code and add onInit as shown below:
For ease of reading, some parts of the code have been omitted. The full version of the code is available on GitHub: DataverseWebPart.ts
import DataverseService, { IDataverseService } from '../services/DataverseService';
export default class DataverseWebPart extends BaseClientSideWebPart<IDataverseWebPartProps> {
private _dataverseService: IDataverseService;
protected async onInit(): Promise<void> {
// Consume the service
this._dataverseService = this.context.serviceScope.consume(DataverseService.serviceKey);
// Provide Dataverse URL to the service
this._dataverseService.instanceUrl = this.properties.instanceUrl;
}
By using the Service Scope to consume services, we can better manage dependencies, improve performance, and ensure a clear separation of concerns in your SPFx solutions.
Execution Flow
There are several key steps involved in the execution process.
First, the web part uses the service that handles authentication and API calls. This service obtains an OAuth token from the native SharePoint On-Behalf-Of (OBO) token endpoint, which facilitates secure token exchange. The OBO token allows the web part to act on behalf of the user, ensuring that it can securely access and interact with the Dataverse API.
Once the token is obtained, the service uses it to authenticate with the Dataverse API, allowing the web part to access and manipulate data.
By following these steps, SPFx web parts can effectively integrate with external services, providing a robust user experience while maintaining a high level of security.
Deployment
Build and package the solution by running the gulp build and gulp package-solution commands in your development environment.
gulp bundle --ship
gulp package-solution --ship
This will generate the necessary package file in the sharepoint/solution folder.
Navigate to your SharePoint Online App Catalog site and upload the generated .sppkg file to the App Catalog.
Once uploaded, select the package and click on “Deploy” to make the web part available across your tenant.
API Access
Before using the web part, we will need to approve the requested API permissions. To do this, go to the SharePoint Admin Center and select "API access" under the "Advanced" section. Once there, you can approve the request and continue using the web part.
If the permission request is declined or not approved, we will receive an error message:
AADSTS65001: The user or administrator has not consented to use the application with ID '8c57a079-3a24-439f-8c56-bbea68b9e88a' named 'SharePoint Online Client Extensibility Web Application Principal'. Send an interactive authorization request for this user and resource.
Result
We have developed a solution that integrates with Dataverse and can be hosted on SharePoint, Teams, or Outlook.
The integration of Dataverse with SharePoint Framework (SPFx) web parts provides a solid foundation for building scalable and efficient solutions within the Microsoft ecosystem.
Summary
In this post, we have explored how to use the Dataverse API within a SharePoint Framework (SPFx) web part. This process involves setting up necessary permissions in Azure Active Directory (AD), configuring the SPFx web part, and authenticating securely to interact with the Dataverse API. Following these steps allows developers to access Dataverse data within SharePoint solutions, improving functionality and user experience.
GitHub
The source code is available on GitHub: github.com/vzhukov/spfx-samples.