Skip to content

Commit 130f3c0

Browse files
authored
Enhancement/#311 page iterator request options (#318)
* Adding request options property to PageIterator * Adding tests for page iterator task to test passing along the headers * using headersinit type for headers * Specifying parameter definition * using constants * Updating function documentation * remove response type, test passing fetchoptions * testing requestOptions set in pageiterator * typos, optional parameters comments
1 parent 8089cd0 commit 130f3c0

File tree

5 files changed

+188
-17
lines changed

5 files changed

+188
-17
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/**
2+
* -------------------------------------------------------------------------------------------
3+
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
4+
* See License in the project root for license information.
5+
* -------------------------------------------------------------------------------------------
6+
*/
7+
8+
import { assert } from "chai";
9+
import { Event } from "microsoft-graph";
10+
11+
import { PageIterator, PageIteratorCallback, GraphRequestOptions, PageCollection } from "../../../src/tasks/PageIterator";
12+
import { getClient } from "../test-helper";
13+
import { ChaosHandler } from "../../../src/middleware/ChaosHandler";
14+
import { ChaosHandlerOptions } from "../../../src/middleware/options/ChaosHandlerOptions";
15+
import { ChaosStrategy } from "../../../src/middleware/options/ChaosStrategy";
16+
import { Client, ClientOptions } from "../../../src";
17+
18+
const client = getClient();
19+
describe("PageIterator", function() {
20+
const pstHeader = { Prefer: 'outlook.timezone= "pacific standard time"' };
21+
const utc = "UTC";
22+
const pst = "Pacific Standard Time";
23+
const testURL = "/me/events";
24+
25+
before(async function() {
26+
this.timeout(20000);
27+
28+
const response = await client.api(testURL).get();
29+
const numberOfEvents = 4;
30+
const existingEventsCount = response.value.length;
31+
32+
if (existingEventsCount >= numberOfEvents) {
33+
return;
34+
}
35+
const eventSubject = '"subject": "Test event ';
36+
const eventTimeZone = '"timeZone": "UTC"';
37+
const eventStartDateTime = '"start": { "dateTime":"' + new Date().toISOString() + '",' + eventTimeZone + "}";
38+
const eventEndDateTime = '"end": { "dateTime":"' + new Date().toISOString() + '",' + eventTimeZone + "}";
39+
40+
for (let i = 1; i <= numberOfEvents - existingEventsCount; i++) {
41+
const eventBody = "{" + eventSubject + "" + 1 + '",' + eventStartDateTime + "," + eventEndDateTime + "}";
42+
const response = await client.api(testURL).post(eventBody);
43+
if (response.error) {
44+
throw response.error;
45+
}
46+
}
47+
});
48+
49+
it("same headers passed with pageIterator", async () => {
50+
const response = await client
51+
.api(`${testURL}?$top=2`)
52+
.headers(pstHeader)
53+
.select("id,start,end")
54+
.get();
55+
56+
const callback: PageIteratorCallback = (eventResponse) => {
57+
const event = eventResponse as Event;
58+
assert.equal(event.start.timeZone, pst);
59+
return true;
60+
};
61+
var requestOptions: GraphRequestOptions = { options: { headers: pstHeader } };
62+
if (response["@odata.nextLink"]) {
63+
const pageIterator = new PageIterator(client, response, callback, requestOptions);
64+
await pageIterator.iterate();
65+
assert.isTrue(pageIterator.isComplete());
66+
}
67+
}).timeout(30 * 1000);
68+
69+
it("different headers passed with pageIterator", async () => {
70+
const response = await client
71+
.api(`${testURL}?$top=2`)
72+
.headers({ Prefer: `outlook.timezone= "${utc}"` })
73+
.select("id,start,end")
74+
.get();
75+
76+
let counter = 0;
77+
const callback: PageIteratorCallback = (eventResponse) => {
78+
const event = eventResponse as Event;
79+
if (counter < 2) {
80+
assert.equal(event.start.timeZone, utc);
81+
counter++;
82+
} else {
83+
assert.equal(event.start.timeZone, pst);
84+
}
85+
return true;
86+
};
87+
88+
var requestOptions = { headers: pstHeader };
89+
if (response["@odata.nextLink"]) {
90+
const pageIterator = new PageIterator(client, response, callback, requestOptions);
91+
await pageIterator.iterate();
92+
assert.isTrue(pageIterator.isComplete());
93+
}
94+
}).timeout(30 * 1000);
95+
96+
it("setting middleware with pageIterator", async () => {
97+
const middleware = new ChaosHandler();
98+
const getPageCollection = () => {
99+
return {
100+
value: [],
101+
"@odata.nextLink": "nextURL",
102+
additionalContent: "additional content",
103+
};
104+
};
105+
const clientOptions: ClientOptions = {
106+
middleware,
107+
};
108+
const responseBody = { value: [{ event1: "value1" }, { event2: "value2" }] };
109+
let counter = 1;
110+
const callback: PageIteratorCallback = (data) => {
111+
assert.equal(data["event" + counter], "value" + counter);
112+
counter++;
113+
return true;
114+
};
115+
116+
const middlewareOptions = [new ChaosHandlerOptions(ChaosStrategy.MANUAL, 200, "middleware options for pageIterator", 0, responseBody)];
117+
const requestOptions = { middlewareOptions };
118+
119+
const client = Client.initWithMiddleware(clientOptions);
120+
const pageIterator = new PageIterator(client, getPageCollection(), callback, requestOptions);
121+
await pageIterator.iterate();
122+
});
123+
});

