DEV Community

Kenichiro Nakamura
Kenichiro Nakamura

Posted on

2

Identify which request failed in Microsoft Graph Batch request

Microsoft Graph provides Batch request feature which saves network round trips to improve performance.

We can include different types of requests, such as GET/POST/DELETE or resources such as Users/Groups/Events, etc.

Even though this is useful, it could be difficult to identify the reason why some of the request has been failed depending on the request type.

Example Scenario

If we request batch to remove users from a group, for example, it will fail if the user is not part of the group. However, the error message does not give us information about which user id was failed to remove.

This is the error when the request fails.

"error": {
    "code": "Request_ResourceNotFound",
    "message": "Resource 'be24f653-c890-454c-a465-0297c3de2fc2' does not exist or one of its queried reference-property objects are not present.",
    "innerError": {
        "date": "2022-10-03T04:06:29",
        "request-id": "af2627a2-428d-4061-bb3a-00247e8589cc",
        "client-request-id": "e03aab35-0657-c9e2-6703-c38debae955c"
    }
}
Enter fullscreen mode Exit fullscreen mode

In such case, we need to know actual request itself to know user id.

Unique Request Id in batch

We need to add BatchRequestStep list to batch request, and each BatchRequestStep has RequestId property. This id will be part of response.

Sample code

Following sample explain how to check response as well as request. I only added two requests for simplify the code, but we can add more. We can set any unique request id, so I used user id here, which I use to show in console as user id.

The Key of batch response is corresponding to request id.

using Microsoft.Graph;
using Microsoft.Identity.Client;
using System.Net;
using System.Net.Http.Headers;

string tenantId = "tenantId";
string clientId = "clientId";
string clientSecret = "clientSecret";
string baseUrl = "https://graph.microsoft.com/v1.0";
IConfidentialClientApplication app = 
    ConfidentialClientApplicationBuilder
    .Create(clientId)
    .WithClientSecret(clientSecret)
    .WithAuthority(new Uri($"https://login.microsoftonline.com/{tenantId}"))
    .Build();

string[] scopes = new[] { "https://graph.microsoft.com/.default" };

AuthenticationResult authenticationResult = 
    await app.AcquireTokenForClient(scopes).ExecuteAsync();

GraphServiceClient graphClient = new (
    new DelegateAuthenticationProvider(r => {
        r.Headers.Authorization =
            new AuthenticationHeaderValue(
                "bearer", authenticationResult.AccessToken);
        return Task.FromResult(0);
    }));

List<User> users = new();
BatchRequestContent batchRequestContent = new();
string groupId = "the groupId";
string memberId1 = "the memberId1";
batchRequestContent.AddBatchRequestStep(
    new BatchRequestStep(
        memberId1,
        new HttpRequestMessage(
            HttpMethod.Delete,
            $"{baseUrl}/groups/{groupId}/members/{memberId1}/$ref")
        )
    );
string memberId2 = "the memberId2";
batchRequestContent.AddBatchRequestStep(
    new BatchRequestStep(
        memberId2,
        new HttpRequestMessage(
            HttpMethod.Delete,
            $"{baseUrl}/groups/{groupId}/members/{memberId2}/$ref")
        )
    );

BatchResponseContent batchResponseContent = 
    await graphClient.Batch.Request().PostAsync(batchRequestContent);

foreach(KeyValuePair<string, HttpResponseMessage> response 
    in await batchResponseContent.GetResponsesAsync())
{
    if(response.Value.StatusCode != HttpStatusCode.OK)
    {
        BatchRequestStep requestStep = batchRequestContent.BatchRequestSteps[response.Key];
        Console.WriteLine($"StatusCode: {response.Value.StatusCode}");
        Console.WriteLine($"Request URI: {requestStep.Request.RequestUri}");
        Console.WriteLine($"Failed user: {requestStep.RequestId}");
    }
}
Enter fullscreen mode Exit fullscreen mode

Summary

Batch is really useful feature for Microsoft Graph, so please try to use it as much as possible. For unit testing the batch request, I have another post here

Do your career a big favor. Join DEV. (The website you're on right now)

It takes one minute, it's free, and is worth it for your career.

Get started

Community matters

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Explore a sea of insights with this enlightening post, highly esteemed within the nurturing DEV Community. Coders of all stripes are invited to participate and contribute to our shared knowledge.

Expressing gratitude with a simple "thank you" can make a big impact. Leave your thanks in the comments!

On DEV, exchanging ideas smooths our way and strengthens our community bonds. Found this useful? A quick note of thanks to the author can mean a lot.

Okay