Jason Mitchell Profile

Jason Mitchell

Open Source
Image credit: Julian Hochgesang on Unsplash

Open Source

Introducing Hallo

18 Jan 2023

Even though it may seem a bit late (given that it is currently on version 3.0.2 at the time of writing), I'd like to introduce my .NET package Hallo. Hallo enables the generation of HAL documents for HTTP APIs through content negotiation.

The primary design goal of Hallo is to enable developers to add support for hypermedia to their APIs without needing to make changes to their models or API endpoints. For every resource you want to generate a HAL document for, you can create a new resource representation by deriving a new class from Hal<T> and implement one or more of IHalState<T>, IHalEmbedded<T> or IHalLinks<T>:

public class PersonRepresentation : Hal<Person>,
                                    IHalState<Person>,
                                    IHalLinks<Person>,
                                    IHalEmbedded<Person>
{
    public object StateFor(Person resource)
    {
        return new
        {
            resource.FirstName,
            resource.LastName
        };
    }

    public IEnumerable<Link> LinksFor(Person resource)
    {
        yield return new Link(Link.Self, $"/people/{resource.Id}");
        yield return new Link("contacts", $"/people/{resource.Id}/contacts");
    }

    public object EmbeddedFor(Person resource)
    {
        return new
        {
            Contacts = new List<Person>()
        };
    }
}

Given the example above and assuming we have an API to access the Person resource, then a HTTP request such as:

GET http://localhost:5000/people/1
Accept: application/hal+json

will produce the result:

{
  "firstName": "Geoffrey",
  "lastName": "Merrill",
  "_embedded": {
    "contacts": []
  },
  "_links": {
    "self": {
      "href": "/people/1"
    },
    "contacts": {
      "href": "/people/1/contacts"
    }
  }
}

Hallo also works with the standard ASP.NET approach to dependency injections which allows you to inject additional services into the resource representation. For example, we could query a database for additional data to use when populating the _embedded property of the HAL document:

public class PersonRepresentation : Hal<Person>,
                                    IHalEmbeddedAsync<Person>
{
    private readonly ContactsLookup _contacts;

    public PersonRepresentation(ContactsLookup contacts)
    {
        _contacts = contacts;
    }

    public async Task<object> EmbeddedForAsync(Person resource)
    {
        var contacts = await _contacts.GetFor(resource.Id);

        return new
        {
            Contacts = contacts
        };
    }
}

To get started with Hallo, check out the README on GitHub which runs through how to set the package up in your API. The repository also includes a functioning sample which can be played with to get a feel for the project. If you have any questions or comments, I'm always open to discussion in the GitHub issues and will happily take contributions. If you do use Hallo in your project, I'd love to know so give me a shout!