Web API in Umbraco Unicore Alpha 3

My experiments with Umbraco Unicore Alpha 3 continues, this time with Web API controllers and integrating it with a Blazor WASM app. I am bringing a bit of Carnatic Music into my demo here! I am using Umbraco Unicore as a content store to hold information about ragas (base melodies in Carnatic music) and I am using a Blazor WASM app to display the content.

My Content Structure

My content structure looks as shown below. I have a Raga List document type that allows Raga document type as its allowed child node type. The Raga document type holds the information about a raga. The Raga List document type acts like a folder to organise my content better. 

And here is my Raga document type.

To create a Web API, I inherit from UmbracoAPIController. My Web API Controller is called RagaAPIController. The method GetRagas is responsible for getting my data. The real change I noticed around Web API controllers in Umbraco Unicore is in the way the data is queried. I am not sure whether this is the right way to do it, but its Umbraco and there is always more than one way to achieve the same thing!

To query the content I use the IPublishedContentQuery .The IPublishedContentQuery is an injectable dependency that can be used to query strongly typed content. I inject the IPublishedContentQuery into my controller and once injected I can use the ContentSingleAtXPath method passing in the XPath to my content node to get the RagaList node. I can then get the child nodes of this node, loop through them and create a List of RagaDTO objects. My API controller looks as shown below.

public class RagaApiController : UmbracoApiController
{

	private readonly IPublishedContentQuery _contentQuery;

	public RagaApiController(IPublishedContentQuery contentQuery)
	{
		_contentQuery = contentQuery;
	}

	public List<RagaDTO> GetRagas()
	{
		var ragaList = _contentQuery.ContentSingleAtXPath("//home/ragaList");

		var ragas = ragaList.Children.OfType<Raga>();

		var ragaContent = new List<RagaDTO>();

		foreach(var raga in ragas)
		{
			ragaContent.Add(new RagaDTO { 
			Name = raga.Name, 
			RagaType = raga.RagaType,
			Notation = raga.Notation
			});
		}

		return ragaContent;
	}

}

And my RagaDTO class is here 

public class RagaDTO
{
	public string Name { get; set; }

	public string RagaType { get; set; }

	public string Notation { get; set; }
}

Finally, I need to enable CORS. I have kept it pretty open, allowing all headers, origins and methods in my example by specifying a named policy in the ConfigureServices() method and enabling the CORS middleware in the Configure() method in the Startup.cs. More about CORS in ASP.NET Core can be read here

services.AddCors(options =>
{
 options.AddPolicy("MyBlazorApp", builder => 
  builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
});

 

app.UseCors("MyBlazorApp");

Build and run, and my API is available at umbraco/api/ragaapi/getragas .

Displaying The Information Using A Blazor App

I am using a Blazor WASM App to display the information. For this, I first need to create an IRagaService interface and its implementation that contains a method to reach out to my Web API. 

public class RagaService : IRagaService
{
private readonly HttpClient httpClient;

	public RagaService(HttpClient httpClient)
	{
		this.httpClient = httpClient;
	}

	public async Task<List<RagaDTO>> GetRagas()
	{
		return await JsonSerializer.DeserializeAsync<List<RagaDTO>>(await httpClient.GetStreamAsync($"umbraco/api/RagaApi/GetRagas"), new JsonSerializerOptions { PropertyNameCaseInsensitive = true});
	}	
}

public interface IRagaService
{
	Task<List<RagaDTO>> GetRagas();
}

This service needs to be registered in the Program.cs

builder.Services.AddHttpClient<IRagaService, RagaService>(s => s.BaseAddress = new Uri("https://localhost:5001/"));

This is the Typed Client Consumption Pattern. More can be read about it here. The JSON returned by the API is deserialized to a List of RagaDTO objects. The RagaDTO class is the same as mentioned before.

Finally, in my Index.Razor component, I can inject the IRagaService to reach out to my Web API can display the data. 

@page "/"
@inject IRagaService ragaService

@if (ragas != null && ragas.Any())
{
    foreach (var raga in ragas.OrderBy(r => r.Name))
    {
<div class="row">
    <p>@raga.Name - @raga.RagaType</p>
</div>
    }
}

@code{

    List<RagaDTO> ragas = new List<RagaDTO>();

    protected override async Task OnInitializedAsync()
    {
        ragas = await ragaService.GetRagas();
    }
}

And here is a screenshot of what my Blazor App displays :-)


REST : Myths & Facts

01 December 2023

This article discusses some of the misconceptions about REST, and what is not REST and presents you with the facts.