Query Microsoft Fabric GraphQL API from an External App

By:   |   Updated: 2024-09-24   |   Comments   |   Related: > Microsoft Fabric


Problem

We would like to query data from a Microsoft Fabric workspace from a C# application. The user needs to be able to log in and be presented with some data. Is there a straightforward way to do this?

Solution

In the tip What is the API for GraphQL in Microsoft Fabric?, we introduced the Microsoft Fabric GraphQL API. We explained how you can enable this API on top of your lakehouse or warehouse tables and how you can write a sample query to retrieve data:

query run in graphql editor

This tip will show you how to execute the same query from an external application, introducing new opportunities for data sharing or exposing data through custom code. There are other ways to create this process:

We'll walk through the steps of a C# code example.

Prerequisites

To query a Microsoft GraphQL API, we need a Fabric-enabled workspace where one or more tables (from a lakehouse, warehouse, or mirrored database) are exposed through GraphQL. The tip, What is the API for GraphQL in Microsoft Fabric? explains how to set up this workspace.

Next, we need to create a Microsoft Entra app. In the Azure Portal, go to Entra ID (formerly Azure Active Directory) and navigate to App registrations.

entra id app registrations

Create a new registration. Specify a name and configure that only accounts of the current organizational directory can use the application. For the redirect URI, use http://localhost:3000 (make sure Single-page application (SPA) is selected).

configure new app registration

Once the app is created, go to the API permissions section:

go to api permissions

Once the app registration is created, you will be taken to the Overview page, where you can find the client ID and the tenant ID. Both will be needed later in our C# script.

Click Add a permission.

API permissions

In the Request API permissions section, click Power BI Service.

power bi permissions

Next, select Delegated permissions.

delegated permissions

From the list, select the Item.Execute.All and Datamart.ReadWrite.All permissions.

select necessary permissions from the list

You should have the following screen for the API permissions:

configured app permissions

In the Manage > Authentication section, verify that the app is enabled for the Authorization Code Flow with PKCE.

verify grant type in authentication

In the Advanced Settings, enable mobile and desktop flows.

enable mobile and desktop flows

Creating the C# App

The screenshots in this tip are taken using Visual Studio Community Edition, but you can use Visual Studio Code as well. In Visual Studio, create a new project with the template Empty Project (.NET Framework). Click Next.

create new project in visual studio

Give the project a name and choose a location to save it. Click Create.

configure project

Once the project is created, add a C# class to it:

add a class to the C# project

The backbone of the C# script has the following structure:

using System;
using Microsoft.Identity.Client;
using GraphQL.Client.Http;
using GraphQL.Client.Serializer.Newtonsoft;
 
namespace AzureADAuthApp
{
    class Program
    {
        private const string ClientId = "myclientID";  // This is your Application ID from Entra App Registration
        private const string TenantId = "mytenantID";  // This is your Tenant ID from Entra App Registration
        private const string Authority = "https://login.microsoftonline.com/" + TenantId;
        private const string GraphQLUri = "https://api.fabric.microsoft.com/v1/workspaces/workspaceID/graphqlapis/someguid/graphql"; // This is your GraphQL API endpoint
 
        static async System.Threading.Tasks.Task Main(string[] args)
        {
    …
        }
    }
}

There are three inputs needed to make the script work in the end:

  • The ClientID of the app registration we created in the previous section.
  • The TenantID of the tenant where your app registration and Fabric workspace resides.
  • The URL to the GraphQL API in Fabric.

The URL can be found in the Fabric workspace in the GraphQL editor by clicking Copy endpoint.

Copy endpoint

We need the Microsoft.Identity.Client package to authenticate against Entra ID, and the GraphQL.Client packages to send a query to the Fabric GraphQL API. Right-click on References and select Manage NuGet Packages…

add packages to the project

Add the Microsoft.Identity.Client package to the project.

add identity package

Install the latest available version:

install latest version

Accept any licenses if necessary:

accept licenses

Next, add the GraphQL.Client package to the project, as well as the GraphQL.Client.Serializer.Newtonsoft package using the same steps:

install graphql libraries

Inside the Main method, the following code will fetch a token from Azure using an interactive prompt. This means you need to log in with your password every time you run this application and potentially go through MFA authentication as well.

