May 23, 2017

Web API - Retrieve records in JavaScript

It is high time to use WEB API for JavaScript calls, though no one is recommending one particular library for that. In fact, underlying argument has two sides;

1) Using a Library - can be tricky since Microsoft can change WEB API and no guarantee new version of Library will be out
2) Without a Library - Coding sequential lines will not manageable in long run

When take both in to account we decided we will have our own light library (easily updated as necessary).

In Order to do this, we found a cool tool that create JS codes for WEB API. This is simply a Dynamics Solution which needs to be deployed first as any other solution. Then you will see the button that launches the tool;


So we generated record Retrieve operation and made below small library for Retrieval of single record in general manner. (We plan to extend this to other CRUD operations).

We made same method to be used to below scenarios;

1) Retrieve record by Id
2) Retrieve record by Criteria

So this is the simple Library. I hope this is manageable than a heavily customized and heavy one.

function RetrieveEntityById(id, entityName, fieldsArry, filterStr) {
    var RetrieveStr = RetrieveStringBuilder(id, entityName, fieldsArry, filterStr);
    return RetrieveEntityByIdWebApi(RetrieveStr);
}

function IdBracketRemover(id) {
    return (id.indexOf('{')>-1) ? id.substring(1, id.length - 1) : id;
}

function RetrieveStringBuilder(id, entityName, fieldsArry, filterStr) {
    var Str;

    if (id != null)
    { Str = entityName + '(' + IdBracketRemover(id) + ')' + '?$select='; }
    else
    { Str = entityName + '?$select='; }

    for (i = 0; i < fieldsArry.length; i++)
    { Str = Str + fieldsArry[i] + ','; }
    Str = Str.substring(0, Str.length - 1);
    if (filterStr != null)
        Str = Str + '&$filter=' + filterStr;
    return Str;
}

function RetrieveEntityByIdWebApi(RetriveString) {
    var result;
    var req = new XMLHttpRequest();
    req.open("GET", Xrm.Page.context.getClientUrl() + "/api/data/v8.2/" + RetriveString, false);
    req.setRequestHeader("OData-MaxVersion", "4.0");
    req.setRequestHeader("OData-Version", "4.0");
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
    req.onreadystatechange = function () {
        if (this.readyState === 4) {
            req.onreadystatechange = null;
            if (this.status === 200) {
                result = JSON.parse(this.response);
            } else {
                Xrm.Utility.alertDialog(this.statusText);
            }
        }
    };
    req.send();
    return result;
}

Please find the ways of calling the method for two different scenarios as mentioned. Check how parameters become null in different scenarios.

// Query basded on Id
// string : "/customeraddresses(1A170E1D-91AE-4965-8631-0FB9270504D7)"
var fieldsArry = ['city', 'country'];
var Id = '{1A170E1D-91AE-4965-8631-0FB9270504D7}';
var AddressEnt = RetrieveEntityById(Id, 'customeraddresses', fieldsArry, null);
if (AddressEnt != null) {
    alert(AddressEnt["city"]);
}


// Query basded on condition (Parent ID and Prefred = true
// string : "/customeraddresses?$filter=_parentid_value eq 19139FC0-DC44-4E88-A793-924F1F90B08F 
//          and  smsmt_ispreferred eq true"
var fieldsArry = ['city', 'country'];
var ParentId = '{19139FC0-DC44-4E88-A793-924F1F90B08F}';
var filterStr = 'new_ispreferred eq true and  _parentid_value eq ' + IdBracketRemover(Id);
var AddressEnt = RetrieveEntityById(null, 'customeraddresses', fieldsArry, filterStr);
if ((AddressEnt != null) && (AddressEnt.value[0] != null)) {
    alert(AddressEnt.value[0].city);
}

For the moment, this seems to be catering the need. If I develop the other operations, I will post them. Anyway, it is the CRM Rest Builder generated this code for me, what I have done is making little changes with parameters to create correct string to be passed.

Special thanks to my colleague Biplab Singha for guiding to this approach.

Post Note;
Noticed assigning a lookup value after retrieving through this could be little tricky. Please find below code snippet of assigning lookup value (coming from entity called new_shareholders and lookup field called new_shname) to primarycontact;


var shEnt = RetrieveEntityById(null, 'new_shareholders', fieldsArry, filterStr);
if ((shEnt != null) && (shEnt.value[0] != null)) {
    var constLookup = new Array();
    constLookup[0] = new Object();
    constLookup[0].id = shEnt.value[0]['_new_shname_value'];
    constLookup[0].name = shEnt.value[0]['_new_shname_value@OData.Community.Display.V1.FormattedValue'];
    constLookup[0].entityType = shEnt.value[0]['_new_shname_value@Microsoft.Dynamics.CRM.lookuplogicalname'];
    Xrm.Page.getAttribute('primarycontact').setValue(constLookup);
}