src/GraphRequest.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,7 @@ export class GraphRequest {
7979
* @private
8080
* A member to hold custom header options for a request
8181
*/
82-
private _headers: {
83-
[key: string]: string;
84-
};
82+
private _headers: HeadersInit;
8583

8684
/**
8785
* @private
@@ -428,10 +426,10 @@ export class GraphRequest {
428426
/**
429427
* @public
430428
* Sets the custom headers for a request
431-
* @param {KeyValuePairObjectStringNumber} headers - The headers key value pair object
429+
* @param {KeyValuePairObjectStringNumber | HeadersInit} headers - The request headers
432430
* @returns The same GraphRequest instance that is being called with
433431
*/
434-
public headers(headers: KeyValuePairObjectStringNumber): GraphRequest {
432+
public headers(headers: KeyValuePairObjectStringNumber | HeadersInit): GraphRequest {
435433
for (const key in headers) {
436434
if (headers.hasOwnProperty(key)) {
437435
this._headers[key] = headers[key] as string;

src/middleware/ChaosHandler.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,19 @@ export class ChaosHandler implements Middleware {
9191
* @param {string} statusMessage - the status message to be returned for the request
9292
* @param {string} requestID - request id
9393
* @param {string} requestDate - date of the request
94+
* @param {any?} requestBody - the request body to be returned for the request
9495
* @returns response body
9596
*/
96-
private createResponseBody(statusCode: number, statusMessage: string, requestID: string, requestDate: string) {
97-
let responseBody: any;
97+
private createResponseBody(statusCode: number, statusMessage: string, requestID: string, requestDate: string, responseBody?: any) {
98+
if (responseBody) {
99+
return responseBody;
100+
}
101+
let body: any;
98102
if (statusCode >= 400) {
99103
const codeMessage: string = httpStatusCode[statusCode];
100104
const errMessage: string = statusMessage;
101105

102-
responseBody = {
106+
body = {
103107
error: {
104108
code: codeMessage,
105109
message: errMessage,
@@ -110,9 +114,9 @@ export class ChaosHandler implements Middleware {
110114
},
111115
};
112116
} else {
113-
responseBody = {};
117+
body = {};
114118
}
115-
return responseBody;
119+
return body;
116120
}
117121

118122
/**
@@ -132,7 +136,7 @@ export class ChaosHandler implements Middleware {
132136
requestID = generateUUID();
133137
requestDate = new Date();
134138
responseHeader = this.createResponseHeaders(chaosHandlerOptions.statusCode, requestID, requestDate.toString());
135-
responseBody = this.createResponseBody(chaosHandlerOptions.statusCode, chaosHandlerOptions.statusMessage, requestID, requestDate.toString());
139+
responseBody = this.createResponseBody(chaosHandlerOptions.statusCode, chaosHandlerOptions.statusMessage, requestID, requestDate.toString(), chaosHandlerOptions.responseBody);
136140
const init: any = { url: requestURL, status: chaosHandlerOptions.statusCode, statusText: chaosHandlerOptions.statusMessage, headers: responseHeader };
137141
context.response = new Response(responseBody, init);
138142
} catch (error) {

src/middleware/options/ChaosHandlerOptions.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { MiddlewareOptions } from "./IMiddlewareOptions";
2020
*/
2121
export class ChaosHandlerOptions implements MiddlewareOptions {
2222
/**
23-
* Specifies the startegy used for the Testing Handler -> RAMDOM/MANUAL
23+
* Specifies the startegy used for the Testing Handler -> RANDOM/MANUAL
2424
*
2525
* @public
2626
*/
@@ -48,20 +48,30 @@ export class ChaosHandlerOptions implements MiddlewareOptions {
4848
*/
4949
public chaosPercentage: number;
5050

51+
/**
52+
* The response body to be returned in the response
53+
*
54+
* @public
55+
*/
56+
public responseBody: any;
57+
5158
/**
5259
* @public
5360
* @constructor
5461
* To create an instance of Testing Handler Options
5562
* @param {ChaosStrategy} ChaosStrategy - Specifies the startegy used for the Testing Handler -> RAMDOM/MANUAL
56-
* @param {number?} statusCode - The Message to be returned in the response
57-
* @param {string} - The Message to be returned in the response
63+
* @param {number?} statusCode - The statusCode to be returned in the response
64+
* @param {string} statusMessage - The Message to be returned in the response
65+
* @param {number?} chaosPercentage - The percentage of randomness/chaos in the handler
66+
* @param {any?} responseBody - The response body to be returned in the response
5867
* @returns An instance of ChaosHandlerOptions
5968
*/
60-
public constructor(chaosStrategy: ChaosStrategy = ChaosStrategy.RANDOM, statusCode?: number, statusMessage: string = "Some error Happened", chaosPercentage?: number) {
69+
public constructor(chaosStrategy: ChaosStrategy = ChaosStrategy.RANDOM, statusCode?: number, statusMessage: string = "Some error Happened", chaosPercentage?: number, responseBody?: any) {
6170
this.chaosStrategy = chaosStrategy;
6271
this.statusCode = statusCode;
6372
this.statusMessage = statusMessage;
6473
this.chaosPercentage = chaosPercentage !== undefined ? chaosPercentage : 10;
74+
this.responseBody = responseBody;
6575
if (this.chaosPercentage > 100) {
6676
throw new Error("Error Pecentage can not be more than 100");
6777
}

src/tasks/PageIterator.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
* @module PageIterator
1010
*/
1111

12+
import { FetchOptions } from "../IFetchOptions";
1213
import { Client } from "../index";
14+
import { MiddlewareOptions } from "../middleware/options/IMiddlewareOptions";
15+
import { ResponseType } from "../ResponseType";
1316

1417
/**
1518
* Signature representing PageCollection
@@ -25,6 +28,19 @@ export interface PageCollection {
2528
[Key: string]: any;
2629
}
2730

31+
/**
32+
* Signature to define the request options to be sent during request.
33+
* The values of the GraphRequestOptions properties are passed to the Graph Request object.
34+
* @property {HeadersInit} headers - the header options for the request
35+
* @property {MiddlewareOptions[]} middlewareoptions - The middleware options for the request
36+
* @property {FetchOptions} options - The fetch options for the request
37+
*/
38+
export interface GraphRequestOptions {
39+
headers?: HeadersInit;
40+
middlewareOptions?: MiddlewareOptions[];
41+
options?: FetchOptions;
42+
}
43+
2844
/**
2945
* Signature representing callback for page iterator
3046
* @property {Function} callback - The callback function which should return boolean to continue the continue/stop the iteration.
@@ -73,22 +89,29 @@ export class PageIterator {
7389
*/
7490
private complete: boolean;
7591

92+
/**
93+
* Information to be added to the request
94+
*/
95+
private requestOptions: GraphRequestOptions;
96+
7697
/**
7798
* @public
7899
* @constructor
79100
* Creates new instance for PageIterator
80101
* @param {Client} client - The graph client instance
81102
* @param {PageCollection} pageCollection - The page collection object
82103
* @param {PageIteratorCallback} callBack - The callback function
104+
* @param {GraphRequestOptions} requestOptions - The request options
83105
* @returns An instance of a PageIterator
84106
*/
85-
public constructor(client: Client, pageCollection: PageCollection, callback: PageIteratorCallback) {
107+
public constructor(client: Client, pageCollection: PageCollection, callback: PageIteratorCallback, requestOptions?: GraphRequestOptions) {
86108
this.client = client;
87109
this.collection = pageCollection.value;
88110
this.nextLink = pageCollection["@odata.nextLink"];
89111
this.deltaLink = pageCollection["@odata.deltaLink"];
90112
this.callback = callback;
91113
this.complete = false;
114+
this.requestOptions = requestOptions;
92115
}
93116

94117
/**
@@ -116,7 +139,20 @@ export class PageIterator {
116139
*/
117140
private async fetchAndUpdateNextPageData(): Promise<any> {
118141
try {
119-
const response: PageCollection = await this.client.api(this.nextLink).get();
142+
let graphRequest = this.client.api(this.nextLink);
143+
if (this.requestOptions) {
144+
if (this.requestOptions.headers) {
145+
graphRequest = graphRequest.headers(this.requestOptions.headers);
146+
}
147+
if (this.requestOptions.middlewareOptions) {
148+
graphRequest = graphRequest.middlewareOptions(this.requestOptions.middlewareOptions);
149+
}
150+
if (this.requestOptions.options) {
151+
graphRequest = graphRequest.options(this.requestOptions.options);
152+
}
153+
}
154+
155+
const response: PageCollection = await graphRequest.get();
120156
this.collection = response.value;
121157
this.nextLink = response["@odata.nextLink"];
122158
this.deltaLink = response["@odata.deltaLink"];

0 commit comments

Comments
 (0)