var app = PublicClientApplicationBuilder.Create(ClientId)
   .WithAuthority(Authority)
   .WithRedirectUri("http://localhost:1234")
   .Build();
 
var scopes = new[] { "https://analysis.windows.net/powerbi/api/.default" };
 
try
{
   var result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();
   if (result != null)
   {
        Console.WriteLine("Authentication Success");
        // graphql code comes here                    
   }
}
catch (MsalServiceException ex)
{
   Console.WriteLine($"Authentication Error: {ex.Message}");
}

If you run the code, you will be prompted to sign in:

sign into your account

You need to sign in with a user with at least a contributor role to the workspace. The first time running the code with the app registration may require you to grant the app registration permissions:

grant consent

It's also possible the app will return an error when trying to log in: "Tokens issued for the ‘Single-Page Application' client-type may only be redeemed via cross-origin requests."

authentication error

If this is the case, we need to make adjustments to the app registration. In the Authentication pane, click on Add a platform.

add a new platform for authentication

From the list, select Mobile and desktop applications.

add mobile and desktop app platform

Configure a redirect URI. The documentation suggests using the same URL as the single-page application (as mentioned in step 10).

configure redirect URI

However, this results in an error:

other redirect URI

In my case, I opted for the redirect URI http://localhost:1234. Now the authentication process should work, and a message should be printed as output for success:

authentication success

The code that deals with the GraphQL request looks like this:

var graphQLClient = new GraphQLHttpClient(GraphQLUri, new NewtonsoftJsonSerializer());
 
graphQLClient.HttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", result.AccessToken);
 
var query = new GraphQLHttpRequest
  {
   Query = @"  query {
               dimension_employees (first: 10) {
                 items {
                   Employee
                  ,IsSalesperson
                 }
               }
              }"
  };
 
var graphQLResponse = await graphQLClient.SendQueryAsync<dynamic>(query);
 
Console.WriteLine(graphQLResponse.Data.ToString());

We're using the same GraphQL query as the one used in the previous tip. Note: Running the code for the first time might take some time to return the result of the GraphQL query, as the warehouse (or lakehouse) needs to "warm up."

However, at the time of writing, the code will throw an exception.

code throws an exception

The HTTP code is OK, which means the GraphQL request itself was successful. But, something went wrong when handling the data returned. The details show that the results from the query are returned in JSON format:

content contains the json we need

We can wrap the call to the GraphQL API in a try-catch block to investigate further by catching the exception of type GraphQLHttpRequestException.

try
{
   var graphQLResponse = await graphQLClient.SendQueryAsync<dynamic>(query);
}
catch (GraphQLHttpRequestException ex)
{
   Console.WriteLine(ex.Message);
   Console.WriteLine(ex.Content.ToString());
   //Console.WriteLine(graphQLResponse.Data.ToString());
}

By accessing the Content property of the exception, we can get to the actual data:

data is returned in the exception

When stepping through all the code with the debugger (including the code from the GraphQL.Client package), we can find the culprit:

A screenshot of a computer&#xA;&#xA;Description automatically generated

The HTTP response from the Fabric GraphQL API has the content type set to text/plain instead of application/json. This content type is not supported by the GraphQL.Client library. It seems to be a bug on the Microsoft side. There are two options to proceed further:

  • Change the code to another GraphQL library that doesn't have a problem with the content type.
  • Handle the data in the catch block (not recommended).

This tip serves as proof of concept for accessing Fabric data through GraphQL. The concepts have been demonstrated, but unfortunately, the code is not production-ready at the time of writing.

Next Steps


sql server categories

sql server webinars

subscribe to mssqltips

sql server tutorials

sql server white papers

next tip



About the author
MSSQLTips author Koen Verbeeck Koen Verbeeck is a seasoned business intelligence consultant at AE. He has over a decade of experience with the Microsoft Data Platform in numerous industries. He holds several certifications and is a prolific writer contributing content about SSIS, ADF, SSAS, SSRS, MDS, Power BI, Snowflake and Azure services. He has spoken at PASS, SQLBits, dataMinds Connect and delivers webinars on MSSQLTips.com. Koen has been awarded the Microsoft MVP data platform award for many years.

This author pledges the content of this article is based on professional experience and not AI generated.

View all my tips


Article Last Updated: 2024-09-24

Comments For This Article

















get free sql tips
agree to terms