Skip to content

Commit 11429d8

Browse files
Adds SDK suggestion in the proxy output
1 parent ad66320 commit 11429d8

File tree

2 files changed

+166
-1
lines changed

2 files changed

+166
-1
lines changed

msgraph-chaos-proxy/ChaosEngine.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,12 @@ private void HandleGraphRequest(SessionEventArgs e) {
213213
}
214214

215215
FailResponse(e, responseComponents, failMode);
216-
216+
if (!IsSdkRequest(e.HttpClient.Request)) {
217+
var color = Console.ForegroundColor;
218+
Console.ForegroundColor = ConsoleColor.Green;
219+
Console.Error.WriteLine($"\tTIP: To handle API errors more easily, use the Graph SDK. More info at {GetMoveToSdkUrl(e.HttpClient.Request)}");
220+
Console.ForegroundColor = color;
221+
}
217222
}
218223
if (!responseComponents.ResponseIsComplete)
219224
UpdateProxyResponse(e, responseComponents, matchingResponse);
@@ -231,6 +236,15 @@ private void FailResponse(SessionEventArgs e, ResponseComponents r, FailMode fai
231236
}
232237
}
233238

239+
private static bool IsSdkRequest(Request request) {
240+
return request.Headers.HeaderExists("SdkVersion");
241+
}
242+
243+
private static string GetMoveToSdkUrl(Request request) {
244+
// TODO: return language-specific guidance links based on the language detected from the User-Agent
245+
return "https://aka.ms/move-to-graph-js-sdk";
246+
}
247+
234248
private static void ProcessMockResponse(SessionEventArgs e, ResponseComponents responseComponents, ChaosProxyMockResponse matchingResponse) {
235249
if (matchingResponse.ResponseCode is not null) {
236250
responseComponents.ErrorStatus = (HttpStatusCode)matchingResponse.ResponseCode;
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# Move to the Graph JavaScript SDK
2+
3+
The Microsoft Graph JavaScript SDK comes with features that will simplify your code and let you focus on building your app. The SDK not only helps you handle API errors but also makes it easier for you to perform complex API operations like batch requests.
4+
5+
## Migrate from fetch to the Graph JavaScript SDK
6+
7+
If you use the fetch API to call APIs in your JavaScript app, you might have code similar to following:
8+
9+
```javascript
10+
const msalClient = new msal.PublicClientApplication({
11+
auth: {
12+
clientId: appId
13+
}
14+
});
15+
16+
function getAccessToken(msalClient) {
17+
const accounts = msalClient.getAllAccounts();
18+
19+
if (accounts.length > 0) {
20+
const accessTokenRequest = {
21+
scopes: [
22+
'https://graph.microsoft.com/User.Read'
23+
],
24+
account: accounts[0]
25+
};
26+
27+
return msalClient.acquireTokenSilent(accessTokenRequest)
28+
.then(response => response.accessToken)
29+
.catch(error => {
30+
console.log(error);
31+
console.log("silent token acquisition fails. acquiring token using redirect");
32+
if (error instanceof msal.InteractionRequiredAuthError) {
33+
return msalClient.acquireTokenRedirect(accessTokenRequest);
34+
}
35+
});
36+
}
37+
else {
38+
return Promise.reject('Sign in');
39+
}
40+
}
41+
42+
msalClient
43+
.loginPopup()
44+
.then(response => getAccessToken(msalClient))
45+
.then(accessToken => fetch('https://graph.microsoft.com/v1.0/me', {
46+
method: 'GET',
47+
headers: {
48+
authorization: `Bearer ${accessToken}`
49+
}
50+
}))
51+
.then(response => response.json())
52+
.then(json => {
53+
// do something here
54+
});
55+
```
56+
57+
To use the Graph JavaScript SDK, you'd change the code to:
58+
59+
```javascript
60+
const msalClient = new msal.PublicClientApplication({
61+
auth: {
62+
clientId: appId
63+
}
64+
});
65+
66+
function getGraphClient(account) {
67+
const authProvider = new MSGraphAuthCodeMSALBrowserAuthProvider.AuthCodeMSALBrowserAuthenticationProvider(msalClient, {
68+
account,
69+
scopes: [
70+
'https://graph.microsoft.com/User.Read'
71+
],
72+
interactionType: msal.InteractionType.Popup,
73+
});
74+
75+
return MicrosoftGraph.Client.initWithMiddleware({ authProvider });
76+
}
77+
78+
msalClient
79+
.loginPopup()
80+
.then(response => {
81+
const accounts = msalClient.getAllAccounts();
82+
83+
if (accounts.length > 0) {
84+
const graphClient = getGraphClient(accounts[0]);
85+
return graphClient.api('/me').get();
86+
}
87+
else {
88+
return Promise.reject('Sign in');
89+
}
90+
})
91+
.then(json => {
92+
// do something here
93+
});
94+
```
95+
96+
## Handle API errors
97+
98+
One of the most common API errors that applications using Microsoft Graph experience when used at scale is throttling. It occurs, when the server is under heavy load and it's meant to decrease the load to keep the service up.
99+
100+
Since throttling rarely occurs on developer tenants, often developers call the API without properly handling errors:
101+
102+
```javascript
103+
fetch('https://graph.microsoft.com/v1.0/me', {
104+
method: 'GET',
105+
headers: {
106+
authorization: `Bearer ${accessToken}`
107+
}
108+
})
109+
.then(response => response.json())
110+
.then(json => {
111+
// do something here
112+
});
113+
```
114+
115+
The proper way to handle throttling errors with fetch API would be to extend the call to watch out for 429 throttling errors and wait before calling the API again for the number of seconds designated in the `retry-after` response header. Updated code would look as follows:
116+
117+
```javascript
118+
function sleep(milliseconds) {
119+
return new Promise((resolve) => setTimeout(resolve, milliseconds));
120+
}
121+
122+
async function fetchAndRetryIfNecessary(callAPIFn) {
123+
const response = await callAPIFn();
124+
125+
if (response.status === 429) {
126+
const retryAfter = response.headers.get('retry-after');
127+
await sleep(retryAfter * 1000);
128+
return fetchAndRetryIfNecessary(callAPIFn);
129+
}
130+
131+
return response;
132+
}
133+
134+
const response = await fetchAndRetryIfNecessary(async () => (
135+
await fetch('https://graph.microsoft.com/v1.0/me', {
136+
method: 'GET',
137+
headers: {
138+
authorization: `Bearer ${accessToken}`
139+
}
140+
})
141+
));
142+
const json = await response.json();
143+
// do something here
144+
```
145+
146+
An easier way to handle throttling, and other errors, is to use the Graph JavaScript SDK, which handles errors for you.
147+
148+
```javascript
149+
const json = await graphClient.api('/me').get();
150+
// do something here
151+
```

0 commit comments

Comments
 (0)