# Microsoft Fabric REST API's

Microsoft Fabric provides a rich set of API's that can be utilized to automate majority of the task required to maintain your Fabric tenant. With Fabric API's, you could automate the process to create/update/delete Notebooks, ML experiments, Semantic models, Warehouses, list SQL Endpoints and tons of other stuff.

The exhaustive list of the API's is available here : [Microsoft Fabric REST APIs](https://learn.microsoft.com/en-us/rest/api/fabric/articles/).

In this post we would see on ways to leverage Fabric API's to perform the following tasks:

* *Create a Lakehouse*
    
* *Move files into the lakehouse as tables. Note that at the time of this writing there isn't any API available to perform external data load into a lakehouse.*
    
* *Create OneLake shortcut from an Azure ADLS2 location*
    
* *Create OneLake shortcut between two different lakehouses*
    

### The Setup

To get started you need to register the application at [https://entra.microsoft.com](https://entra.microsoft.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/Overview/quickStartType~/null/sourceType/Microsoft_AAD_IAM/appId/ad53ea30-aa6b-4232-a596-b00f31920145/objectId/1d59f9c6-36a8-43f3-a862-32e7d087ddde/isMSAApp~/false/defaultBlade/Overview/appSignInAudience/AzureADMyOrg/servicePrincipalCreated~/true)

As Microsoft Entra uses MFA(Multi Factor Authentication) you might want to first set that up for your login to work . You can find more details here :

[https://learn.microsoft.com/en-us/entra/identity/authentication/concept-mfa-howitworks](https://learn.microsoft.com/en-us/entra/identity/authentication/concept-mfa-howitworks)

Once logged in, navigate to Applications &gt;&gt;App registrations &gt;&gt; New registration

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1724690897503/35730069-9cfa-438d-b3b5-d15cd01735f7.png align="left")

and register an application

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1724691011600/4519fd9b-8525-4365-8fa1-5f980d6b00e6.png align="center")

I have the named it as : `Fabric API Calls`

Once registered, the application would be assigned an `Application ID, Object ID` and `tenant ID`. We would only require the `Application ID` to be referenced in the code.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1724691324356/225ce188-f91f-44b6-ad3f-cab2afa703f4.png align="center")

### The Code

In a new Console Application add two Nuget packages : `NewtonSoft` and `Microsoft Identity`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1724692866364/c800ed70-1387-4eab-ba11-7be6b3aec478.png align="center")

Next, create a connection to the `ADLS2` storage for the shortcut.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1724693021730/f2af7ec0-ba55-44e9-8212-50a9abba54e9.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1724693515176/724afaa7-9545-4ffb-a1e3-6af22ae7f482.png align="center")

Declare a bunch of static variables under `Program` class in the Console Application.

```csharp
    private static string ClientId = "Cliend Id which we got from registring it in Entra";
    private static string AzureADLSConnection = "Connection Id from the above image marked in red";
    private static string Authority = "https://login.microsoftonline.com/organizations";
    private static string RedirectURI = "http://localhost";
    private static string[] scopes = new string[] { "https://api.fabric.microsoft.com/Workspace.ReadWrite.All https://api.fabric.microsoft.com/Item.ReadWrite.All https://api.fabric.microsoft.com/OneLake.ReadWrite.All" };
    private static string responsename = "";
    private static string workspaceName = "Workspace name";
```

I have declared a variable called `scopes`

