Skip to content

Commit 7aba27f

Browse files
committed
merge with dev
2 parents 1a23f51 + 96b40bd commit 7aba27f

18 files changed

+359
-111
lines changed

package-lock.json

+4-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,4 @@
9393
"src/"
9494
]
9595
}
96-
}
96+
}

scripts/package-lock.json

+3-9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

spec/core/GraphClientError.ts

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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+
10+
import { GraphClientError } from "../../src/GraphClientError";
11+
12+
describe("GraphClientError", () => {
13+
const message = "test";
14+
const name = "test_name";
15+
it("Should return GraphClientError error with message set", () => {
16+
const gError = new GraphClientError(message);
17+
assert.equal(gError.message, message);
18+
});
19+
20+
it("Should return GraphClientError when Error object is passed", () => {
21+
const errorParameter = new Error(message);
22+
errorParameter.name = name;
23+
const gError = GraphClientError.setGraphClientError(errorParameter);
24+
assert.equal(gError.message, message);
25+
assert.equal(gError.name, name);
26+
});
27+
28+
it("Should return GraphClientError when custom error object is passed", () => {
29+
const customErrorParameter = { errorName: name, errorMessage: message };
30+
const gError = GraphClientError.setGraphClientError(customErrorParameter);
31+
assert.isDefined(gError.customError);
32+
assert.equal(gError.customError, customErrorParameter);
33+
});
34+
});

src/Constants.ts

+6
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,9 @@ export const GRAPH_API_VERSION = "v1.0";
2020
* A Default base url for a request
2121
*/
2222
export const GRAPH_BASE_URL = "https://graph.microsoft.com/";
23+
24+
/**
25+
* To hold list of the service root endpoints for Microsoft Graph and Graph Explorer for each national cloud.
26+
* Set(iterable:Object) is not supported in Internet Explorer. The consumer is recommended to use a suitable polyfill.
27+
*/
28+
export const GRAPH_URLS = new Set<string>(["graph.microsoft.com", "graph.microsoft.us", "dod-graph.microsoft.us", "graph.microsoft.de", "microsoftgraph.chinacloudapi.cn"]);

src/CustomAuthenticationProvider.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
* @module CustomAuthenticationProvider
1010
*/
1111

12+
import { GraphClientError } from "./GraphClientError";
1213
import { AuthenticationProvider } from "./IAuthenticationProvider";
1314
import { AuthProvider } from "./IAuthProvider";
1415

