Skip to content
This repository has been archived by the owner on Jun 18, 2019. It is now read-only.

Commit

Permalink
rewrite of the odata pipeline to move responsibility 100% to parsers …
Browse files Browse the repository at this point in the history
…for handling response, update to rreturn an object with etag for item update
  • Loading branch information
patrick-rodgers committed Jan 2, 2017
1 parent 5124a1e commit 19445ef
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 49 deletions.
1 change: 1 addition & 0 deletions src/sharepoint/index.ts
Expand Up @@ -25,6 +25,7 @@ export {
export {
ItemAddResult,
ItemUpdateResult,
ItemUpdateResultData,
PagedItemCollection
} from "./items";

Expand Down
33 changes: 28 additions & 5 deletions src/sharepoint/items.ts
Expand Up @@ -188,7 +188,7 @@ export class Item extends QueryableSecurable {
"IF-Match": eTag,
"X-HTTP-Method": "MERGE",
},
}).then((data) => {
}, new ItemUpdatedParser()).then((data) => {
removeDependency();
resolve({
data: data,
Expand Down Expand Up @@ -257,7 +257,11 @@ export interface ItemAddResult {

export interface ItemUpdateResult {
item: Item;
data: any;
data: ItemUpdateResultData;
}

export interface ItemUpdateResultData {
"odata.etag": string;
}

/**
Expand Down Expand Up @@ -291,9 +295,28 @@ export class PagedItemCollection<T> {
class PagedItemCollectionParser extends ODataParserBase<PagedItemCollection<any>> {
public parse(r: Response): Promise<PagedItemCollection<any>> {

return r.json().then(json => {
let nextUrl = json.hasOwnProperty("d") && json.d.hasOwnProperty("__next") ? json.d.__next : json["odata.nextLink"];
return new PagedItemCollection(nextUrl, this.parseODataJSON(json));
return new Promise<PagedItemCollection<any>>((resolve, reject) => {

if (this.handleError(r, reject)) {
r.json().then(json => {
let nextUrl = json.hasOwnProperty("d") && json.d.hasOwnProperty("__next") ? json.d.__next : json["odata.nextLink"];
resolve(new PagedItemCollection(nextUrl, this.parseODataJSON(json)));
});
}
});
}
}

class ItemUpdatedParser extends ODataParserBase<ItemUpdateResultData> {
public parse(r: Response): Promise<ItemUpdateResultData> {

return new Promise<ItemUpdateResultData>((resolve, reject) => {

if (this.handleError(r, reject)) {
resolve({
"odata.etag": r.headers.get("etag"),
});
}
});
}
}
Expand Down
22 changes: 21 additions & 1 deletion src/sharepoint/odata.ts
Expand Up @@ -5,6 +5,7 @@ import { HttpClient } from "../net/httpclient";
import { RuntimeConfig } from "../configuration/pnplibconfig";
import { TypedHash } from "../collections/collections";
import { ODataIdException, BatchParseException } from "../utils/exceptions";
import { ProcessHttpClientResponseException } from "../utils/exceptions";

export function extractOdataId(candidate: any): string {

Expand All @@ -24,7 +25,26 @@ export interface ODataParser<U> {
export abstract class ODataParserBase<U> implements ODataParser<U> {

public parse(r: Response): Promise<U> {
return r.json().then(json => this.parseODataJSON(json));

return new Promise<U>((resolve, reject) => {

if (this.handleError(r, reject)) {
if ((r.headers.has("Content-Length") && parseFloat(r.headers.get("Content-Length")) === 0) || r.status === 204) {
resolve(<U>{});
} else {
r.json().then(json => resolve(this.parseODataJSON<U>(json)));
}
}
});
}

protected handleError(r: Response, reject: (reason?: any) => void): boolean {
if (!r.ok) {
r.json().then(json => {
reject(new ProcessHttpClientResponseException(r.status, r.statusText, json));
});
}
return r.ok;
}

protected parseODataJSON<U>(json: any): U {
Expand Down
48 changes: 5 additions & 43 deletions src/sharepoint/queryable.ts
Expand Up @@ -4,7 +4,7 @@ import { FetchOptions, HttpClient } from "../net/httpclient";
import { ODataParser, ODataDefaultParser, ODataBatch } from "./odata";
import { ICachingOptions, CachingParserWrapper, CachingOptions } from "./caching";
import { RuntimeConfig } from "../configuration/pnplibconfig";
import { ProcessHttpClientResponseException, AlreadyInBatchException } from "../utils/exceptions";
import { AlreadyInBatchException } from "../utils/exceptions";

export interface QueryableConstructor<T> {
new (baseUrl: string | Queryable, path?: string): T;
Expand Down Expand Up @@ -271,9 +271,7 @@ export class Queryable {

// we are not part of a batch, so proceed as normal
let client = new HttpClient();
return client.get(this.toUrlAndQuery(), getOptions).then((response) => {
return this.processHttpClientResponse(response, parser);
});
return client.get(this.toUrlAndQuery(), getOptions).then((response) => parser.parse(response));

} else {

Expand All @@ -287,9 +285,7 @@ export class Queryable {

// we are not part of a batch, so proceed as normal
let client = new HttpClient();
return client.post(this.toUrlAndQuery(), postOptions).then((response) => {
return this.processHttpClientResponse(response, parser);
});
return client.post(this.toUrlAndQuery(), postOptions).then((response) => parser.parse(response));

} else {
return this._batch.add(this.toUrlAndQuery(), "POST", postOptions, parser);
Expand All @@ -302,9 +298,7 @@ export class Queryable {

// we are not part of a batch, so proceed as normal
let client = new HttpClient();
return client.patch(this.toUrlAndQuery(), patchOptions).then((response) => {
return this.processHttpClientResponse(response, parser);
});
return client.patch(this.toUrlAndQuery(), patchOptions).then((response) => parser.parse(response));

} else {
return this._batch.add(this.toUrlAndQuery(), "PATCH", patchOptions, parser);
Expand All @@ -317,44 +311,12 @@ export class Queryable {

// we are not part of a batch, so proceed as normal
let client = new HttpClient();
return client.delete(this.toUrlAndQuery(), deleteOptions).then((response) => {
return this.processHttpClientResponse(response, parser);
});
return client.delete(this.toUrlAndQuery(), deleteOptions).then((response) => parser.parse(response));

} else {
return this._batch.add(this.toUrlAndQuery(), "DELETE", deleteOptions, parser);
}
}

private processHttpClientResponse<T>(response: Response, parser: ODataParser<T>): Promise<T> {

return new Promise<T>((resolve, reject) => {

// 200 = OK (get, delete)
// 201 = Created (create)
// 204 = No Content (update)
if (response.ok) {

if ((response.headers.has("Content-Length") && parseFloat(response.headers.get("Content-Length")) === 0)
|| response.status === 204) {

// in these cases the server has returned no content, so we create an empty object
// this was done because the fetch browser methods throw exceptions with no content
return resolve(<T>{});
}

// pipe our parsed content
return resolve(parser.parse(response));

} else {

// and reject
response.json().then(json => {
return reject(new ProcessHttpClientResponseException(response.status, response.statusText, json));
});
}
});
}
}

/**
Expand Down

0 comments on commit 19445ef

Please sign in to comment.