As name suggests it comes in middle of something and that is request and response cycle. It has access to context object which contains request, response objects and any other options that are specific to middleware. Also it has an access to execute next middleware in the chain.
Create a custom middleware pipeline by implementing the Middleware interface. The following examples demonstrate how to create a custom logging middleware and how to create a custom http request a response handler.
First middleware is passed with the context object containing request, and other middleware specific options. One has to explicitly make call to execute method of the next middleware with context object once the current middleware work is over.
// MyLoggingHandler.ts
import { Middleware } from "@microsoft/microsoft-graph-client";
import { Context } from "@microsoft/microsoft-graph-client";
export class MyLoggingHandler implements Middleware {
private nextMiddleware: Middleware;
public async execute(context: Context): Promise<void> {
try {
let url: string;
if (typeof context.request === "string") {
url = context.request;
} else {
url = context.request.url;
}
console.log(url);
return await this.nextMiddleware.execute(context);
} catch (error) {
throw error;
}
}
public setNext(next: Middleware): void {
this.nextMiddleware = next;
}
}
Note: Http message handler should set the response object in the context object.
// MyHttpMessageHandler.ts
import { Middleware } from "@microsoft/microsoft-graph-client";
export class MyHttpMessageHandler implements Middleware {
public async execute(context: Context): Promise<void> {
try {
// For more information about context object refer "Context" section below
let response = await fetch(context.request, context.options);
// Set the response back in the context
context.response = response;
return;
} catch (error) {
throw error;
}
}
}
Can use own middlewares and the ones shipped with the library [Here are the set of Middlewares shipped with the library] to create the middleware chain. Create a chain out of these one has to link them in sequentially manner in own preferred order using .setNext()
method.
Using AuthenticationHandler [one shipped with the library] and MyLoggingHandler, and MyHttpMessageHandler [custom ones] to create a middleware chain here.
NOTE: Instead of ImplicitMSALAuthenticationProvider, one can provide their own Authentication Handler. For more about using custom authentication provider, refer here.
import { ImplicitMSALAuthenticationProvider } from "@microsoft/microsoft-graph-client";
import { MyLoggingHandler } from "./MyLoggingHandler";
import { MyHttpMessageHandler } from "./MyHttpMessageHandler";
let authProvider = new ImplicitMSALAuthenticationProvider("<CLIENT_ID>", ["user.read"]);
let authenticationHandler = new AuthenticationHandler(authProvider);
let myLoggingHandler = new MyLoggingHandler();
let myHttpMessageHandler = new MyHttpMessageHandler();
// Note: myHttpMessageHandler is the last in the chain so there is no need of setting next middleware for it.
authenticationHandler.setNext(myLoggingHandler);
myLoggingHandler.setNext(myHttpMessageHandler);
Pass first middleware in the chain for initializing the client.
let clientOptions: ClientOptions = {
middleware: authenticationHandler,
};
const client = Client.initWithMiddleware(clientOptions);
One can pass any middleware specific options or data while initializing the client, this will be available in the context.middlewareOptions
.
let clientOptions: ClientOptions = {
middleware: authenticationHandler,
middlewareOptions: {
loggingPrefix: "MSGraph-Client-Library",
},
};
The above middlewareOptions object will be available in the context object that is being passed to the execute method of a middleware.
// MyLoggingHandler.ts
import { Middleware } from "@microsoft/microsoft-graph-client";
import { Context } from "@microsoft/microsoft-graph-client";
export class MyLoggingHandler implements Middleware {
private nextMiddleware: Middleware;
public async execute(context: Context): Promise<void> {
try {
let url: string;
if (typeof context.request === "string") {
url = context.request;
} else {
url = context.request.url;
}
if (context.middlewareOptions !== undefined && context.middlewareOptions.loggingPrefix !== undefined) {
console.log(`${context.middlewareOptions.loggingPrefix}: ${url}`);
} else {
console.log(url);
}
await this.nextMiddleware.execute(context);
} catch (error) {
throw error;
}
}
public setNext(next: Middleware): void {
this.nextMiddleware = next;
}
}
Refer MiddlewareOptions interface to know its structure.