`private static string[] scopes = new string[] { "`[`https://api.fabric.microsoft.com/Workspace.ReadWrite.All`](https://api.fabric.microsoft.com/Workspace.ReadWrite.All) [`https://api.fabric.microsoft.com/Item.ReadWrite.All`](https://api.fabric.microsoft.com/Item.ReadWrite.All) [`https://api.fabric.microsoft.com/OneLake.ReadWrite.All`](https://api.fabric.microsoft.com/OneLake.ReadWrite.All)`" };`

Basically scopes defines the level of permissions that are required to perform certain operations across the fabric tenant.  
For example : [`Workspace.ReadWrite.All`](https://api.fabric.microsoft.com/Workspace.ReadWrite.All),[`Item.ReadWrite.All`](https://api.fabric.microsoft.com/Item.ReadWrite.All)[`OneLake.ReadWrite.All`](https://api.fabric.microsoft.com/OneLake.ReadWrite.All), allows to read and write across a workspace, item and OneLake.

Next we create a new class called `MyService` with two generic methods that would perform `GET` and `POST` operations. These operations would use `Bearer` token authentication. You can read more about `Bearer` authentication [here](https://swagger.io/docs/specification/authentication/bearer-authentication/) .

A special shoutout to this article.

[https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/](https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/)

My design of the class `MyService` revolving around the usage of `HTTPClient` was inspired by the above article

In the class `MyService`, as stated earlier has two generic methods for `GET` and `POST`. I have named them as `GetAsync` and `PostAsync`.

```csharp
   public class MyService
   {

       private static readonly HttpClient client = new HttpClient();
       public HttpClient Client => client;
       public async Task<string> GetAsync(string url)
       {


           PublicClientApplicationBuilder PublicClientAppBuilder =
                   PublicClientApplicationBuilder.Create(ClientId)
                   .WithAuthority(Authority)
                   .WithRedirectUri(RedirectURI);

           IPublicClientApplication PublicClientApplication = PublicClientAppBuilder.Build();

           AuthenticationResult result = await PublicClientApplication.AcquireTokenInteractive(scopes)
                                                .ExecuteAsync()
                                               .ConfigureAwait(false);

           Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
           HttpResponseMessage response = await client.GetAsync(url);
           response.EnsureSuccessStatusCode();
           return await response.Content.ReadAsStringAsync();
       }

       public async Task<string> PostAsync(string url, HttpContent content)
       {

           PublicClientApplicationBuilder PublicClientAppBuilder =
                   PublicClientApplicationBuilder.Create(ClientId)
                   .WithAuthority(Authority)
                   .WithRedirectUri(RedirectURI);

           IPublicClientApplication PublicClientApplication = PublicClientAppBuilder.Build();

           AuthenticationResult result = await PublicClientApplication.AcquireTokenInteractive(scopes)
                                                .ExecuteAsync()
                                               .ConfigureAwait(false);

           client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
           HttpResponseMessage response = await client.PostAsync(url, content);
           try
           {
               response.EnsureSuccessStatusCode();
               return await response.Content.ReadAsStringAsync();
           }
           catch
           {
               Console.WriteLine(response.Content.ReadAsStringAsync().Result);
               return null;
           }

       }
   }
```

### Main method in the Console Application

```csharp
static async Task Main(string[] args)
{
    MyService service = new MyService();
    string baseUrl = "https://api.fabric.microsoft.com/v1/workspaces";
    responsename = await service.GetAsync(baseUrl);
    JObject jsonObject = JObject.Parse(responsename);
    int i = 0; string workspaceId = "";
    for (i = 0; i < jsonObject["value"].Count(); i++)
    {
        if (jsonObject["value"][i]["displayName"].ToString() == workspaceName)
        {
            workspaceId = jsonObject["value"][1]["id"].ToString();
        }
    }
}
```

Couple of things to note . I have used `Newtonsoft` library to parse the response and to fetch the `workspaceId`of the desired workspace I want to manage by checking the workspace name in the for loop.

The `workspacename` used above is a static variable declared earlier.

`private static string workspaceName = "Workspace name";`

Now execute the program. At the launch, it would prompt for acceptance of the required permissions based on the scopes that were declared.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1724696019277/4da94e3b-1e75-4751-9d08-0f4e1d061164.png align="center")

Once accepted, it would ask for the Fabric tenant login to set the `Bearer` token. Login into it using your Fabric tenant credentials.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1724696382316/46c2d967-e6b1-4fc1-896e-8e92dde0da9a.png align="center")

Once the login is authenticated and everything else works ok , you would see the following screen.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1724696732209/b2036071-c822-4f8a-95c1-fbe5e9698070.png align="center")

Please note the set up **will not work** if your workspace License mode is Pro.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1724697501445/9fe32e17-0bf4-4e1b-91f0-04ebede31fe1.png align="center")