@@ -43,11 +44,18 @@ export class CustomAuthenticationProvider implements AuthenticationProvider {
4344
*/
4445
public async getAccessToken(): Promise<any> {
4546
return new Promise((resolve: (accessToken: string) => void, reject: (error: any) => void) => {
46-
this.provider((error: any, accessToken: string | null) => {
47+
this.provider(async (error: any, accessToken: string | null) => {
4748
if (accessToken) {
4849
resolve(accessToken);
4950
} else {
50-
reject(error);
51+
if (!error) {
52+
const invalidTokenMessage = "Access token is undefined or empty.\
53+
Please provide a valid token.\
54+
For more help - https://github.com/microsoftgraph/msgraph-sdk-javascript/blob/dev/docs/CustomAuthenticationProvider.md";
55+
error = new GraphClientError(invalidTokenMessage);
56+
}
57+
const err = await GraphClientError.setGraphClientError(error);
58+
reject(err);
5159
}
5260
});
5361
});

src/GraphClientError.ts

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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+
/**
9+
* @module GraphClientError
10+
*/
11+
12+
/**
13+
* @class
14+
* Create GraphClientError object to handle client-side errors
15+
* encountered within the JavaScript Client SDK.
16+
* Whereas GraphError Class should be used to handle errors in the response from the Graph API.
17+
*/
18+
19+
export class GraphClientError extends Error {
20+
/**
21+
* @public
22+
* A custom error. This property should set be when the error is not of instanceOf Error/GraphClientError.
23+
* Example =
24+
* const client = MicrosoftGraph.Client.init({
25+
* defaultVersion: "v1.0",
26+
* authProvider: (done) => { done({TokenError:"AccessToken cannot be null"}, "<ACCESS_TOKEN>");
27+
* });
28+
*/
29+
public customError?: any;
30+
31+
/**
32+
* @public
33+
* @static
34+
* @async
35+
* To set the GraphClientError object
36+
* @param {any} - The error returned encountered by the Graph JavaScript Client SDK while processing request
37+
* @returns GraphClientError object set to the error passed
38+
*/
39+
public static setGraphClientError(error: any): GraphClientError {
40+
let graphClientError: GraphClientError;
41+
if (error instanceof Error) {
42+
graphClientError = error;
43+
} else {
44+
graphClientError = new GraphClientError();
45+
graphClientError.customError = error;
46+
}
47+
return graphClientError;
48+
}
49+
50+
/**
51+
* @public
52+
* @constructor
53+
* Creates an instance of GraphClientError
54+
* @param {string} message? - Error message
55+
* @returns An instance of GraphClientError
56+
*/
57+
public constructor(message?: string) {
58+
super(message);
59+
Object.setPrototypeOf(this, GraphClientError.prototype);
60+
}
61+
}

src/GraphError.ts

+2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ export class GraphError extends Error {
5757
*/
5858
public constructor(statusCode: number = -1, message?: string, baseError?: Error) {
5959
super(message || (baseError && baseError.message));
60+
// https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work
61+
Object.setPrototypeOf(this, GraphError.prototype);
6062
this.statusCode = statusCode;
6163
this.code = null;
6264
this.requestId = null;

src/GraphErrorHandler.ts

+23-9
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,20 @@
1212
import { GraphError } from "./GraphError";
1313
import { GraphRequestCallback } from "./IGraphRequestCallback";
1414

15+
/**
16+
* @interface
17+
* Signature for the json represent of the error response from the Graph API
18+
* https://docs.microsoft.com/en-us/graph/errors
19+
* @property {[key: string] : string | number} - The Key value pair
20+
*/
21+
interface GraphAPIErrorResponse {
22+
error: {
23+
code: string;
24+
message: string;
25+
innerError: any;
26+
};
27+
}
28+
1529
/**
1630
* @class
1731
* Class for GraphErrorHandler
@@ -41,7 +55,7 @@ export class GraphErrorHandler {
4155
* @static
4256
* @async
4357
* Populates the GraphError instance from the Error returned by graph service
44-
* @param {any} error - The error returned by graph service or some native error
58+
* @param {GraphAPIErrorResponse} graphError - The error possibly returned by graph service or some native error
4559
* @param {number} statusCode - The status code of the response
4660
* @returns A promise that resolves to GraphError instance
4761
*
@@ -57,19 +71,17 @@ export class GraphErrorHandler {
5771
* }
5872
* }
5973
*/
60-
private static constructErrorFromResponse(error: any, statusCode: number): GraphError {
61-
error = error.error;
74+
private static constructErrorFromResponse(graphError: GraphAPIErrorResponse, statusCode: number): GraphError {
75+
const error = graphError.error;
6276
const gError = new GraphError(statusCode, error.message);
6377
gError.code = error.code;
6478
if (error.innerError !== undefined) {
6579
gError.requestId = error.innerError["request-id"];
6680
gError.date = new Date(error.innerError.date);
6781
}
68-
try {
69-
gError.body = JSON.stringify(error);
70-
} catch (error) {
71-
// tslint:disable-line: no-empty
72-
}
82+
83+
gError.body = JSON.stringify(error);
84+
7385
return gError;
7486
}
7587

@@ -78,6 +90,7 @@ export class GraphErrorHandler {
7890
* @static
7991
* @async
8092
* To get the GraphError object
93+
* Reference - https://docs.microsoft.com/en-us/graph/errors
8194
* @param {any} [error = null] - The error returned by graph service or some native error
8295
* @param {number} [statusCode = -1] - The status code of the response
8396
* @param {GraphRequestCallback} [callback] - The graph request callback function
@@ -87,10 +100,11 @@ export class GraphErrorHandler {
87100
let gError: GraphError;
88101
if (error && error.error) {
89102
gError = GraphErrorHandler.constructErrorFromResponse(error, statusCode);
90-
} else if (typeof Error !== "undefined" && error instanceof Error) {
103+
} else if (error instanceof Error) {
91104
gError = GraphErrorHandler.constructError(error, statusCode);
92105
} else {
93106
gError = new GraphError(statusCode);
107+
gError.body = error; // if a custom error is passed which is not instance of Error object or a graph API response
94108
}
95109
if (typeof callback === "function") {
96110
callback(gError, null);

src/GraphRequest.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
/**
99
* @module GraphRequest
1010
*/
11-
11+
import { GraphClientError } from "./GraphClientError";
1212
import { GraphError } from "./GraphError";
1313
import { GraphErrorHandler } from "./GraphErrorHandler";
1414
import { oDataQueryNames, serializeContent, urlJoin } from "./GraphRequestUtil";
@@ -379,8 +379,12 @@ export class GraphRequest {
379379
const response: any = await GraphResponseHandler.getResponse(rawResponse, this._responseType, callback);
380380
return response;
381381
} catch (error) {
382+
if (error instanceof GraphClientError) {
383+
throw error;
384+
}
382385
let statusCode: number;
383-
if (typeof rawResponse !== "undefined") {
386+
387+
if (rawResponse) {
384388
statusCode = rawResponse.status;
385389
}
386390
const gError: GraphError = await GraphErrorHandler.getError(error, statusCode, callback);

src/GraphRequestUtil.ts

+32-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
/**
99
* @module GraphRequestUtil
1010
*/
11-
11+
import { GRAPH_URLS } from "./Constants";
1212
/**
1313
* To hold list of OData query params
1414
*/
@@ -58,3 +58,34 @@ export const serializeContent = (content: any): any => {
5858
}
5959
return content;
6060
};
61+
62+
/**
63+
* Checks if the url is one of the service root endpoints for Microsoft Graph and Graph Explorer.
64+
* @param {string} url - The url to be verified
65+
* @returns {boolean} - Returns true if the url is a Graph URL
66+
*/
67+
export const isGraphURL = (url: string): boolean => {
68+
// Valid Graph URL pattern - https://graph.microsoft.com/{version}/{resource}?{query-parameters}
69+
// Valid Graph URL example - https://graph.microsoft.com/v1.0/
70+
url = url.toLowerCase();
71+
72+
if (url.indexOf("https://") !== -1) {
73+
url = url.replace("https://", "");
74+
75+
// Find where the host ends
76+
const startofPortNoPos = url.indexOf(":");
77+
const endOfHostStrPos = url.indexOf("/");
78+
let hostName = "";
79+
if (endOfHostStrPos !== -1) {
80+
if (startofPortNoPos !== -1 && startofPortNoPos < endOfHostStrPos) {
81+
hostName = url.substring(0, startofPortNoPos);
82+
return GRAPH_URLS.has(hostName);
83+
}
84+
// Parse out the host
85+
hostName = url.substring(0, endOfHostStrPos);
86+
return GRAPH_URLS.has(hostName);
87+
}
88+
}
89+
90+
return false;
91+
};

src/Version.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
* @module Version
1313
*/
1414

15-
export const PACKAGE_VERSION = "2.1.0-Preview.2";
15+
export const PACKAGE_VERSION = "2.2.0-Preview.1";

src/middleware/RedirectHandler.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ export class RedirectHandler implements Middleware {
202202
} else {
203203
const redirectUrl: string = this.getLocationHeader(response);
204204
if (!this.isRelativeURL(redirectUrl) && this.shouldDropAuthorizationHeader(response.url, redirectUrl)) {
205-
setRequestHeader(context.request, context.options, RedirectHandler.AUTHORIZATION_HEADER, undefined);
205+
delete context.options.headers[RedirectHandler.AUTHORIZATION_HEADER];
206206
}
207207
await this.updateRequestUrl(redirectUrl, context);
208208
}

0 commit comments

Comments
 (0)