How to integrate with the Trello API from .NET/C#
I have been playing around with the Trello REST API recently. To my surprise, there doesn't seem to be any actively developed client package for .NET and Trello doesn't show examples in C# on their website. Here's a quick overview of what I have learned.
For this post, I'll build a minimal console application in .NET 6 interacting with the Trello API. The code is not specific to console apps in any way and can be used on a website too if that's what you came here to achieve.
To communicate with the Trello REST API you will need an API key and a token. If you haven't already, sign up for a new user on trello.com. Next, go to https://trello.com/app-key
and accept the developer terms. On the following page you will see your API key:
When developing a website you would normally want to let the user authorize your website's access to the Trello API using the authorize
endpoint described in Trello's documentation. Since I'm developing a console application for this post, I'll use the Token link shown in the screenshot above. When generating a new token you will need to authorize access to your boards:
When clicking the Authorize button at the bottom of the page, a new token will be generated:
With the API key and token in place, we are ready to start integrating. Create a new console application. For this demo, I'm using a .NET 6 minimal app:
dotnet new console
I'll also install all of the NuGet packages that we need to get everything wired up:
dotnet add package Microsoft.Extensions.Hosting
dotnet add package Microsoft.Extensions.Http
dotnet add package Spectre.Console
dotnet add package System.Net.Http.Json
The Microsoft.Extensions.Hosting
package is needed to configure the host builder. Microsoft.Extensions.Http
will serve as a way to configure the HttpClient
needed to communicate with the API. Spectre.Console
will generate some "UI" and System.Net.Http.Json
contains a convenient way to map HTTP responses to strongly typed objects.
Let's start by configuring the dependencies:
var host = Host
.CreateDefaultBuilder(args)
.ConfigureServices((_, services) =>
{
services.AddHttpClient("trello", options =>
{
options.BaseAddress = new Uri("https://api.trello.com/1/");
options.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(
"OAuth",
"oauth_consumer_key=\"API_KEY\", oauth_token=\"TOKEN\"");
});
})
.Build();
If you are familiar with ASP.NET Core, the code will be pretty straightforward. I use the builder to configure a new HttpClient
. The base address is set to the root of Trello's REST API and the API key and token generated in the previous step is set as the authorization header on all requests. You will need to replace API_KEY
and TOKEN
with the values generated on your Trello account.
Next, I'll pull a new HttpClient
:
var httpClientFactory = host.Services.GetRequiredService<IHttpClientFactory>();
var httpClient = httpClientFactory.CreateClient("trello");
This will generate a new HttpClient
with the base address and authorization headers configured in the previous step.
To show different ways and concepts of the API, I'll code up a small client able to pick a card and mark it as closed. Start by getting a list of boards:
var boards = await httpClient
.GetFromJsonAsync<List<TrelloIdAndName>>($"members/me/boards");
The members/me/boards
endpoint returns a list of Board
objects from Trello. We are only interested in the Id
and Name
properties for this example, why I'm deserializing the response to a List
of TrelloIdAndName
objects:
internal class TrelloIdAndName
{
public string Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
With the list of boards returned from the API, I'll use Spectre.Console
to generate a quick prompt:
var selectedBoard = AnsiConsole.Prompt(
new SelectionPrompt<TrelloIdAndName>()
.Title("Select board")
.PageSize(10)
.AddChoices(boards));
var selectedBoardId = selectedBoard.Id;
Let's run the code:
Success! I have three boards in that account. When picking one of the boards, I want to show a list of lists and let the user pick one of them. Finally, show the cards in the selected list a have the user pick one. The code looks like this:
var lists = await httpClient.GetFromJsonAsync<List<TrelloIdAndName>>($"boards/{selectedBoardId}/lists");
var selectedList = AnsiConsole.Prompt(
new SelectionPrompt<TrelloIdAndName>()
.Title("Select list")
.PageSize(10)
.AddChoices(lists));
var selectedListId = selectedList.Id;
var cards = await httpClient.GetFromJsonAsync<List<TrelloIdAndName>>($"lists/{selectedListId}/cards");
var selectedCard = AnsiConsole.Prompt(
new SelectionPrompt<TrelloIdAndName>()
.Title("Select card")
.PageSize(10)
.AddChoices(cards));
var selectedCardId = selectedCard.Id;
The code pretty much follows the same structure as when requesting the boards. I'm getting the lists inside the selected Trello boards. Then let the user pick on and output the cards in the selected list.
To get the details of the selected card, I'll generate a new model class:
internal class TrelloCard
{
public string Id { get; set; }
public string Name { get; set; }
public string Desc { get; set; }
}
Like previously, I'm only mapping the properties I need for this sample. Each card contains a range of properties when returned from the Trello API.
Request the card details and output them in a table:
var card = await httpClient.GetFromJsonAsync<TrelloCard>($"cards/{selectedCardId}");
var table = new Table();
table.HideHeaders();
table.AddColumn("");
table.AddRow(card.Name);
table.AddRow(new Panel(card.Desc));
AnsiConsole.Write(table);
The code produces this UI in the console:
The final step is to let the user mark the card as closed:
if (AnsiConsole.Confirm("Close it?"))
{
await httpClient.PutAsync($"cards/{card.Id}?closed=true", null);
}
If the user confirms the close, the PUT
method on the card details is requested with closed=true
. The entire session looks like this:
That's it. With a few lines of code and a bit of magic from Spectre.Console
we have made a simple Trello client. Here's the full code:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Spectre.Console;
using System.Net.Http.Headers;
using System.Net.Http.Json;
var host = Host
.CreateDefaultBuilder(args)
.ConfigureServices((_, services) =>
{
services.AddHttpClient("trello", options =>
{
options.BaseAddress = new Uri("https://api.trello.com/1/");
options.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"OAuth",
"oauth_consumer_key=\"API_KEY\", oauth_token=\"TOKEN\"");
});
})
.Build();
var httpClientFactory = host.Services.GetRequiredService<IHttpClientFactory>();
var httpClient = httpClientFactory.CreateClient("trello");
var boards = await httpClient.GetFromJsonAsync<List<TrelloIdAndName>>($"members/me/boards");
var selectedBoard = AnsiConsole.Prompt(
new SelectionPrompt<TrelloIdAndName>()
.Title("Select board")
.PageSize(10)
.AddChoices(boards));
var selectedBoardId = selectedBoard.Id;
var lists = await httpClient.GetFromJsonAsync<List<TrelloIdAndName>>($"boards/{selectedBoardId}/lists");
var selectedList = AnsiConsole.Prompt(
new SelectionPrompt<TrelloIdAndName>()
.Title("Select list")
.PageSize(10)
.AddChoices(lists));
var selectedListId = selectedList.Id;
var cards = await httpClient.GetFromJsonAsync<List<TrelloIdAndName>>($"lists/{selectedListId}/cards");
var selectedCard = AnsiConsole.Prompt(
new SelectionPrompt<TrelloIdAndName>()
.Title("Select card")
.PageSize(10)
.AddChoices(cards));
var selectedCardId = selectedCard.Id;
var card = await httpClient.GetFromJsonAsync<TrelloCard>($"cards/{selectedCardId}");
var table = new Table();
table.HideHeaders();
table.AddColumn("");
table.AddRow(card.Name);
table.AddRow(new Panel(card.Desc));
AnsiConsole.Write(table);
if (AnsiConsole.Confirm("Close it?"))
{
await httpClient.PutAsync($"cards/{card.Id}?closed=true", null);
}
elmah.io: Error logging and Uptime Monitoring for your web apps
This blog post is brought to you by elmah.io. elmah.io is error logging, uptime monitoring, deployment tracking, and service heartbeats for your .NET and JavaScript applications. Stop relying on your users to notify you when something is wrong or dig through hundreds of megabytes of log files spread across servers. With elmah.io, we store all of your log messages, notify you through popular channels like email, Slack, and Microsoft Teams, and help you fix errors fast.
See how we can help you monitor your website for crashes Monitor your website