Now lets check the methods to perform the lakehouse operations :

### Create a new Lakehouse

```csharp
    static async Task CreateLakeHouse(string workspaceId, string displayName)
    {

        string baseUrl = $"https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/lakehouses";
        MyService service = new MyService();
        var jsonData = new Dictionary<string, string>
              {
                  { "displayName", displayName },
                  { "type", "Lakehouse"}
};
        string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(jsonData);
        var content = new StringContent(jsonString, Encoding.UTF8, "application/json");
        responsename = await service.PostAsync(baseUrl, content);
        Console.WriteLine(responsename);

    }
```

*Call to the above method :*

```csharp
await CreateLakeHouse(workspaceId, "Fabric_API_LakeHouse");
```

where `Fabric_API_LakeHouse` is the name of the lakehouse to be created.

### Move Files into a Table in a Lakehouse

As stated earlier, at the time of this writing there are no API's to perform a direct data load into the lakehouse. Only option available is to copy the data from `Files` to `Tables` in a lakehouse.

The method would copy `demo_data.csv` from `Files` to `Tables` as a `delta` table.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1724699119490/e77d512d-f9aa-41f3-83b6-97372c1008a3.png align="center")

```csharp
static async Task LoadTable(string workspaceId, string Lakehouse, string relativePath, string tablename)
{

    MyService service = new MyService();

    string baseUrl = $"https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/lakehouses";
    responsename = await service.GetAsync(baseUrl);
    JObject jsonObject_lakhouse = JObject.Parse(responsename);
    var lakehouseid = (jsonObject_lakhouse["value"].FirstOrDefault(lh => lh["displayName"]?.ToString() == Lakehouse));
    lakehouseid = lakehouseid["id"];

    baseUrl = $"https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/lakehouses/{lakehouseid}/tables/{tablename}/load";

    var jsonData = new Dictionary<string, object>
    {
        { "relativePath", relativePath },
        { "pathType", "File" },
        { "mode", "Overwrite" },
        { "recursive", false },
        { "formatOptions", new Dictionary<string, object>
            {
                { "format", "Csv" },
                { "header", true },
                { "delimiter", "," }
            }
        }
    };

    string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(jsonData);
    var content = new StringContent(jsonString, Encoding.UTF8, "application/json");
    responsename = await service.PostAsync(baseUrl, content);
    Console.WriteLine(responsename);

}
```

*Call to the above method :*

```csharp
   await LoadTable(workspaceId, "Fabric_API_LakeHouse", "Files/demo_data.csv", "demo_data");
```

Few things to note. I have used a a `LINQ` method to fetch the `lakehouseid` based on `LakeHouse`argument passed to the function.

`var lakehouseid = (jsonObject_lakhouse["value"].FirstOrDefault(lh => lh["displayName"]?.ToString() == Lakehouse)); lakehouseid = lakehouseid["id"];`

Also have to mention the format option of the file to be moved  
`{ "formatOptions", new Dictionary<string, object> { { "format", "Csv" }, { "header", true }, { "delimiter", "," } } }`

Post execution you would see the `demo_data.csv` copied to `Tables` of the lakehouse.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1724700556291/ba2fa646-0e21-42a5-9d3c-6483d583b473.png align="center")

### Create a Azure ADLS2 Shortcut

```csharp
    static async Task CreateADLS_ShortCut(string workspaceId, string LakehouseName, string shortCutPath, string shortCutName, string sourceLocation, string sourcesubPath, string connectionId)
    {
        MyService service = new MyService();


        string baseUrl = $"https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/items";

        responsename = await service.GetAsync(baseUrl);
        JObject jsonObject_lakhouse = JObject.Parse(responsename);
        var lakehouseid = jsonObject_lakhouse["value"].FirstOrDefault(lh => lh["displayName"]?.ToString() == LakehouseName && lh["type"]?.ToString() == "Lakehouse");
        lakehouseid = lakehouseid["id"];

        baseUrl = $"https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/items/{lakehouseid}/shortcuts";

        var jsonData = new Dictionary<string, object>
        {
            { "path",  shortCutPath },
            { "name", shortCutName },
            { "target", new Dictionary<string, object>
                {
            { "adlsGen2", new Dictionary<string, object>
                {
                    { "location", sourceLocation },
                    { "subpath", sourcesubPath },
                    { "connectionId", connectionId }
                }
            }
            }
            }

};

        string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(jsonData);
        var content = new StringContent(jsonString, Encoding.UTF8, "application/json");
        responsename = await service.PostAsync(baseUrl, content);

    }
```

