DynamicsWebApi

repository·dev·Indexed 43 days ago

https://github.com/aleksandrrogov/dynamicswebapi

A TypeScript helper library for simplifying interactions with the Microsoft Dataverse Web API, Microsoft Power Pages, and Microsoft Dynamics 365 (CRM). Version 3.0.0 provides a high-level wrapper for CRUD operations, Fetch XML, batch requests, and the Dataverse Search API. It supports Node.js, browser environments, and Power Pages with automatic anti-forgery token handling.

Tokens
9.2K
Snippets
23
Records
42
Agent score
54%

What's inside DynamicsWebApi

  1. Main features of DynamicsWebApi

    dev

    DynamicsWebApi provides a high-level wrapper for Microsoft Dataverse Web API with the following capabilities:

    • Microsoft Dataverse Search API: Access Search (Query), Suggestion, and Autocomplete.
    • Batch Requests: Convert multiple requests into a single Batch operation.
    • Automation: Automated paging, chunked file uploading/downloading, and automatic conversion of long URLs into Batch Requests.
    • CRUD & Advanced Operations: Standard CRUD, Fetch XML, Actions, and Functions.
    • Metadata: Query and modify Table, Column, Choice (Option Set), and Relationship definitions.
    • File Handling: Upload, Download, and Delete data in File Fields.
    • Control: Support for AbortSignal and AbortController (Browser and Node.js 15+).
    • Environment Support: Node.js, Browser, and Microsoft Power Pages (with automatic anti-forgery token handling).
  2. Install and use DynamicsWebApi in Node.js

    dev

    Install the package via npm and import it using either CommonJS or ESM syntax.

    npm install dynamics-web-api --save
    // CommonJS
    const DynamicsWebApi = require("dynamics-web-api").DynamicsWebApi;
    
    // ESM
    import { DynamicsWebApi } from "dynamics-web-api";
  3. Use DynamicsWebApi in Microsoft Power Pages

    dev

    DynamicsWebApi (v2.1.0+) automatically detects if it is running on Power Pages and will automatically supply an anti-forgery token with each request. You can include it via a CDN or by uploading it as a Web File.

    <!-- Option 1: Using CDN (Recommended) -->
    <script type="text/javascript" src="https://unpkg.com/dynamics-web-api@2.3.0/dist/dynamics-web-api.min.js"></script>
    
    <!-- Option 2: Using an uploaded Web File -->
    <script type="text/javascript" src="~/dynamicsWebApi.min.js"></script>
  4. Use DynamicsWebApi in Dynamics 365 Web Resources

    dev

    To use the library within Dynamics 365, download the browser-compiled version from the v2/dist folder. Upload the script as a JavaScript Web Resource, then add it to a table form or reference it in an HTML Web Resource. Initialize the library using new DynamicsWebApi(). By default, it targets Web API v9.2 and Search API v1.0.

    // Initialize the library
    const dynamicsWebApi = new DynamicsWebApi();
    
    // Example: Calling a function
    const response = await dynamicsWebApi.callFunction("WhoAmI");
    Xrm.Navigation.openAlertDialog({ text: `Hello Dynamics 365! My id is: ${response.UserId}` });
  5. Troubleshoot Batch operation errors

    dev

    When working with batch requests, you may encounter specific errors related to the batch lifecycle. Common issues include:

    • Empty Batch: If you call executeBatch() without adding any operations via startBatch(), the library identifies the payload as empty.
    • Unstarted Batch: If you attempt to execute a batch without first calling startBatch(), the library will throw an error indicating the operation has not been started.
    • Incompatible Operations: Certain operations cannot be included within a batch request. The library provides mechanisms to detect and throw errors when an operation is used in an invalid batch context.
  6. Perform Batch Operations

    dev

    To group multiple requests into a single HTTP call, use the batching API. This improves performance and allows for atomic operations using Change Sets.

    Workflow:

    1. Call startBatch() to initialize the batch context.
    2. Queue your requests (e.g., create, update, delete) within the batch.
    3. Call executeBatch(request?) to send the batch to the server.

    Key options in BatchRequest:

    • continueOnError: If true, sets the Prefer header to odata.continue-on-error, allowing the batch to continue even if individual requests fail.
  7. Configure Batch Request Collections

    dev

    Batch operations allow grouping multiple requests into a single HTTP call.

    • BatchRequestCollection: A Record<string, InternalRequest[]> where the key is the batch identifier and the value is an array of InternalRequest objects.
    • contentId: Within an InternalRequest, use this property (specifically for batch requests) to set the Content-ID header or reference a request within a Change Set.
    • inChangeSet: A boolean indicating if the request should be part of a single atomic Change Set within the batch.
  8. Initialize DynamicsWebApi

    dev

    To use the library, create a new instance of the DynamicsWebApi class. You can optionally pass a Config object to the constructor to define connection details like serverUrl. If no config is provided, the instance will use default settings or can be initialized later using initializeInstance.

    import { DynamicsWebApi } from 'dynamics-web-api';
    
    const dynamicsWebApi = new DynamicsWebApi({
        serverUrl: 'https://contoso.api.crm.dynamics.com/'
    });
  9. Perform Batch Operations with DynamicsWebApi

    dev

    You can convert multiple requests into a single Batch operation using startBatch(), adding requests with create, update, etc., and finally executing them with executeBatch(). When using contentId in a request, you can reference that ID in subsequent requests within the same batch using the $ prefix (e.g., "$1").

    const contact = {
        firstname: "John",
        lastname: "Doe"
    };
    
    const order = {
        name: "1 year membership",
        // reference a request in a navigation property using the contentId
        "customerid_contact@odata.bind": "$1"
    };
    
    dynamicsWebApi.startBatch();
    // contentId "1" allows the order to reference this contact
    dynamicsWebApi.create({ data: contact, collection: "contacts", contentId: "1" });
    dynamicsWebApi.create({ data: order, collection: "salesorders" });
    
    const responses = await dynamicsWebApi.executeBatch();
    
    // responses contains the results of the batch operations
    const contactId = responses[0];
    const salesorderId = responses[1];
  10. Configure the DynamicsWebApi client

    dev

    The Config interface defines how the client connects to Microsoft Dataverse. Key configuration options include:

    • serverUrl: The URL to the Dataverse API server (e.g., https://contoso.api.crm.dynamics.com/). Required for Node.js applications.
    • impersonate: GUID of a Dynamics 365 systemuserid to impersonate via the MSCRMCallerID header.
    • impersonateAAD: GUID of an Azure Active Directory (AAD) object ID to impersonate via the CallerObjectId header.
    • onTokenRefresh: A callback function () => Promise<AccessToken | string | null> used to refresh security tokens.
    • includeAnnotations: Sets the Prefer header with odata.include-annotations= to provide extra info for lookups and option sets.
    • maxPageSize: Sets the odata.maxpagesize preference.
    • returnRepresentation: Sets the Prefer header to return=representation to return the created/updated entity in a single request.
    • useEntityNames: If true, uses Entity Logical Names instead of Collection Logical Names.
    • dataApi: Configuration for the Dataverse Web API (path data).
    • searchApi: Configuration for the Dataverse Search API (path search).
  11. Handle and inspect HTTP errors with handleHttpError

    dev

    The ErrorHelper.handleHttpError method is used to transform a parsed error response from the server into a structured DynamicsWebApiError. You can pass optional parameters to the method to enrich the error object with additional context from your local function call.

    // Example of how an error might be structured after handling
    // The resulting object will contain properties from both the parsedError and the parameters
    const error = ErrorHelper.handleHttpError(parsedError, { myContext: 'some-value' });
    console.log(error.status); // e.g., 404
    console.log(error.statusMessage); // e.g., 'Resource not found'
  12. Escape special characters for search and Unicode

    dev

    To ensure queries and data transfers are handled correctly, use these escaping utilities:

    • escapeSearchSpecialCharacters(value: string): Escapes characters that have special meaning in OData/Dataverse search queries (e.g., +, -, &, |, !, (, ), {, }, [, ], ^, ", ~, *, ?, :, \, /).
    • escapeUnicodeSymbols(value: string): Converts non-ASCII Unicode characters into their escaped \uXXXX format.
    import { escapeSearchSpecialCharacters, escapeUnicodeSymbols } from './helpers/Regex';
    
    const query = escapeSearchSpecialCharacters('test+value'); // 'test\+value'
    const unicode = escapeUnicodeSymbols('©'); // '\u00a9'