Comprehensive JavaScript framework for Microsoft Dynamics CRM/365 WebAPI integration with promise-based CRUD operations, batch processing, and 200+ pre-implemented actions
Client configuration, URL building, header management, and utility functions for customizing WebApiClient behavior and accessing low-level functionality.
Global configuration properties for customizing WebApiClient behavior.
import * as bluebird from "bluebird";
/** CRM Web API version to use (default: "8.0") */
let ApiVersion: string;
/** Automatically retrieve all pages for multi-page results (default: false) */
let ReturnAllPages: boolean;
/** Format errors in readable format vs raw JSON (default: true) */
let PrettifyErrors: boolean;
/** Send requests asynchronously vs synchronously (default: true) */
let Async: boolean;
/** Base URL for single page application scenarios */
let ClientUrl: string;
/** Authentication token for single page application scenarios */
let Token: string;
/** WebApiClient library version */
let Version: string;
/** Bluebird promise implementation used internally */
let Promise: typeof bluebird;Configuration Examples:
// Basic configuration
WebApiClient.ApiVersion = "9.0";
WebApiClient.ReturnAllPages = true;
WebApiClient.PrettifyErrors = false;
WebApiClient.Async = true;
// Single Page Application configuration
WebApiClient.ClientUrl = "https://orgname.crm.dynamics.com/api/data/v9.0/";
WebApiClient.Token = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJS...";
WebApiClient.ApiVersion = "9.0";
// Power Pages configuration
WebApiClient.ClientUrl = "/_api/";
// Access Bluebird promise library
const customPromise = WebApiClient.Promise.resolve(data);Functions for building URLs and working with entity names.
/**
* Get the base Web API URL for the current CRM context
* @returns Base URL string for Web API endpoints
*/
function GetApiUrl(): string;
/**
* Get the entity set name for an entity logical name
* @param entity - Entity logical name (e.g., "account", "contact")
* @returns Entity set name for Web API URLs (e.g., "accounts", "contacts")
*/
function GetSetName(entity: string): string;Usage Examples:
// Get API base URL
const apiUrl = WebApiClient.GetApiUrl();
console.log(apiUrl); // https://orgname.crm.dynamics.com/api/data/v9.0/
// Get entity set names
const accountSetName = WebApiClient.GetSetName("account");
console.log(accountSetName); // "accounts"
const contactSetName = WebApiClient.GetSetName("contact");
console.log(contactSetName); // "contacts"
const userSetName = WebApiClient.GetSetName("systemuser");
console.log(userSetName); // "systemusers"
// Build custom URLs
const customUrl = WebApiClient.GetApiUrl() + WebApiClient.GetSetName("account") +
"?$select=name,revenue&$filter=statecode eq 0";Headers are managed per-request using the headers parameter in request objects.
interface Header {
/** Header name */
key: string;
/** Header value */
value: string;
}Usage Examples:
// Add custom headers to individual requests
await WebApiClient.Create({
entityName: "account",
entity: { name: "Test Account" },
headers: [
{ key: "Prefer", value: "return=representation" },
{ key: "CustomHeader", value: "CustomValue" }
]
});
// Authentication header for external access
await WebApiClient.Retrieve({
entityName: "account",
entityId: accountId,
headers: [
{ key: "Authorization", value: "Bearer " + accessToken }
]
});
// CSRF token for Power Pages
await WebApiClient.Update({
entityName: "account",
entityId: accountId,
entity: { name: "Updated Name" },
headers: [
{ key: "__RequestVerificationToken", value: csrfToken }
]
});Direct HTTP request function for custom operations not covered by other methods.
/**
* Send a raw HTTP request to the Web API
* @param method - HTTP method (GET, POST, PATCH, DELETE, etc.)
* @param url - Full URL for the request
* @param payload - Request payload object
* @param parameters - Additional request parameters
* @returns Promise resolving to response data
*/
function SendRequest(
method: string,
url: string,
payload: object,
parameters?: BaseParameters
): Promise<any> | any | BatchRequest;Usage Examples:
// Custom action execution
const actionUrl = WebApiClient.GetApiUrl() + "WinOpportunity";
const result = await WebApiClient.SendRequest("POST", actionUrl, {
Status: 3,
OpportunityClose: {
subject: "Won the deal!",
actualrevenue: 100000,
"opportunityid@odata.bind": "/opportunities(" + opportunityId + ")"
}
});
// Custom query with complex URL
const complexUrl = WebApiClient.GetApiUrl() +
WebApiClient.GetSetName("account") +
"?$select=name,revenue&$expand=contact_customer_accounts($select=fullname,emailaddress1)";
const complexResults = await WebApiClient.SendRequest("GET", complexUrl, null);
// Custom entity operation
const customEntityUrl = WebApiClient.GetApiUrl() +
WebApiClient.GetSetName("new_customentity") +
"(" + entityId + ")/Microsoft.Dynamics.CRM.new_CustomAction";
const customResult = await WebApiClient.SendRequest("POST", customEntityUrl, {
InputParameter: "value"
}, {
headers: [{ key: "Prefer", value: "return=representation" }]
});Collection-valued navigation properties can be expanded using the $expand query parameter in retrieve operations.
Usage Example:
// Retrieve records with collection expansion
const accountsWithContacts = await WebApiClient.Retrieve({
entityName: "account",
queryParams: "?$select=name&$expand=contact_customer_accounts($select=fullname,emailaddress1)"
});
console.log("Accounts with expanded contacts:", accountsWithContacts.value);
// Handle paginated expanded results
for (const account of accountsWithContacts.value) {
if (account["contact_customer_accounts@odata.nextLink"]) {
// Additional requests needed for remaining pages
console.log("More contacts available at:", account["contact_customer_accounts@odata.nextLink"]);
}
}Access to the Bluebird promise library used internally for advanced promise operations.
/** Bluebird promise implementation with additional methods */
let Promise: typeof bluebird;Usage Examples:
// Use Promise.all for concurrent operations
const promises = [
WebApiClient.Retrieve({ entityName: "account", entityId: account1Id }),
WebApiClient.Retrieve({ entityName: "account", entityId: account2Id }),
WebApiClient.Retrieve({ entityName: "account", entityId: account3Id })
];
const allAccounts = await WebApiClient.Promise.all(promises);
// Use Promise.map for processing arrays
const accountIds = ["id1", "id2", "id3", "id4", "id5"];
const accountDetails = await WebApiClient.Promise.map(accountIds, async (id) => {
return WebApiClient.Retrieve({
entityName: "account",
entityId: id,
queryParams: "?$select=name,revenue"
});
}, { concurrency: 3 }); // Process 3 at a time
// Use additional Bluebird methods
const timeoutResult = await WebApiClient.Retrieve({
entityName: "account",
queryParams: "?$select=name"
})
.timeout(5000) // 5 second timeout
.catch(WebApiClient.Promise.TimeoutError, (error) => {
console.log("Request timed out");
return { value: [] }; // Return empty result
});When running within CRM forms or web resources, the client automatically detects the context:
// No additional configuration needed - automatic context detection
const currentUser = await WebApiClient.Execute(WebApiClient.Requests.WhoAmIRequest);// Configure for Power Pages
WebApiClient.ClientUrl = "/_api/";
// Add CSRF token for updates (get from shell.getTokenDeferred())
const csrfToken = await shell.getTokenDeferred();
WebApiClient.AppendToDefaultHeaders({
key: "__RequestVerificationToken",
value: csrfToken
});// Configure for external SPA
WebApiClient.Configure({
ClientUrl: "https://orgname.crm.dynamics.com/api/data/v9.0/",
Token: "Bearer " + oauthToken,
ApiVersion: "9.0"
});
// Or using header
WebApiClient.ClientUrl = "https://orgname.crm.dynamics.com/api/data/v9.0/";
WebApiClient.AppendToDefaultHeaders({
key: "Authorization",
value: "Bearer " + oauthToken
});For entities with non-standard naming:
// Use overriddenSetName for unusual entity set names
await WebApiClient.Create({
overriddenSetName: "contactleadscollection", // Instead of auto-generated name
entity: { name: "Custom Entity" }
});// Global synchronous mode
WebApiClient.Async = false;
// Per-request synchronous mode
const syncResult = WebApiClient.Retrieve({
entityName: "account",
entityId: accountId,
async: false
});// Raw JSON errors instead of formatted messages
WebApiClient.PrettifyErrors = false;
try {
await WebApiClient.Create({
entityName: "account",
entity: { invalid_field: "value" }
});
} catch (error) {
// With PrettifyErrors = false, error contains full JSON response
const errorJson = JSON.parse(error);
console.log("Error code:", errorJson.error.code);
console.log("Error message:", errorJson.error.message);
}// Set specific API version
WebApiClient.ApiVersion = "9.2";
// Per-request API version override
await WebApiClient.Create({
entityName: "account",
entity: { name: "Test" },
apiVersion: "8.2"
});Install with Tessl CLI
npx tessl i tessl/npm-xrm-webapi-client