Easily debug Microsoft Graph JavaScript SDK requests


Using the Microsoft Graph JavaScript SDK is a convenient way to connect your app to Microsoft 365. Here’s how you can easily debug API requests issued from the SDK.

Build apps that work with Microsoft 365

Microsoft 365 is a platform where millions of users collaborate every day. You can create apps that use the data and insights from Microsoft 365 to help them work more efficiently and effectively.

Microsoft Graph is the API that connects you to your organization’s data in Microsoft 365. You can interact with it using its REST endpoints. If you build an app connected to Microsoft 365 using JavaScript, you should consider using the Microsoft Graph JavaScript SDK. The SDK simplifies authentication and handles complex scenarios like backing off when throttled, following redirects and uploading large files, which means that you can focus on building your app instead of its plumbing!

Use the Microsoft Graph JavaScript SDK to connect your JavaScript app to Microsoft 365

To begin using the Microsoft Graph JavaScript SDK, create a Graph client with an authentication provider. Then, you can start calling Microsoft Graph to access and manipulate data in Microsoft 365.

For building a deamon app, you’d use code similar to following:

import { ClientSecretCredential } from '@azure/identity';
import { Client } from '@microsoft/microsoft-graph-client';
import { TokenCredentialAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials/index.js';

// [...] shortened for brevity

const credential = new ClientSecretCredential(
  tenantId,
  appId,
  secret
);

const authProvider = new TokenCredentialAuthenticationProvider(credential, {
  scopes: ['https://graph.microsoft.com/.default'],
});

const client = Client.initWithMiddleware({ authProvider });

Debug Microsoft Graph JavaScript SDK API requests

When you start building your app, it can happen that you’ll get an error calling Microsoft Graph. Looking at the returned error information should give you a clearer idea of what’s wrong and how to fix it.

If that’s not the case though, and you need to see the request and response that goes over the wire, here’s a trick that you can use.

Microsoft Graph JavaScript SDK middleware

The Microsoft Graph JavaScript SDK supports the concept of middleware: functions that run as part of its request- and response pipeline and have access to the information about the outgoing request and received response. If you want to inspect API requests and responses issued by the Microsoft Graph JavaScript SDK, building a custom middleware is the easiest way about it. Middleware has access to the full request context information which includes information about the outgoing request and received response.

Debug middleware for Microsoft Graph JavaScript SDK

Start, with creating a new file named debugMiddleware.js. Add the following code:

export function DebugMiddleware() {
  this.nextMiddleware = undefined;

  const getHeaders = (headers) => {
    const h = {};
    for (var header of headers.entries()) {
      h[header[0]] = header[1];
    }
    return h;
  };

  return {
    execute: async (context) => {
      console.debug('');
      console.debug(`Request: ${context.request}`);
      console.debug(JSON.stringify(context.options, null, 2));

      await this.nextMiddleware.execute(context);

      const resp = context.response.clone();

      const headers = getHeaders(resp.headers);
      console.debug('');
      console.debug('Response headers:');
      console.debug(JSON.stringify(headers, null, 2));
      if (headers.hasOwnProperty('content-type') &&
        headers['content-type'].startsWith('application/json') &&
        resp.body) {
        console.debug('');
        console.debug('Response body:');
        console.debug(JSON.stringify(await resp.json(), null, 2));
      }
    },
    setNext: (next) => {
      this.nextMiddleware = next;
    }
  }
}

The function follows the Microsoft Graph JavaScript SDK middleware pattern and creates a new object with two methods: execute, which runs the middleware, and setNext, which defines the next middleware in chain.

When this function runs as part of the client’s middleware, it will first log information about the outgoing request. Then, it will call the next middleware in chain and wait for its execution. This is where the actual API request will be executed. Finally, it will clone the received response, print response headers, and if suitable, the response body.

Use the debug middleware

The last step is to add the debug middleware to the Graph client. To do that, update the client’s initiation code as follows:

import { ClientSecretCredential } from '@azure/identity';
import { Client, MiddlewareFactory } from '@microsoft/microsoft-graph-client';
import { TokenCredentialAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials/index.js';
import { DebugMiddleware } from './debugMiddleware.js';

// [...] shortened for brevity

const credential = new ClientSecretCredential(
  tenantId,
  appId,
  secret
);

const authProvider = new TokenCredentialAuthenticationProvider(credential, {
  scopes: ['https://graph.microsoft.com/.default'],
});

const middleware = MiddlewareFactory.getDefaultMiddlewareChain(authProvider);
// add just before executing the request to get access to all headers
middleware.splice(-1, 0, new DebugMiddleware());

const client = Client.initWithMiddleware({ middleware });

We changed the Graph client instantiation code, to get the default middleware chain, which includes authentication, handling throttling and ends with issuing the web request. For debugging to have access to all request and response information, we need to insert it before the last middleware, which is the HTTP client.

With this setup in place, when you call Microsoft Graph using the client, you’ll see the following output in the console:

Request: https://graph.microsoft.com/v1.0/me
{
  "method": "GET",
  "headers": {
    "Authorization": "Bearer eyJ0eXAiOiJKV...",
    "client-request-id": "303c13f7-69c6-7f29-3982-7306ca0bfd62",
    "SdkVersion": "graph-js/3.0.6 (featureUsage=7)"
  },
  "redirect": "manual"
}

Response headers:
{
  "cache-control": "no-cache",
  "client-request-id": "303c13f7-69c6-7f29-3982-7306ca0bfd62",
  "connection": "close",
  "content-encoding": "gzip",
  "content-type": "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8",
  "date": "Mon, 04 Sep 2023 14:46:22 GMT",
  "odata-version": "4.0",
  "request-id": "2547335a-54cb-4688-909b-5e8d65f4ff65",
  "strict-transport-security": "max-age=31536000",
  "transfer-encoding": "chunked",
  "vary": "Accept-Encoding",
  "x-ms-ags-diagnostic": "{\"ServerInfo\":{\"DataCenter\":\"West Europe\",\"Slice\":\"E\",\"Ring\":\"5\",\"ScaleUnit\":\"004\",\"RoleInstance\":\"AM2PEPF0001C25B\"}}",
  "x-ms-resource-unit": "1"
}

Response body:
{
  "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
  "businessPhones": [
    "4258828080"
  ],
  "displayName": "Waldek Mastykarz",
  "givenName": "Waldek",
  "jobTitle": "Developer Advocate",
  "mail": "waldek@2czk3g.onmicrosoft.com",
  "mobilePhone": null,
  "officeLocation": "Netherlands",
  "preferredLanguage": "en-GB",
  "surname": "Mastykarz",
  "userPrincipalName": "waldek@2czk3g.onmicrosoft.com",
  "id": "9da37739-ad63-42aa-b0c2-06f7b43e3e9e"
}

Summary

Using the Microsoft Graph JavaScript SDK is an easy way for you to get the data and insights from Microsoft 365 in your app. The SDK simplifies authentication and handles complex API scenarios for you. If you ever need to debug the requests and responses handled by the SDK, you can build a simple debug middleware to log the raw requests and responses for you.

Others found also helpful: