CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-xrm-webapi-client

Comprehensive JavaScript framework for Microsoft Dynamics CRM/365 WebAPI integration with promise-based CRUD operations, batch processing, and 200+ pre-implemented actions

Overview
Eval results
Files

configuration-utilities.mddocs/

Configuration and Utilities

Client configuration, URL building, header management, and utility functions for customizing WebApiClient behavior and accessing low-level functionality.

Capabilities

Client Configuration

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);

URL and Entity Utilities

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";

Header Management

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 }
    ]
});

Low-Level Request Function

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" }]
});

Navigation Property Expansion

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"]);
    }
}

Promise Integration

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
});

Environment-Specific Configuration

CRM Forms and Web Resources

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);

Power Pages (PowerApps Portals)

// 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
});

Single Page Applications

// 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
});

Advanced Configuration

Custom Entity Set Names

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" }
});

Synchronous Operations

// Global synchronous mode
WebApiClient.Async = false;

// Per-request synchronous mode
const syncResult = WebApiClient.Retrieve({
    entityName: "account",
    entityId: accountId,
    async: false
});

Error Handling Configuration

// 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);
}

API Version Management

// 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

docs

batch-processing.md

configuration-utilities.md

crm-actions-functions.md

crud-operations.md

entity-associations.md

index.md

tile.json