Efficient data management is essential for businesses and organizations in today’s data-driven world. Microsoft Dataverse is a powerful cloud-based service that provides a unified and scalable platform for data storage, management, and integration. Dataverse Web API serves as a robust interface for interacting with Dataverse, allowing developers to create, read, update, and delete data programmatically. In this blog, we will explore the Dataverse Web API, delve into its endpoint examples, discuss relationships between entities and lookups, discuss client-side integrations and real life use cases and provide relevant references. We will also explore an useful developer tool, Dataverse REST Builder which is used to to create and execute requests against the Dataverse Web API.
Understanding the Dataverse Web API
The Dataverse Web API follows the principles of REST (Representational State Transfer), making it accessible over HTTP and adhering to standard HTTP methods such as GET, POST, PATCH and DELETE. The API implements the OData (Open Data Protocol), version 4.0, an OASIS standard for building and consuming RESTful APIs over rich data sources. It supports both JSON and XML formats for data representation. The API provides a comprehensive set of endpoints that enable CRUD operations on entities and other essential functionalities.
Since the API is built on open standards, there is no official assembly/library for a specific developer experience. Here comes the Dataverse REST Builder.
It supports both cloud and on-premise versions. The on-premise one comes as an extension of XrmToolBox and the cloud version is released as a Managed Solution under Microsoft Dynamics365 Sandbox environment. Developers can perform all types of actions with Dataverse Web API including filtering, ordering, specific field selection, entity relationship, lookup references etc.
API Endpoint Examples
Retrieve single record
In the configuration section of Dataverse REST Builder, developers can choose the request type, request table, columns and other options as well.
fetch(Xrm.Utility.getGlobalContext().getClientUrl() + "/api/data/v9.2/contacts(f5bf2017-e2fd-ed11-8f6e-0022489d8fcc)?$select=annualincome,fullname,jobtitle", {
method: "GET",
headers: {
"OData-MaxVersion": "4.0",
"OData-Version": "4.0",
"Content-Type": "application/json; charset=utf-8",
"Accept": "application/json",
"Prefer": "odata.include-annotations=*"
}
}).then(
function success(response) {
return response.json().then((json) => { if (response.ok) { return [response, json]; } else { throw json.error; } });
}
).then(function (responseObjects) {
var response = responseObjects[0];
var responseBody = responseObjects[1];
var result = responseBody;
}).catch(function (error) {
console.log(error.message);
});
Response
This endpoint retrieves the contact record (fullname, jobtitle, annualincome) with the specified GUID (Globally Unique Identifier).
Retrieve multiple records
fetch(Xrm.Utility.getGlobalContext().getClientUrl() + "/api/data/v9.2/accounts?$expand=account_chats($select=activityid,statecode,activitytypecode)&$filter=contains(emailaddress1,'vivacomsolutions.com')&$orderby=accountid asc", {
method: "GET",
headers: {
"OData-MaxVersion": "4.0",
"OData-Version": "4.0",
"Content-Type": "application/json; charset=utf-8",
"Accept": "application/json",
"Prefer": "odata.include-annotations=*"
}
}).then(
function success(response) {
return response.json().then((json) => { if (response.ok) { return [response, json]; } else { throw json.error; } });
}
).then(function (responseObjects) {
var response = responseObjects[0];
var responseBody = responseObjects[1];
var results = responseBody;
}
}).catch(function (error) {
console.log(error.message);
});
This endpoint retrieves account records where emailaddress1 contains ‘vivacomsolutions.com’ and joins another table “account_chats”.
Create a record
var record = {};
record.accountid = "f5bf2017-e2fd-ed11-8f6e-0022489d8fcc"; // Guid
record.name = "Vivasoft Limited"; // Text
record.emailaddress1 = "contact@vivasoftltd.com"; // Text
record.address1_telephone2 = "+880 1713428432"; // Text
fetch(Xrm.Utility.getGlobalContext().getClientUrl() + "/api/data/v9.2/accounts", {
method: "POST",
headers: {
"OData-MaxVersion": "4.0",
"OData-Version": "4.0",
"Content-Type": "application/json; charset=utf-8",
"Accept": "application/json",
"Prefer": "odata.include-annotations=*"
},
body: JSON.stringify(record)
}).then(
function success(response) {
if (response.ok) {
var uri = response.headers.get("OData-EntityId");
var regExp = /\(([^)]+)\)/;
var matches = regExp.exec(uri);
var newId = matches[1];
console.log(newId);
} else {
return response.json().then((json) => { throw json.error; });
}
}
).catch(function (error) {
console.log(error.message);
});
This endpoint creates a new account record with the provided data.
Update a record
var record = {};
record.emailaddress1 = "contact@vivasoftltd.com"; // Text
fetch(Xrm.Utility.getGlobalContext().getClientUrl() + "/api/data/v9.2/accounts(f5bf2017-e2fd-ed11-8f6e-0022489d8fcc)", {
method: "PATCH",
headers: {
"OData-MaxVersion": "4.0",
"OData-Version": "4.0",
"Content-Type": "application/json; charset=utf-8",
"Accept": "application/json",
"Prefer": "odata.include-annotations=*"
},
body: JSON.stringify(record)
}).then(
function success(response) {
if (response.ok) {
console.log("Record updated");
} else {
return response.json().then((json) => { throw json.error; });
}
}
).catch(function (error) {
console.log(error.message);
});
This endpoint updates the account record with the specified GUID by modifying the emailaddress1 field.
Delete a record
fetch(Xrm.Utility.getGlobalContext().getClientUrl() + "/api/data/v9.2/accounts(f5bf2017-e2fd-ed11-8f6e-0022489d8fcc)", {
method: "DELETE",
headers: {
"OData-MaxVersion": "4.0",
"OData-Version": "4.0",
"Content-Type": "application/json; charset=utf-8",
"Accept": "application/json"
}
}).then(
function success(response) {
if (response.ok) {
console.log("Record deleted");
} else {
return response.json().then((json) => { throw json.error; });
}
}
).catch(function (error) {
console.log(error.message);
});
This endpoint deletes the account record with the specified GUID.
Integrations with Dataverse Web API
The Dataverse Web API can be integrated into various applications and systems to extend its capabilities. Here are some examples of integrations:
- Custom Web Applications: Developers can leverage the Dataverse Web API to build custom web applications that interact with Dataverse data. For instance, a customer relationship management (CRM) system can use the API to retrieve and update customer records stored in Dataverse.
- Power Automate Flow: Power Automate flow allows users to automate workflows across different applications and services. By integrating the Dataverse Web API, users can automate data operations, such as creating records in Dataverse when a specific event occurs in another application.
- Power Apps: Dataverse allows data to be integrated from multiple sources into a single store, which can then be used in Power Apps too by using its Web API.
Use Case
In this section, we’ll discuss a real-life use case of Dataverse Web API integrated with Dynamics365 Sales module.
Let’s consider a scenario where you have a bakery business. You have several sales managers, each manager has a couple of part-time sales representatives whose main responsibility is to visit restaurants, fast food shops etc. to increase sales on a daily/weekly/monthly basis. Since these sales reps work as part-time employees, it’s challenging to keep track of their working hours/time offs. So, you are feeling the need of a CRM scheduling tool so that your managers can keep track of their sales reps’ activities:
- Working hours
- Time offs
- Visits to different restaurants
As we already know that Dataverse Web API can be integrated with Dynamics365 and using the combination we can build a scheduling tool which is basically a custom web app. In this example, we have used Angular to build the custom user interfaces but you can choose other Javascript frameworks such as React, Vue etc. as well.
In Dataverse, we have different tables/entities where data is stored. In this article, we will use total 4 tables/entities:
- Contact(s): It’s a default entity provided by Dataverse. All the sales reps data will be stored here.
- Account(s): It’s also a default entity provided by Dataverse where we’ll store data of all the restaurants/fast food shops’ that sales reps will visit.
- Availability(s): It’s a custom entity which will store resources’ availability/unavailability.
- Visit(s): It’s a custom entity which will be used to store all the visit details.
We will divide our scheduling tool into two major modules:
1. Resource Availability/Unavailability:
In the given scenario, since the sales reps work on a part-time basis, it’s vital to keep track of their availability/unavailability meaning when they are working/when they are not. Using our scheduling tool, a sales rep can register his/her working hours/time offs on a daily/weekly/monthly basis.
After putting all the necessary data, our tool will create a record in the Availability entity against that particular resource using Dataverse Web API.
var dataToSave = {
start: new Date("2023-06-01T09:00:00+06:00"),
end: new Date("2023-06-30T14:00:00+06:00"),
repeatoccurrence: 1,
repeatpattern: RepeatPattern.Monthly,
dayofmonth: [1, 3, 4],
name: "John's Working Hours for the Month of June"
};
let httpHeaders = new HttpHeaders({
Prefer: ["return=representation", 'odata.include-annotations="*"'],
});
let options = {
headers: httpHeaders,
};
const url = this.getUrl("post", "new_Availability", "");
return this.httpClient.post(url, dataToSave, options);
Managers can view their resources’ availability in the resource calendar view.
2. Visits to different restaurants:
To schedule the visits, a sales representative or his/her manager can register them through our tool. These visits will be populated based on resource availability.
Here, we are considering the restaurants as customers which will be fetched from the Account(s) entity.
var url = `accounts?$select=name,emailaddress1,telephone1,address1_composite&$filter=`;
if (top != undefined) url += `&$top=${top}`;
var finalUrl = this.getUrl("get", url, "");
return this.httpClient.get(finalUrl, {
headers: {
Prefer: 'odata.include-annotations="*"',
},
});
After fulfilling the necessary fields, users can schedule a visit in a particular restaurant within his working hour. A record will be created in the Visit(s) entity against a specific account(customer) and contact(sales representative).
Security
To use Dataverse Web API services with JavaScript within HTML web resources, form scripts, or ribbon commands, developers don’t need to include any code for authentication. Because the application will be deployed under a specific Sandbox environment which will authenticate users using Microsoft Azure AD authentication.