*Call to the above method :*

```csharp
 await CreateADLS_ShortCut(workspaceId, "Fabric_API_LakeHouse", "Files/ADLS_Shortcut", "Source", "https://<storage_account>.dfs.core.windows.net/", "/<storage_account>/source", AzureADLSConnection);
```

The method requires the path to the shortcut, name for the shortcut, the `ADLS2` connectionid that we created earlier and the `ADLS2 URI`.

The method would create a shortcut at path `Files/ADLS_Shortcut` from the `ADLS2` location `<storage_account>/Source` in Azure to the lakehouse `Fabric_API_LakeHouse`.

*ADLS2 location*

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1724700373311/a49fe5ac-5511-49a2-b524-db0a250672f1.png align="left")

The Source folder has two subfolders `Source_1` and `Source_2` and a text file `1.txt`.

As seen below, the shortcut was created for the `ADLS2` location

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1724707800155/4ce56554-95d1-4fde-9a8c-4be11117108f.png align="center")

### Create a OneLake Shortcut

```csharp
    static async Task CreateLakeHouse_ShortCut(string workspaceId, string SourceLakehouse, string DestinationLakehouse, string SourceLakehousePath, string DestinationLakehousePath, string shortCutName)
    {

        MyService service = new MyService();
        string baseUrl = $"https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/items";
        responsename = await service.GetAsync(baseUrl);
        JObject jsonObject_lakhouse = JObject.Parse(responsename);
        var lakehouseid_source = jsonObject_lakhouse["value"].FirstOrDefault(lh => lh["displayName"]?.ToString() == SourceLakehouse && lh["type"]?.ToString() == "Lakehouse");
        lakehouseid_source = lakehouseid_source["id"];

        var lakehouseid_destination = jsonObject_lakhouse["value"].FirstOrDefault(lh => lh["displayName"]?.ToString() == DestinationLakehouse && lh["type"]?.ToString() == "Lakehouse");
        lakehouseid_destination = lakehouseid_destination["id"];

        baseUrl = $"https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/items/{lakehouseid_destination}/shortcuts";

        var jsonData = new Dictionary<string, object>
        {
            { "path", SourceLakehousePath },//SourceLakehousePath
            { "name",shortCutName },//shortCutName
            { "target", new Dictionary<string, object>
                {
            { "oneLake", new Dictionary<string, object>
                {
                    { "workspaceId",  workspaceId },
                    { "itemId", lakehouseid_source },
                    { "path",  DestinationLakehousePath}//DestinationLakehousePath
                }
            }
            }
            }

};

        string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(jsonData);
        var content = new StringContent(jsonString, Encoding.UTF8, "application/json");
        responsename = await service.PostAsync(baseUrl, content);

    }
```

*Call to the method*

```csharp
await CreateLakeHouse_ShortCut(workspaceId, "LakeHouse_1", "LakeHouse_2", "Files/Customers", "Files/Customers", "CustomerShortcut");
```

The method requires Source and Destination OneLake locations. In this case the method creates shortcut from `LakeHouse_1` to `LakeHouse_2` from `Files/Customers` under `LakeHouse_1` to `LakeHouse_2`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1724706305141/df9935dd-d6cc-45c3-8f13-08587100f1b3.png align="center")

### Closing Notes

Through this article I tried to provide insights into the possibilities of the Fabric REST API's.  
Once you get a basic understanding of the underlying structure of the formats and the methods, automating the most crucial aspects of your Fabric tenant through the REST API's would be an easy possibility. Thank you for reading !!!
