Web API Basic Operations Sample (Client-side JavaScript)
This sample demonstrates how to perform basic CRUD (create, retrieve, update, and delete) and association and dissociation operations on tables rows (entity records) using client-side JavaScript.
Note
This sample implements the operations detailed in the Web API Basic Operations Sample and uses the common JavaScript constructs described in Web API Samples (Client-side JavaScript)
Prerequisites
To run this sample, the following is required:
- Access to Microsoft Dataverse environment.
- A user account with privileges to import solutions and perform CRUD operations, typically a system administrator or system customizer security role.
Run this sample
To run this sample, download the solution package from here and extract the contents. Locate the WebAPIBasicOperations_1_0_0_1_managed.zip
solution and import it into your Dataverse environment and run the sample. For instructions on how to import the sample solution, see Web API Samples (Client-side JavaScript).
Code sample
This sample includes two web resources:
WebAPIBasicOperations.html
The WebAPIBasicOperations.html web resource provides the context in which the JavaScript code will run.
<html>
<head>
<title>Microsoft CRM Web API Basic Operations Example</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<script
src="../ClientGlobalContext.js.aspx"
type="text/javascript"
></script>
<script src="scripts/es6promise.js" type="text/javascript"></script>
<script
src="scripts/WebAPIBasicOperations.js"
type="text/javascript"
></script>
<style type="text/css">
body {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}
#preferences {
border: inset;
padding: 10px 10px;
}
#output_area {
border: inset;
background-color: gainsboro;
padding: 10px 10px;
}
</style>
</head>
<body>
<h1>Microsoft CRM Web API Basic Operations Example</h1>
<p>
This page demonstrates the CRM Web API's basic operations using
JavaScript.
</p>
<h2>Instructions</h2>
<p>
Choose your preferences and run the JavaScript code. Use your browser's
developer tools to view the output written to the console (e.g.: in IE 11
or Microsoft Edge, press F12 to load the Developer Tools).
</p>
<p>
Remove sample data (Choose whether you want to delete sample data created
during this execution):
<br />
<input name="removesampledata" type="radio" value="yes" checked />
Yes
<input name="removesampledata" type="radio" value="no" />
No
</p>
<input
type="button"
name="start_sample"
value="Start Sample"
onclick="Sdk.startSample()"
/>
</body>
</html>
WebAPIBasicOperations.js
The WebAPIBasicOperations.js web resource is the JavaScript library that defines the operations this sample performs.
"use strict";
var Sdk = window.Sdk || {};
/**
* @function getClientUrl
* @description Get the client URL.
* @returns {string} The client URL.
*/
Sdk.getClientUrl = function () {
var context;
// GetGlobalContext defined by including reference to
// ClientGlobalContext.js.aspx in the HTML page.
if (typeof GetGlobalContext != "undefined") {
context = GetGlobalContext();
} else {
if (typeof Xrm != "undefined") {
// Xrm.Page.context defined within the Xrm.Page object model for form scripts.
context = Xrm.Page.context;
} else {
throw new Error("Context is not available.");
}
}
return context.getClientUrl();
};
/**
* An object instantiated to manage detecting the
* Web API version in conjunction with the
* Sdk.retrieveVersion function
*/
Sdk.versionManager = new (function () {
//Start with base version
var _webAPIMajorVersion = 8;
var _webAPIMinorVersion = 0;
//Use properties to increment version and provide WebAPIPath string used by Sdk.request;
Object.defineProperties(this, {
WebAPIMajorVersion: {
get: function () {
return _webAPIMajorVersion;
},
set: function (value) {
if (typeof value != "number") {
throw new Error(
"Sdk.versionManager.WebAPIMajorVersion property must be a number."
);
}
_webAPIMajorVersion = parseInt(value, 10);
},
},
WebAPIMinorVersion: {
get: function () {
return _webAPIMinorVersion;
},
set: function (value) {
if (isNaN(value)) {
throw new Error(
"Sdk.versionManager._webAPIMinorVersion property must be a number."
);
}
_webAPIMinorVersion = parseInt(value, 10);
},
},
WebAPIPath: {
get: function () {
return "/api/data/v" + _webAPIMajorVersion + "." + _webAPIMinorVersion;
},
},
});
})();
//Setting variables specific to this sample within a container so they won't be
// overwritten by another scripts code
Sdk.SampleVariables = {
entitiesToDelete: [], // Entity URIs to be deleted later (if user so chooses)
deleteData: true, // Controls whether sample data are deleted at the end of sample run
contact1Uri: null, // e.g.: Peter Cambel
contactAltUri: null, // e.g.: Peter_Alt Cambel
account1Uri: null, // e.g.: Contoso, Ltd
account2Uri: null, // e.g.: Fourth Coffee
contact2Uri: null, // e.g.: Susie Curtis
opportunity1Uri: null, // e.g.: Adventure Works
competitor1Uri: null,
};
/**
* @function request
* @description Generic helper function to handle basic XMLHttpRequest calls.
* @param {string} action - The request action. String is case-sensitive.
* @param {string} uri - An absolute or relative URI. Relative URI starts with a "/".
* @param {object} data - An object representing an entity. Required for create and update actions.
* @param {object} addHeader - An object with header and value properties to add to the request
* @returns {Promise} - A Promise that returns either the request object or an error object.
*/
Sdk.request = function (action, uri, data, addHeader) {
if (!RegExp(action, "g").test("POST PATCH PUT GET DELETE")) {
// Expected action verbs.
throw new Error(
"Sdk.request: action parameter must be one of the following: " +
"POST, PATCH, PUT, GET, or DELETE."
);
}
if (!typeof uri === "string") {
throw new Error("Sdk.request: uri parameter must be a string.");
}
if (RegExp(action, "g").test("POST PATCH PUT") && !data) {
throw new Error(
"Sdk.request: data parameter must not be null for operations that create or modify data."
);
}
if (addHeader) {
if (
typeof addHeader.header != "string" ||
typeof addHeader.value != "string"
) {
throw new Error(
"Sdk.request: addHeader parameter must have header and value properties that are strings."
);
}
}
// Construct a fully qualified URI if a relative URI is passed in.
if (uri.charAt(0) === "/") {
//This sample will try to use the latest version of the web API as detected by the
// Sdk.retrieveVersion function.
uri = Sdk.getClientUrl() + Sdk.versionManager.WebAPIPath + uri;
}
return new Promise(function (resolve, reject) {
var request = new XMLHttpRequest();
request.open(action, encodeURI(uri), true);
request.setRequestHeader("OData-MaxVersion", "4.0");
request.setRequestHeader("OData-Version", "4.0");
request.setRequestHeader("Accept", "application/json");
request.setRequestHeader("Content-Type", "application/json; charset=utf-8");
if (addHeader) {
request.setRequestHeader(addHeader.header, addHeader.value);
}
request.onreadystatechange = function () {
if (this.readyState === 4) {
request.onreadystatechange = null;
switch (this.status) {
case 200: // Operation success with content returned in response body.
case 201: // Create success.
case 204: // Operation success with no content returned in response body.
resolve(this);
break;
default: // All other statuses are unexpected so are treated like errors.
var error;
try {
error = JSON.parse(request.response).error;
} catch (e) {
error = new Error("Unexpected Error");
}
reject(error);
break;
}
}
};
request.send(JSON.stringify(data));
});
};
/**
* @function startSample
* @description Runs the sample.
* This sample demonstrates basic CRUD+ operations.
* Results are sent to the debugger's console window.
*/
Sdk.startSample = function () {
// Initializing.
Sdk.SampleVariables.deleteData =
document.getElementsByName("removesampledata")[0].checked;
Sdk.SampleVariables.entitiesToDelete = []; // Reset the array.
Sdk.SampleVariables.contact1Uri = "";
Sdk.SampleVariables.account1Uri = "";
Sdk.SampleVariables.account2Uri = "";
Sdk.SampleVariables.contact2Uri = "";
Sdk.SampleVariables.opportunity1Uri = "";
Sdk.SampleVariables.competitor1Uri = "";
/**
* Behavior of this sample varies by version
* So starting by retrieving the version;
*/
Sdk.retrieveVersion()
.then(function () {
return Sdk.basicCreateAndUpdatesAsync();
})
.then(function () {
return Sdk.createWithAssociationAsync();
})
.then(function () {
return Sdk.createRelatedAsync();
})
.then(function () {
return Sdk.associateExistingAsync();
})
.then(function () {
return Sdk.deleteSampleData();
})
.catch(function (err) {
console.log("ERROR: " + err.message);
});
};
Sdk.retrieveVersion = function () {
return new Promise(function (resolve, reject) {
Sdk.request("GET", "/RetrieveVersion")
.then(function (request) {
try {
var RetrieveVersionResponse = JSON.parse(request.response);
var fullVersion = RetrieveVersionResponse.Version;
var versionData = fullVersion.split(".");
Sdk.versionManager.WebAPIMajorVersion = parseInt(versionData[0], 10);
Sdk.versionManager.WebAPIMinorVersion = parseInt(versionData[1], 10);
resolve();
} catch (err) {
reject(new Error("Error processing version: " + err.message));
}
})
.catch(function (err) {
reject(new Error("Error retrieving version: " + err.message));
});
});
};
Sdk.basicCreateAndUpdatesAsync = function () {
return new Promise(function (resolve, reject) {
// Section 1.
//
// Create the contact using POST request.
// A new entry will be added regardless if a contact with this info already exists in the system or not.
console.log("--Section 1 started--");
var contact = {};
contact.firstname = "Peter";
contact.lastname = "Cambel";
var entitySetName = "/contacts";
Sdk.request("POST", entitySetName, contact)
.then(function (request) {
// Process response from previous request.
Sdk.SampleVariables.contact1Uri =
request.getResponseHeader("OData-EntityId");
Sdk.SampleVariables.entitiesToDelete.push(
Sdk.SampleVariables.contact1Uri
); // To delete later
console.log(
"Contact 'Peter Cambel' created with URI: %s",
Sdk.SampleVariables.contact1Uri
);
// Setup for next request.
//
// Update contact.
// Add property values to a specific contact using PATCH request.
var contact = {};
contact.annualincome = 80000.0;
contact.jobtitle = "Junior Developer";
return Sdk.request("PATCH", Sdk.SampleVariables.contact1Uri, contact);
})
.then(function () {
// Process response from previous request.
console.log(
"Contact 'Peter Cambel' updated with job title and annual income."
);
// Setup for next request.
//
// Retrieve selected properties of a Contact entity using GET request.
// NOTE: It is performance best practice to select only the properties you need.
// Retrieved contact properties.
var properties = [
"fullname",
"annualincome",
"jobtitle",
"description",
].join();
// NOTE: For performance best practices, use $select to limit the properties you want to return
// See also: https://msdn.microsoft.com/library/gg334767.aspx#bkmk_requestProperties
var query = "?$select=" + properties;
return Sdk.request(
"GET",
Sdk.SampleVariables.contact1Uri + query,
null
);
})
.then(function (request) {
// Process response from previous request.
var contact1 = JSON.parse(request.response);
var successMsg =
"Contact '%s' retrieved:\n" +
"\tAnnual income: %s \n" +
"\tJob title: %s \n" +
"\tDescription: %s";
console.log(
successMsg,
contact1.fullname, // This property is read-only. Calculated from firstname and lastname.
contact1.annualincome,
contact1.jobtitle,
contact1.description
); // Description will be "null" because it has not been set yet.
// Setup for next request.
//
// Update properties.
// Set new values for some of the properties and apply the values to the server via PATCH request.
// Notice that we are updating the jobtitle and annualincome properties and adding value to the
// description property in the same request.
var contact = {};
contact.jobtitle = "Senior Developer";
contact.annualincome = 95000.0;
contact.description = "Assignment to-be-determined. ";
return Sdk.request("PATCH", Sdk.SampleVariables.contact1Uri, contact);
})
.then(function () {
// Process response from previous request.
console.log(
"Contact 'Peter Cambel' updated:\n" +
"\tJob title: Senior Developer, \n" +
"\tAnnual income: 95000, \n" +
"\tDescription: Assignment to-be-determined."
);
// Setup for next request.
//
// Set value for a single property using PUT request.
// In this case, we are setting the telephone1 property to "555-0105".
var value = { value: "555-0105" };
return Sdk.request(
"PUT",
Sdk.SampleVariables.contact1Uri + "/telephone1",
value
);
})
.then(function () {
// Process response from previous request.
console.log("Contact 'Peter Cambel' phone number updated.");
// Setup for next request.
//
// Retrieve single value property.
// Get a value of a single property using GET request.
// In this case, telephone1 is retrieved. We should get back "555-0105".
return Sdk.request(
"GET",
Sdk.SampleVariables.contact1Uri + "/telephone1",
null
);
})
.then(function (request) {
// Process response from previous request.
var phoneNumber = JSON.parse(request.response);
console.log("Contact's phone number is: %s", phoneNumber.value);
})
.then(function () {
// Setup for next request.
//The following operations require version 8.2 or higher
if (
Sdk.versionManager.WebAPIMajorVersion > 8 ||
(Sdk.versionManager.WebAPIMajorVersion == 8 &&
Sdk.versionManager.WebAPIMinorVersion >= 2)
) {
// Starting with December 2016 update (v8.2), a contact instance can be
// created and its properties returned in one operation by using a
//'Prefer: return=representation' header.
var contactAlt = {};
contactAlt.firstname = "Peter_Alt";
contactAlt.lastname = "Cambel";
contactAlt.jobtitle = "Junior Developer";
contactAlt.annualincome = 80000;
contactAlt.telephone1 = "555-0110";
var properties = ["fullname", "annualincome", "jobtitle"].join();
var query = "?$select=" + properties;
// Create contact and return its state (in the body).
var retRepHeader = {
header: "Prefer",
value: "return=representation",
};
Sdk.request("POST", entitySetName + query, contactAlt, retRepHeader)
.then(function (request) {
var contactA = JSON.parse(request.response);
//Because 'OData-EntityId' header not returned in a 201 response, you must instead
// construct the URI.
Sdk.SampleVariables.contactAltUri =
Sdk.getClientUrl() +
Sdk.versionManager.WebAPIPath +
"/contacts(" +
contactA.contactid +
")";
Sdk.SampleVariables.entitiesToDelete.push(
Sdk.SampleVariables.contactAltUri
);
var successMsg =
"Contact '%s' created:\n" +
"\tAnnual income: %s \n" +
"\tJob title: %s \n";
console.log(
successMsg,
contactA.fullname,
contactA.annualincome,
contactA.jobtitle
);
console.log("Contact URI: %s", Sdk.SampleVariables.contactAltUri);
})
.then(function () {
// Setup for next request.
//Similarly, the December 2016 update (v8.2) also enables returning selected properties
//after an update operation (PATCH), with the 'Prefer: return=representation' header.
var contactAlt = {};
contactAlt.jobtitle = "Senior Developer";
contactAlt.annualincome = 95000;
contactAlt.description = "MS Azure and Dataverse Specialist";
var properties = [
"fullname",
"annualincome",
"jobtitle",
"description",
].join();
var query = "?$select=" + properties;
// Update contact and return its state (in the body).
var retRepHeader = {
header: "Prefer",
value: "return=representation",
};
return Sdk.request(
"PATCH",
Sdk.SampleVariables.contactAltUri + query,
contactAlt,
retRepHeader
);
})
.then(function (request) {
// Process response from previous request.
var contactA = JSON.parse(request.response);
var successMsg =
"Contact '%s' updated:\n" +
"\tAnnual income: %s \n" +
"\tJob title: %s \n";
console.log(
successMsg,
contactA.fullname,
contactA.annualincome,
contactA.jobtitle
);
//End this series of operations:
resolve();
})
.catch(function (err) {
reject(err);
});
} else {
resolve();
}
})
.catch(function (err) {
reject(err);
});
});
};
Sdk.createWithAssociationAsync = function () {
return new Promise(function (resolve, reject) {
// Section 2.
//
// Create a new account entity and associate it with an existing contact using POST request.
console.log("\n--Section 2 started--");
var account = {};
account.name = "Contoso, Ltd.";
account.telephone1 = "555-5555";
account["primarycontactid@odata.bind"] = Sdk.SampleVariables.contact1Uri; //relative URI ok. E.g.: "/contacts(###)".
var entitySetName = "/accounts";
Sdk.request("POST", entitySetName, account)
.then(function (request) {
// Process response from previous request.
Sdk.SampleVariables.account1Uri =
request.getResponseHeader("OData-EntityId");
Sdk.SampleVariables.entitiesToDelete.push(
Sdk.SampleVariables.account1Uri
);
console.log("Account 'Contoso, Ltd.' created.");
// Setup for next request.
//
// Retrieve account's primary contact with selected properties using GET request and 'expand' query.
var contactProperties = ["fullname", "jobtitle", "annualincome"].join();
var query =
"?$select=name,telephone1&$expand=primarycontactid($select=" +
contactProperties +
")";
return Sdk.request(
"GET",
Sdk.SampleVariables.account1Uri + query,
null
);
})
.then(function (request) {
// Process response from previous request.
var account1 = JSON.parse(request.response);
var successMsg =
"Account '%s' has primary contact '%s': \n" +
"\tJob title: %s \n" +
"\tAnnual income: %s ";
console.log(
successMsg,
account1.name,
account1.primarycontactid.fullname,
account1.primarycontactid.jobtitle,
account1.primarycontactid.annualincome
);
//End this series of operations:
resolve();
})
.catch(function (err) {
reject(err);
});
});
};
Sdk.createRelatedAsync = function () {
return new Promise(function (resolve, reject) {
// Section 3.
//
// Create related entities (deep insert).
// Create the following entities in one operation using deep insert technique:
// account
// |--- contact
// |--- tasks
// Then retrieve properties of these entities
//
// Constructing the entity relationship.
console.log("\n--Section 3 started--");
var account = {};
account.name = "Fourth Coffee";
account.primarycontactid = {
firstname: "Susie",
lastname: "Curtis",
jobtitle: "Coffee Master",
annualincome: 48000.0,
Contact_Tasks: [
{
subject: "Sign invoice",
description: "Invoice #12321",
scheduledend: new Date("April 19th, 2016"),
},
{
subject: "Setup new display",
description: "Theme is - Spring is in the air",
scheduledstart: new Date("4/20/2016"),
},
{
subject: "Conduct training",
description: "Train team on making our new blended coffee",
scheduledstart: new Date("6/1/2016"),
},
],
};
var entitySetName = "/accounts";
Sdk.request("POST", entitySetName, account)
.then(function (request) {
// Process response from previous request.
Sdk.SampleVariables.account2Uri =
request.getResponseHeader("OData-EntityId");
Sdk.SampleVariables.entitiesToDelete.push(
Sdk.SampleVariables.account2Uri
);
console.log("Account 'Fourth Coffee' created.");
// Setup for next request.
//
// Retrieve account entity info using GET request and 'expand' query.
var contactProperties = ["fullname", "jobtitle", "annualincome"].join();
// Expand on primarycontactid to select some of contact's properties.
// NOTE: With $expand, the CRM server will return values for the selected properties.
// The CRM Web API only supports expansions one level deep.
// See also: https://msdn.microsoft.com/library/mt607871.aspx#bkmk_expandRelated
var query =
"?$select=name&$expand=primarycontactid($select=" +
contactProperties +
")";
return Sdk.request(
"GET",
Sdk.SampleVariables.account2Uri + query,
null
);
})
.then(function (request) {
// Process response from previous request.
var account2 = JSON.parse(request.response);
var successMsg =
"Account '%s' has primary contact '%s':\n" +
"\tJob title: %s \n" +
"\tAnnual income: %s";
console.log(
successMsg,
account2.name,
account2.primarycontactid.fullname,
account2.primarycontactid.jobtitle,
account2.primarycontactid.annualincome
);
// Setup for next request.
//
// Retrieve contact entity and expanding on its tasks using GET request.
Sdk.SampleVariables.contact2Uri =
Sdk.getClientUrl() +
Sdk.versionManager.WebAPIPath +
"/contacts(" +
account2.primarycontactid.contactid +
")"; //Full URI.
Sdk.SampleVariables.entitiesToDelete.push(
Sdk.SampleVariables.contact2Uri
); // For Susie Curtis
var contactProperties = ["fullname", "jobtitle"].join();
var contactTaskProperties = [
"subject",
"description",
"scheduledstart",
"scheduledend",
].join();
// Expand on contact_tasks to select some of its properties for each task.
var query =
"?$select=" +
contactProperties +
"&$expand=Contact_Tasks($select=" +
contactTaskProperties +
")";
return Sdk.request(
"GET",
Sdk.SampleVariables.contact2Uri + query,
null
);
})
.then(function (request) {
// Process response from previous request.
var contact2 = JSON.parse(request.response);
console.log(
"Contact '%s' has the following assigned tasks:",
contact2.fullname
);
// construct the output string.
var successMsg =
"Subject: %s \n" +
"\tDescription: %s \n" +
"\tStart: %s \n" +
"\tEnd: %s \n";
for (var i = 0; i < contact2.Contact_Tasks.length; i++) {
console.log(
successMsg,
contact2.Contact_Tasks[i].subject,
contact2.Contact_Tasks[i].description,
contact2.Contact_Tasks[i].scheduledstart,
contact2.Contact_Tasks[i].scheduledend
);
}
//End this series of operations:
resolve();
})
.catch(function (err) {
reject(err);
});
});
};
Sdk.associateExistingAsync = function () {
return new Promise(function (resolve, reject) {
// Section 4
//
// Entity associations:
// Associate to existing entities via the different relationship types:
// 1) 1:N relationship - Associate an existing contact to an existing account
// (e.g.: contact - Peter Cambel to account - Fourth Coffee).
// 2) N:N relationship - Associate an competitor to opportunity.
console.log("\n--Section 4 started--");
var contact = {};
contact["@odata.id"] = Sdk.SampleVariables.contact1Uri;
Sdk.request(
"POST",
Sdk.SampleVariables.account2Uri + "/contact_customer_accounts/$ref",
contact
)
.then(function () {
// Process response from previous request.
console.log(
"Contact 'Peter Cambel' associated to account 'Fourth Coffee'."
);
// Setup for next request.
//
// Verify that the reference was made as expected.
var contactProperties = ["fullname", "jobtitle"].join();
// This returns a collection of all associated contacts...in a "value" array.
var query = "/contact_customer_accounts?$select=" + contactProperties;
return Sdk.request(
"GET",
Sdk.SampleVariables.account2Uri + query,
null
);
})
.then(function (request) {
// Process response from previous request.
var relatedContacts = JSON.parse(request.response).value; //collection is in the "value" array.
var successMsg = "\tName: %s, " + "Job title: %s ";
console.log("Contact list for account 'Fourth Coffee': ");
for (var i = 0; i < relatedContacts.length; i++) {
console.log(
successMsg,
relatedContacts[i].fullname,
relatedContacts[i].jobtitle
);
}
// Setup for next request.
//
// Disassociate a contact from an account.
return Sdk.request(
"DELETE",
Sdk.SampleVariables.account2Uri +
"/contact_customer_accounts/$ref?$id=" +
Sdk.SampleVariables.contact1Uri,
null
);
})
.then(function () {
// Process response from previous request.
console.log(
"Contact 'Peter Cambel' disassociated from account 'Fourth Coffee'."
);
// Setup for next request.
//
// N:N relationship:
// Associate a competitor to an opportunity.
var competitor = {};
competitor.name = "Adventure Works";
competitor.strengths =
"Strong promoter of private tours for multi-day outdoor adventures.";
var entitySetName = "/competitors";
return Sdk.request("POST", entitySetName, competitor);
})
.then(function (request) {
// Process response from previous request.
Sdk.SampleVariables.competitor1Uri =
request.getResponseHeader("OData-EntityId");
Sdk.SampleVariables.entitiesToDelete.push(
Sdk.SampleVariables.competitor1Uri
);
console.log("Competitor 'Adventure Works' created.");
// Setup for next request.
//
// Create a new opportunity...
var opportunity = {};
opportunity.name = "River rafting adventure";
opportunity.description =
"Sales team on a river-rafting offsite and team building.";
var entitySetName = "/opportunities";
return Sdk.request("POST", entitySetName, opportunity);
})
.then(function (request) {
// Process response from previous request.
Sdk.SampleVariables.opportunity1Uri =
request.getResponseHeader("OData-EntityId");
Sdk.SampleVariables.entitiesToDelete.push(
Sdk.SampleVariables.opportunity1Uri
);
console.log("Opportunity 'River rafting adventure' created.");
// Setup for next request.
//
// Associate competitor to opportunity.
var competitor = {};
competitor["@odata.id"] = Sdk.SampleVariables.competitor1Uri;
return Sdk.request(
"POST",
Sdk.SampleVariables.opportunity1Uri +
"/opportunitycompetitors_association/$ref",
competitor
);
})
.then(function () {
// Process response from previous request.
console.log(
"Opportunity 'River rafting adventure' associated with competitor 'Adventure Works'."
);
// Setup for next request.
//
// Retrieve competitor entity and expanding on its opportunitycompetitors_association
// for all opportunities, using GET request.
var opportunityProperties = ["name", "description"].join();
var competitorProperties = ["name"].join();
var query =
"?$select=" +
competitorProperties +
"&$expand=opportunitycompetitors_association($select=" +
opportunityProperties +
")";
return Sdk.request(
"GET",
Sdk.SampleVariables.competitor1Uri + query,
null
);
})
.then(function (request) {
// Process response from previous request.
var competitor1 = JSON.parse(request.response);
console.log(
"Competitor '%s' has the following opportunities:",
competitor1.name
);
var successMsg = "\tName: %s, \n" + "\tDescription: %s";
for (
var i = 0;
i < competitor1.opportunitycompetitors_association.length;
i++
) {
console.log(
successMsg,
competitor1.opportunitycompetitors_association[i].name,
competitor1.opportunitycompetitors_association[i].description
);
}
// Setup for next request.
//
// Disassociate competitor from opportunity.
return Sdk.request(
"DELETE",
Sdk.SampleVariables.opportunity1Uri +
"/opportunitycompetitors_association/$ref?$id=" +
Sdk.SampleVariables.competitor1Uri,
null
);
})
.then(function () {
// Process response from previous request.
console.log(
"Opportunity 'River rafting adventure' disassociated with competitor 'Adventure Works'"
);
//End this series of operations:
resolve();
})
.catch(function (err) {
reject(err);
});
});
};
Sdk.deleteSampleData = function () {
return new Promise(function (resolve, reject) {
// House cleaning - deleting sample data
// NOTE: If instances have a parent-child relationship, then deleting the parent will,
// by default, automatically cascade delete child instances. In this program,
// tasks related using the Contact_Tasks relationship have contact as their parent.
// Other relationships may behave differently.
// See also: https://msdn.microsoft.com/library/gg309412.aspx#BKMK_CascadingBehavior
console.log("\n--Section 5 started--");
if (Sdk.SampleVariables.deleteData) {
for (var i = 0; i < Sdk.SampleVariables.entitiesToDelete.length; i++) {
console.log(
"Deleting entity: " + Sdk.SampleVariables.entitiesToDelete[i]
);
Sdk.request(
"DELETE",
Sdk.SampleVariables.entitiesToDelete[i],
null
).catch(function (err) {
reject(
new Error("ERROR: Delete failed --Reason: \n\t" + err.message)
);
});
}
resolve();
} else {
console.log("Sample data not deleted.");
resolve();
}
});
};
See also
Use the Dataverse Web API
Create a table row using the Web API
Retrieve a table row using the Web API
Update and delete table rows using the Web API
Web API Samples
Web API Basic Operations Sample
Web API Basic Operations Sample (C#)
Web API Samples (Client-side JavaScript)
Web API Query Data Sample (Client-side JavaScript)
Web API Conditional Operations Sample (Client-side JavaScript)
Web API Functions and Actions Sample (Client-side JavaScript)