Skip to content

Commit 96b40bd

Browse files
authored
Merge pull request #353 from microsoftgraph/nikitha/graph-clientside-error
Empty error reported in the SDK
2 parents 4ffbc1d + 386aae3 commit 96b40bd

6 files changed

+177
-13
lines changed

spec/core/Client.ts

+43
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import "isomorphic-fetch";
1010

1111
import { CustomAuthenticationProvider, TelemetryHandler } from "../../src";
1212
import { Client } from "../../src/Client";
13+
import { GraphClientError } from "../../src/GraphClientError";
1314
import { AuthProvider } from "../../src/IAuthProvider";
1415
import { ClientOptions } from "../../src/IClientOptions";
1516
import { Options } from "../../src/IOptions";
@@ -101,6 +102,48 @@ describe("Client.ts", () => {
101102
const response = await client.api("me").get();
102103
assert.equal(response, responseBody);
103104
});
105+
106+
it("Should throw error in case the access token is undefined", async () => {
107+
try {
108+
const options = {
109+
defaultVersion: "v1.0",
110+
debugLogging: true,
111+
authProvider: (done) => {
112+
done(null, getTokenFunction());
113+
},
114+
};
115+
116+
const getTokenFunction = (): string => {
117+
return undefined;
118+
};
119+
const client = Client.init(options);
120+
const res = await client.api("/test").get();
121+
} catch (error) {
122+
assert.isTrue(error instanceof GraphClientError);
123+
assert.isDefined(error.message);
124+
}
125+
});
126+
127+
it("Should throw error in case the access token is empty", async () => {
128+
const customError = { message: "Token is empty" };
129+
try {
130+
const options = {
131+
defaultVersion: "v1.0",
132+
debugLogging: true,
133+
authProvider: (done) => {
134+
done(customError, getTokenFunction());
135+
},
136+
};
137+
const getTokenFunction = (): string => {
138+
return "";
139+
};
140+
const client = Client.init(options);
141+
const res = await client.api("/test").get();
142+
} catch (error) {
143+
assert.isTrue(error instanceof GraphClientError);
144+
assert.equal(error.customError, customError);
145+
}
146+
});
104147
});
105148

106149
describe("init", () => {

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/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/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);

0 commit comments

Comments
 (0)