Skip to content

Commit 5e5d52b

Browse files
authored
Merge pull request #251 from microsoftgraph/nmetulev/basegraph
Updated BaseGraph to always use the same client instance
2 parents 25f759c + 4769440 commit 5e5d52b

File tree

9 files changed

+213
-122
lines changed

9 files changed

+213
-122
lines changed

src/BaseGraph.ts

Lines changed: 75 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
* -------------------------------------------------------------------------------------------
66
*/
77

8-
import { Client, ResponseType } from '@microsoft/microsoft-graph-client';
8+
import { Client, GraphRequest, Middleware, MiddlewareOptions, ResponseType } from '@microsoft/microsoft-graph-client';
99
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
1010
import * as MicrosoftGraphBeta from '@microsoft/microsoft-graph-types-beta';
11-
import { IProvider, prepScopes } from '.';
1211
import { MgtBaseComponent } from './components/baseComponent';
1312
import { Batch } from './utils/Batch';
13+
import { ComponentMiddlewareOptions } from './utils/ComponentMiddlewareOptions';
14+
import { prepScopes } from './utils/GraphHelpers';
1415

1516
/**
1617
* The base Graph implementation.
@@ -29,36 +30,54 @@ export abstract class BaseGraph {
2930
public client: Client;
3031

3132
/**
32-
* a provider used for making calls
33+
* name of a component for analytics
3334
*
3435
* @protected
35-
* @type {IProvider}
36+
* @type {string}
3637
* @memberof BaseGraph
3738
*/
38-
protected _provider: IProvider;
39-
40-
constructor(provider: IProvider) {
41-
this._provider = provider;
42-
}
39+
protected componentName: string;
4340

4441
/**
4542
* Returns a new instance of the Graph using the same
46-
* provider and the provided component.
43+
* client within the context of the provider.
4744
*
4845
* @param {MgtBaseComponent} component
4946
* @returns
5047
* @memberof BaseGraph
5148
*/
5249
public abstract forComponent(component: MgtBaseComponent): BaseGraph;
5350

51+
/**
52+
* Returns a new graph request for a specific component
53+
* Used internally for analytics purposes
54+
*
55+
* @param {string} path
56+
* @param {MgtBaseComponent} [component=null]
57+
* @memberof Graph
58+
*/
59+
public api(path: string): GraphRequest {
60+
let request = this.client.api(path);
61+
if (this.componentName) {
62+
request.middlewareOptions = (options: MiddlewareOptions[]): GraphRequest => {
63+
const requestObj = request as any;
64+
requestObj._middlewareOptions = requestObj._middlewareOptions.concat(options);
65+
return request;
66+
};
67+
request = request.middlewareOptions([new ComponentMiddlewareOptions(this.componentName)]);
68+
}
69+
70+
return request;
71+
}
72+
5473
/**
5574
* creates batch request
5675
*
5776
* @returns
5877
* @memberof BaseGraph
5978
*/
6079
public createBatch() {
61-
return new Batch(this.client);
80+
return new Batch(this.client, this.componentName);
6281
}
6382

