Skip to content

Commit

Permalink
Added synch requests tests, per-request options, this resolves #5
Browse files Browse the repository at this point in the history
  • Loading branch information
DigitalFlow committed Feb 26, 2017
1 parent ac8980a commit 762f9ff
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 28 deletions.
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,32 @@ You can always download the browserified version of this framework by downloadin
[![Build Status](https://travis-ci.org/DigitalFlow/Xrm-WebApi-Client.svg?branch=master)](https://travis-ci.org/DigitalFlow/Xrm-WebApi-Client)

## Operations
### Synchronous vs Asynchronous
Per default, all requests are sent asynchronously.
This is the suggested way of sending requests, however, sometimes there is the need for using synchronous requests.

For example if you want to use a function for hiding / enabling a ribbon bar button, it has to return either true or false for the visibility of the button. In this case, you would need to use a synchronous request for being able to directly return values.

Be sure to avoid synchronous requests if it is possible and use asynchronous requests instead.

For sending requests synchronously, you can either set ```WebApiClient.Async``` to false, which will configure the WebApiClient to send all requests synchronously, or pass an ```async``` property in your request, like so:

```JavaScript
var request = {
entityName: "account",
entity: {name: "Adventure Works"},
async: false
};

try {
var response = WebApiClient.Create(request);

// Process response
}
catch (error) {
// Handle error
}
```

### Create
The client supports creation of records. You have to pass the entity logical name, and a data object:
Expand Down Expand Up @@ -109,6 +135,16 @@ WebApiClient.ReturnAllPages = true;

By setting this to true, each retrieve multiple request will check for an @odata.nextLink property inside the response, call the next page and concatenate the results, until all records have been retrieved.

You can also pass this option per-request, like this:

```JavaScript
var request = {
entityName: "account",
queryParams: "?$select=name,revenue,&$orderby=revenue asc,name desc&$filter=revenue ne null",
returnAllPages: true
};
```

##### Retrieve by query expression:

```JavaScript
Expand Down
53 changes: 33 additions & 20 deletions src/js/WebApiClient.Core.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@
return "";
}

function SendAsync(method, url, payload, requestHeaders, previousResponse) {
function SendAsync(method, url, payload, parameters, previousResponse) {
var xhr = new XMLHttpRequest();

var promise = new Promise(function(resolve, reject) {
Expand All @@ -207,8 +207,8 @@
response = MergeResults(previousResponse, response);

// Results are paged, we don't have all results at this point
if (nextLink && WebApiClient.ReturnAllPages) {
resolve(SendAsync("GET", nextLink, null, requestHeaders, response));
if (nextLink && (WebApiClient.ReturnAllPages || parameters.returnAllPages)) {
resolve(SendAsync("GET", nextLink, null, parameters, response));
}
else {
resolve(response);
Expand All @@ -235,7 +235,7 @@
xhr.open(method, url, true);

AppendHeaders(xhr, DefaultHeaders);
AppendHeaders(xhr, requestHeaders);
AppendHeaders(xhr, parameters.headers);

// Bugfix for IE. If payload is undefined, IE would send "undefined" as request body
if (payload) {
Expand All @@ -247,7 +247,7 @@
return promise;
}

function SendSync(method, url, payload, requestHeaders, previousResponse) {
function SendSync(method, url, payload, parameters, previousResponse) {
var xhr = new XMLHttpRequest();
var response;

Expand All @@ -263,8 +263,8 @@
response = MergeResults(previousResponse, response);

// Results are paged, we don't have all results at this point
if (nextLink && WebApiClient.ReturnAllPages) {
SendSync("GET", nextLink, null, requestHeaders, response);
if (nextLink && (WebApiClient.ReturnAllPages || parameters.returnAllPages)) {
SendSync("GET", nextLink, null, parameters, response);
}
}
else if (xhr.status === 204) {
Expand All @@ -287,7 +287,7 @@
xhr.open(method, url, false);

AppendHeaders(xhr, DefaultHeaders);
AppendHeaders(xhr, requestHeaders);
AppendHeaders(xhr, parameters.headers);

// Bugfix for IE. If payload is undefined, IE would send "undefined" as request body
if (payload) {
Expand All @@ -299,18 +299,31 @@
return response;
}

WebApiClient.SendRequest = function (method, url, payload, requestHeaders, previousResponse) {
WebApiClient.SendRequest = function (method, url, payload, parameters, previousResponse) {
/// <summary>Sends request using given method, url, payload and additional per-request headers.</summary>
/// <param name="method" type="String">Method type of request to send, such as "GET".</param>
/// <param name="url" type="String">URL target for request.</param>
/// <param name="payload" type="Object">Payload for request.</param>
/// <param name="requestHeaders" type="Array">Array of headers that consist of objects with key and value property.</param>
/// <returns>Promise for sent request.</returns>

if (WebApiClient.Async) {
return SendAsync(method, url, payload, requestHeaders, previousResponse);
// Fallback for request headers array as fourth parameter
if (Array.isArray(parameters)) {
parameters = {
headers: parameters
};
}

var asynchronous = WebApiClient.Async;

if (typeof(parameters.async) !== "undefined") {
asynchronous = parameters.async;
}

if (asynchronous) {
return SendAsync(method, url, payload, parameters, previousResponse);
} else {
return SendSync(method, url, payload, requestHeaders, previousResponse);
return SendSync(method, url, payload, parameters, previousResponse);
}
};

Expand Down Expand Up @@ -342,7 +355,7 @@

var url = WebApiClient.GetApiUrl() + WebApiClient.GetSetName(params.entityName, params.overriddenSetName);

return WebApiClient.SendRequest("POST", url, params.entity, params.headers);
return WebApiClient.SendRequest("POST", url, params.entity, params);
};

WebApiClient.Retrieve = function(parameters) {
Expand Down Expand Up @@ -384,7 +397,7 @@
url += params.queryParams;
}

return WebApiClient.SendRequest("GET", url, null, params.headers);
return WebApiClient.SendRequest("GET", url, null, params);
};

WebApiClient.Update = function(parameters) {
Expand All @@ -399,7 +412,7 @@

var url = GetRecordUrl(params);

return WebApiClient.SendRequest("PATCH", url, params.entity, params.headers);
return WebApiClient.SendRequest("PATCH", url, params.entity, params);
};

WebApiClient.Delete = function(parameters) {
Expand All @@ -409,7 +422,7 @@
var params = parameters || {};
var url = GetRecordUrl(params);

return WebApiClient.SendRequest("DELETE", url, null, params.headers);
return WebApiClient.SendRequest("DELETE", url, null, params);
};

WebApiClient.Associate = function(parameters) {
Expand All @@ -433,7 +446,7 @@

var payload = { "@odata.id": GetRecordUrl(params.source) };

return WebApiClient.SendRequest("POST", url, payload, params.headers);
return WebApiClient.SendRequest("POST", url, payload, params);
};

WebApiClient.Disassociate = function(parameters) {
Expand All @@ -459,7 +472,7 @@

var url = targetUrl + relationShip;

return WebApiClient.SendRequest("DELETE", url, null, params.headers);
return WebApiClient.SendRequest("DELETE", url, null, params);
};

WebApiClient.Execute = function(request) {
Expand All @@ -471,7 +484,7 @@
throw new Error("Request for execution must be in prototype chain of WebApiClient.Request");
}

return WebApiClient.SendRequest(request.method, request.buildUrl(), request.payload, request.headers);
return WebApiClient.SendRequest(request.method, request.buildUrl(), request.payload, request);
};

WebApiClient.Expand = function (parameters) {
Expand All @@ -498,7 +511,7 @@
continue;
}

record[name] = WebApiClient.SendRequest("GET", record[attribute], null, params.headers);
record[name] = WebApiClient.SendRequest("GET", record[attribute], null, params);

// Delete @odata.nextLink property
delete record[attribute];
Expand Down
66 changes: 58 additions & 8 deletions src/spec/WebApiClientSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ describe("WebApiClient", function() {
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
};

var defaults = {
ApiVersion: WebApiClient.ApiVersion,
ReturnAllPages: WebApiClient.ReturnAllPages,
PrettifyErrors: WebApiClient.PrettifyErrors,
Async: WebApiClient.Async
};

beforeEach(function() {
account = {
Name: "Adventure Works"
Expand All @@ -29,6 +36,8 @@ describe("WebApiClient", function() {
FirstName: "Joe"
};

WebApiClient.Configure(defaults);

xhr = sinon.fakeServer.create();
xhr.autoRespond = true;

Expand Down Expand Up @@ -912,6 +921,55 @@ describe("WebApiClient", function() {
});
});

describe("Synchronous requests", function() {
// We only test retrieve. If this works, all other requests should also work like the async ones
it("should retrieve by id with global sync flag", function(){
WebApiClient.Async = false;
var response = WebApiClient.Retrieve({entityName: "account", entityId: "00000000-0000-0000-0000-000000000001"});
expect(response).toEqual(account);
});

// We only test retrieve. If this works, all other requests should also work like the async ones
it("should retrieve by id with per request sync flag", function(){
var response = WebApiClient.Retrieve({entityName: "account", entityId: "00000000-0000-0000-0000-000000000001", async: false});
expect(response).toEqual(account);
});

it("should retrieve multiple with query params", function(){
var request = {
entityName: "account",
queryParams: "?$select=name,revenue,&$orderby=revenue asc,name desc&$filter=revenue ne null",
async: false
};

var response = WebApiClient.Retrieve(request);
expect(response).toEqual([account]);
});

it("should per default only retrieve first page", function(){
var request = {
entityName: "account",
queryParams: "?$select=pagingtestfirst",
async: false
};

var response = WebApiClient.Retrieve(request);
expect(response.value.length).toEqual(1);
});

it("should retrieve all pages if wanted", function(){
var request = {
entityName: "account",
queryParams: "?$select=pagingtestfirst",
async: false,
returnAllPages: true
};

var response = WebApiClient.Retrieve(request);
expect(response.value.length).toEqual(2);
});
});

describe("Errors", function() {
it("should be prettified by default", function(done){
WebApiClient.PrettifyErrors = true;
Expand Down Expand Up @@ -954,12 +1012,6 @@ describe("WebApiClient", function() {

describe("Configure", function() {
it("should apply values", function(){
var before = {
ApiVersion: WebApiClient.ApiVersion,
ReturnAllPages: WebApiClient.ReturnAllPages,
PrettifyErrors: WebApiClient.PrettifyErrors
};

WebApiClient.Configure({
ApiVersion: "8.2",
ReturnAllPages: true,
Expand All @@ -969,8 +1021,6 @@ describe("WebApiClient", function() {
expect(WebApiClient.ApiVersion).toBe("8.2");
expect(WebApiClient.ReturnAllPages).toBe(true);
expect(WebApiClient.PrettifyErrors).toBe(false);

WebApiClient.Configure(before);
});
});

Expand Down

0 comments on commit 762f9ff

Please sign in to comment.