6483
/**
@@ -68,8 +87,7 @@ export abstract class BaseGraph {
6887
* @memberof BaseGraph
6988
*/
7089
public async getMe(): Promise<MicrosoftGraph.User> {
71-
return this.client
72-
.api('me')
90+
return this.api('me')
7391
.middlewareOptions(prepScopes('user.read'))
7492
.get();
7593
}
@@ -83,8 +101,7 @@ export abstract class BaseGraph {
83101
*/
84102
public async getUser(userPrincipleName: string): Promise<MicrosoftGraph.User> {
85103
const scopes = 'user.readbasic.all';
86-
return this.client
87-
.api(`/users/${userPrincipleName}`)
104+
return this.api(`/users/${userPrincipleName}`)
88105
.middlewareOptions(prepScopes(scopes))
89106
.get();
90107
}
@@ -98,8 +115,7 @@ export abstract class BaseGraph {
98115
*/
99116
public async findPerson(query: string): Promise<MicrosoftGraph.Person[]> {
100117
const scopes = 'people.read';
101-
const result = await this.client
102-
.api('/me/people')
118+
const result = await this.api('/me/people')
103119
.search('"' + query + '"')
104120
.middlewareOptions(prepScopes(scopes))
105121
.get();
@@ -115,8 +131,7 @@ export abstract class BaseGraph {
115131
*/
116132
public async findContactByEmail(email: string): Promise<MicrosoftGraph.Contact[]> {
117133
const scopes = 'contacts.read';
118-
const result = await this.client
119-
.api('/me/contacts')
134+
const result = await this.api('/me/contacts')
120135
.filter(`emailAddresses/any(a:a/address eq '${email}')`)
121136
.middlewareOptions(prepScopes(scopes))
122137
.get();
@@ -194,8 +209,7 @@ export abstract class BaseGraph {
194209

195210
uri += `/calendarview?${sdt}&${edt}`;
196211

197-
const calendarView = await this.client
198-
.api(uri)
212+
const calendarView = await this.api(uri)
199213
.middlewareOptions(prepScopes(scopes))
200214
.orderby('start/dateTime')
201215
.get();
@@ -212,8 +226,7 @@ export abstract class BaseGraph {
212226
const scopes = 'people.read';
213227

214228
const uri = '/me/people';
215-
const people = await this.client
216-
.api(uri)
229+
const people = await this.api(uri)
217230
.middlewareOptions(prepScopes(scopes))
218231
.filter("personType/class eq 'Person'")
219232
.get();
@@ -231,8 +244,7 @@ export abstract class BaseGraph {
231244
const scopes = 'people.read';
232245

233246
const uri = `/groups/${groupId}/members`;
234-
const people = await this.client
235-
.api(uri)
247+
const people = await this.api(uri)
236248
.middlewareOptions(prepScopes(scopes))
237249
.get();
238250
return people ? people.value : null;
@@ -249,8 +261,7 @@ export abstract class BaseGraph {
249261
const scopes = 'Group.Read.All';
250262

251263
const uri = `/groups/${groupId}/planner/plans`;
252-
const plans = await this.client
253-
.api(uri)
264+
const plans = await this.api(uri)
254265
.header('Cache-Control', 'no-store')
255266
.middlewareOptions(prepScopes(scopes))
256267
.get();
@@ -264,8 +275,7 @@ export abstract class BaseGraph {
264275
* @memberof BaseGraph
265276
*/
266277
public async getAllMyPlannerPlans(): Promise<MicrosoftGraph.PlannerPlan[]> {
267-
const plans = await this.client
268-
.api('/me/planner/plans')
278+
const plans = await this.api('/me/planner/plans')
269279
.header('Cache-Control', 'no-store')
270280
.middlewareOptions(prepScopes('Group.Read.All'))
271281
.get();
@@ -281,8 +291,7 @@ export abstract class BaseGraph {
281291
* @memberof BaseGraph
282292
*/
283293
public async getSinglePlannerPlan(planId: string): Promise<MicrosoftGraph.PlannerPlan> {
284-
const plan = await this.client
285-
.api(`/planner/plans/${planId}`)
294+
const plan = await this.api(`/planner/plans/${planId}`)
286295
.header('Cache-Control', 'no-store')
287296
.middlewareOptions(prepScopes('Group.Read.All'))
288297
.get();
@@ -298,8 +307,7 @@ export abstract class BaseGraph {
298307
* @memberof BaseGraph
299308
*/
300309
public async getBucketsForPlannerPlan(planId: string): Promise<MicrosoftGraph.PlannerBucket[]> {
301-
const buckets = await this.client
302-
.api(`/planner/plans/${planId}/buckets`)
310+
const buckets = await this.api(`/planner/plans/${planId}/buckets`)
303311
.header('Cache-Control', 'no-store')
304312
.middlewareOptions(prepScopes('Group.Read.All'))
305313
.get();
@@ -315,8 +323,7 @@ export abstract class BaseGraph {
315323
* @memberof BaseGraph
316324
*/
317325
public async getTasksForPlannerBucket(bucketId: string): Promise<MicrosoftGraph.PlannerTask[]> {
318-
const tasks = await this.client
319-
.api(`/planner/buckets/${bucketId}/tasks`)
326+
const tasks = await this.api(`/planner/buckets/${bucketId}/tasks`)
320327
.header('Cache-Control', 'no-store')
321328
.middlewareOptions(prepScopes('Group.Read.All'))
322329
.get();
@@ -334,8 +341,7 @@ export abstract class BaseGraph {
334341
* @memberof BaseGraph
335342
*/
336343
public async setPlannerTaskDetails(taskId: string, details: MicrosoftGraph.PlannerTask, eTag: string): Promise<any> {
337-
return await this.client
338-
.api(`/planner/tasks/${taskId}`)
344+
return await this.api(`/planner/tasks/${taskId}`)
339345
.header('Cache-Control', 'no-store')
340346
.middlewareOptions(prepScopes('Group.ReadWrite.All'))
341347
.header('If-Match', eTag)
@@ -405,8 +411,7 @@ export abstract class BaseGraph {
405411
* @memberof BaseGraph
406412
*/
407413
public async addPlannerTask(newTask: MicrosoftGraph.PlannerTask): Promise<any> {
408-
return this.client
409-
.api('/planner/tasks')
414+
return this.api('/planner/tasks')
410415
.header('Cache-Control', 'no-store')
411416
.middlewareOptions(prepScopes('Group.ReadWrite.All'))
412417
.post(newTask);
@@ -421,8 +426,7 @@ export abstract class BaseGraph {
421426
* @memberof BaseGraph
422427
*/
423428
public async removePlannerTask(taskId: string, eTag: string): Promise<any> {
424-
return this.client
425-
.api(`/planner/tasks/${taskId}`)
429+
return this.api(`/planner/tasks/${taskId}`)
426430
.header('Cache-Control', 'no-store')
427431
.header('If-Match', eTag)
428432
.middlewareOptions(prepScopes('Group.ReadWrite.All'))
@@ -438,8 +442,7 @@ export abstract class BaseGraph {
438442
* @memberof BaseGraph
439443
*/
440444
public async getAllMyTodoGroups(): Promise<MicrosoftGraphBeta.OutlookTaskGroup[]> {
441-
const groups = await this.client
442-
.api('/me/outlook/taskGroups')
445+
const groups = await this.api('/me/outlook/taskGroups')
443446
.header('Cache-Control', 'no-store')
444447
.version('beta')
445448
.middlewareOptions(prepScopes('Tasks.Read'))
@@ -456,8 +459,7 @@ export abstract class BaseGraph {
456459
* @memberof BaseGraph
457460
*/
458461
public async getSingleTodoGroup(groupId: string): Promise<MicrosoftGraphBeta.OutlookTaskGroup> {
459-
const group = await this.client
460-
.api(`/me/outlook/taskGroups/${groupId}`)
462+
const group = await this.api(`/me/outlook/taskGroups/${groupId}`)
461463
.header('Cache-Control', 'no-store')
462464
.version('beta')
463465
.middlewareOptions(prepScopes('Tasks.Read'))
@@ -474,8 +476,7 @@ export abstract class BaseGraph {
474476
* @memberof BaseGraph
475477
*/
476478
public async getFoldersForTodoGroup(groupId: string): Promise<MicrosoftGraphBeta.OutlookTaskFolder[]> {
477-
const folders = await this.client
478-
.api(`/me/outlook/taskGroups/${groupId}/taskFolders`)
479+
const folders = await this.api(`/me/outlook/taskGroups/${groupId}/taskFolders`)
479480
.header('Cache-Control', 'no-store')
480481
.version('beta')
481482
.middlewareOptions(prepScopes('Tasks.Read'))
@@ -492,8 +493,7 @@ export abstract class BaseGraph {
492493
* @memberof BaseGraph
493494
*/
494495
public async getAllTodoTasksForFolder(folderId: string): Promise<MicrosoftGraphBeta.OutlookTask[]> {
495-
const tasks = await this.client
496-
.api(`/me/outlook/taskFolders/${folderId}/tasks`)
496+
const tasks = await this.api(`/me/outlook/taskFolders/${folderId}/tasks`)
497497
.header('Cache-Control', 'no-store')
498498
.version('beta')
499499
.middlewareOptions(prepScopes('Tasks.Read'))
@@ -512,8 +512,7 @@ export abstract class BaseGraph {
512512
* @memberof BaseGraph
513513
*/
514514
public async setTodoTaskDetails(taskId: string, task: any, eTag: string): Promise<MicrosoftGraphBeta.OutlookTask> {
515-
return await this.client
516-
.api(`/me/outlook/tasks/${taskId}`)
515+
return await this.api(`/me/outlook/tasks/${taskId}`)
517516
.header('Cache-Control', 'no-store')
518517
.version('beta')
519518
.header('If-Match', eTag)
@@ -570,15 +569,13 @@ export abstract class BaseGraph {
570569
const { parentFolderId = null } = newTask;
571570

572571
if (parentFolderId) {
573-
return await this.client
574-
.api(`/me/outlook/taskFolders/${parentFolderId}/tasks`)
572+
return await this.api(`/me/outlook/taskFolders/${parentFolderId}/tasks`)
575573
.header('Cache-Control', 'no-store')
576574
.version('beta')
577575
.middlewareOptions(prepScopes('Tasks.ReadWrite'))
578576
.post(newTask);
579577
} else {
580-
return await this.client
581-
.api('/me/outlook/tasks')
578+
return await this.api('/me/outlook/tasks')
582579
.header('Cache-Control', 'no-store')
583580
.version('beta')
584581
.middlewareOptions(prepScopes('Tasks.ReadWrite'))
@@ -595,15 +592,35 @@ export abstract class BaseGraph {
595592
* @memberof BaseGraph
596593
*/
597594
public async removeTodoTask(taskId: string, eTag: string): Promise<any> {
598-
return await this.client
599-
.api(`/me/outlook/tasks/${taskId}`)
595+
return await this.api(`/me/outlook/tasks/${taskId}`)
600596
.header('Cache-Control', 'no-store')
601597
.version('beta')
602598
.header('If-Match', eTag)
603599
.middlewareOptions(prepScopes('Tasks.ReadWrite'))
604600
.delete();
605601
}
606602

603+
/**
604+
* Helper method to chain Middleware when instantiating new Client
605+
*
606+
* @protected
607+
* @param {...Middleware[]} middleware
608+
* @returns {Middleware}
609+
* @memberof BaseGraph
610+
*/
611+
protected chainMiddleware(...middleware: Middleware[]): Middleware {
612+
const rootMiddleware = middleware[0];
613+
let current = rootMiddleware;
614+
for (let i = 1; i < middleware.length; ++i) {
615+
const next = middleware[i];
616+
if (current.setNext) {
617+
current.setNext(next);
618+
}
619+
current = next;
620+
}
621+
return rootMiddleware;
622+
}
623+
607624
private blobToBase64(blob: Blob): Promise<string> {
608625
return new Promise((resolve, reject) => {
609626
const reader = new FileReader();
@@ -617,8 +634,7 @@ export abstract class BaseGraph {
617634

618635
private async getPhotoForResource(resource: string, scopes: string[]): Promise<string> {
619636
try {
620-
const blob = await this.client
621-
.api(`${resource}/photo/$value`)
637+
const blob = await this.api(`${resource}/photo/$value`)
622638
.version('beta')
623639
.responseType(ResponseType.BLOB)
624640
.middlewareOptions(prepScopes(...scopes))

0 commit comments

Comments
 (0)