Skip to content

Latest commit

 

History

History
264 lines (206 loc) · 7.97 KB

README.md

File metadata and controls

264 lines (206 loc) · 7.97 KB

HateoasNet

A small hateoas libarry for .NET with fluent-like configuration and easey integrations with lambda expressions for building hateoas links with type mapping. Supports ease for custom hateoas output implementations.

Status

Quality Gate Status Coverage Build status Deploy status CI

Target Platforms

HateoasNet targets NetCoreApp3.1 and Net Framework 4.72.

Get Started

The latest stable version of HateoasNet can be installed using the Nuget package manager

Install-Package HateoasNet -Version <version>

Dotnet CLI

dotnet add package HateoasNet --version <version>

or package reference.

<PackageReference Include="HateoasNet" Version="<version>" />

Contributing

Before contributing, get started with our Contributing guide.

Code of conduct

Please note we have a Code of conduct, please follow it in all your interactions with the project.


Examples

Inline configuration and integration

using HateoasNet.DependencyInjection.Core;

public void ConfigureServices(IServiceCollection services)
{
    // other registration...

    services.ConfigureHateoas(context =>
    {
        return context.Configure<List<Member>>(members =>
        {
            members.AddLink("get-members");
            members.AddLink("invite-member");
            members.AddLink("create-member");
        })

        .Configure<Member>(member =>
        {
            member.AddLink("get-member").HasRouteData(e => new { id = e.Id });
            member.AddLink("update-member").HasRouteData(e => new { id = e.Id });
        })

        .Configure<Member>(member =>
        {
            member.AddLink("get-guild")
                .HasRouteData(e => new { id = e.GuildId })
                .When(e => e.GuildId != null);

            member.AddLink("promote-member")
                .HasRouteData(e => new { id = e.Id })
                .When(e => e.GuildId != null && !e.IsGuildMaster);

            member.AddLink("demote-member")
                .HasRouteData(e => new { id = e.Id })
                .When(e => e.GuildId != null && e.IsGuildMaster);

            member.AddLink("leave-guild")
                .HasRouteData(e => new { id = e.Id })
                .When(e => e.GuildId != null);
        });
    });

    // other registrations...
}

Configuration in separated class

using HateoasNet.Abstractions;

public class MemberHateoasBuilder : IHateoasSourceBuilder<Member>
{
    public void Build(IHateoasSource<Member> resource)
    {
        resource.AddLink("get-member").HasRouteData(e => new { id = e.Id });
        resource.AddLink("update-member").HasRouteData(e => new { id = e.Id });

        resource
            .AddLink("get-guild")
            .HasRouteData(e => new { id = e.GuildId })
            .When(e => e.GuildId != null);

        resource
            .AddLink("promote-member")
            .HasRouteData(e => new { id = e.Id })
            .When(e => e.GuildId != null && !e.IsGuildMaster);

        resource
            .AddLink("demote-member")
            .HasRouteData(e => new { id = e.Id })
            .When(e => e.GuildId != null && e.IsGuildMaster);

        resource.AddLink("leave-guild")
                .HasRouteData(e => new { id = e.Id })
                .When(e => e.GuildId != null);
    }
}

Integration calling IHateoasSourceBuilders

using HateoasNet.DependencyInjection.Core;

public void ConfigureServices(IServiceCollection services)
{
    // other registrations...

    // setup applying map configurations from classes in separated files
    services.ConfigureHateoas(context => context
        .ApplyConfiguration(new GuildHateoasBuilder())
        .ApplyConfiguration(new ListGuildHateoasBuilder())
        .ApplyConfiguration(new MemberHateoasBuilder())
        .ApplyConfiguration(new ListMemberHateoasBuilder())
        .ApplyConfiguration(new InviteHateoasBuilder())
        .ApplyConfiguration(new InvitesHateoasBuilder()));

    // other registrations...
}

Integration using assemblies

using HateoasNet.DependencyInjection.Core;

public void ConfigureServices(IServiceCollection services)
{
    // other registrations...

    // setup applying configurations from IHateoasSourceBuilder implementations in separated files found in a given assembly
    services.ConfigureHateoas(context => context.ConfigureFromAssembly(typeof(GuildHateoasBuilder).Assembly));

    // other registrations...
}

IHateoas Abstraction usage

using HateoasNet;
using System.Linq;
using System.Collection.Generics;

[ApiController]
[Route("[controller]")]
public class MembersController : ControllerBase
{
    private readonly IHateoas _hateoas;
    private readonly List<Member> _members;

    public MembersController(List<Member> members, IHateoas hateoas)
    {
        _hateoas = hateoas;
        _members = members;
    }

    [HttpGet("{id:guid}", Name = "get-member")]
    public IActionResult Get(Guid id)
    {
        var member = _members.SingleOrDefault(i => i.Id == id);
        var links = _hateoas.Generate(member);
        return member != null ? Ok(new { data = member, links }) : NotFound() as IActionResult;
    }
}

Sample of optional custom Hateoas output implementation

using HateoasNet;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Immutable;

public class DictionaryHateoas : AbstractHateoas<ImmutableDictionary<string, object>>
{
    public DictionaryHateoas(IHateoas hateoas) : base(hateoas)
    {
    }

    protected override ImmutableDictionary<string, object> GenerateCustom(IEnumerable<HateoasLink> links)
    {
        return links.ToImmutableDictionary(x => x.Rel, x => (object)new { x.Href, x.Method });
    }
}

Sample of optional custom Hateoas output registrations

using HateoasNet.DependencyInjection.Core;

public void ConfigureServices(IServiceCollection services)
{
    // other registrations...

    // optional step to register all custom IHateoas<T> implementations in separated files found in a given assemblies
    services.RegisterAllCustomHateoas(new Assembly[] { typeof(Startup).Assembly }, ServiceLifetime.Scoped)

    // other registrations...
}

Custom IHateoas Abstraction usage

using HateoasNet;
using System.Linq;
using System.Collections.Generic;

[ApiController]
[Route("[controller]")]
public class GuildsController : ControllerBase
{
    private readonly IHateoas<ImmutableDictionary<string, object>> _hateoas;
    private readonly List<Guild> _guilds;

    public GuildsController(List<Guild> guilds, IHateoas<ImmutableDictionary<string, object>> hateoas)
    {
        _hateoas = hateoas;
        _guilds = guilds;
    }

    [HttpGet("{id:guid}", Name = "get-guild")]
    public IActionResult Get(Guid id)
    {
        var guild = _guilds.SingleOrDefault(i => i.Id == id);
        var links = _hateoas.Generate(guild);
        return guild != null ? Ok(new { data = guild, links }) : NotFound() as IActionResult;
    }
}

Credits

Project conceived by @icarotorres : icaro.stuart@gmail.com, then owner of this repository.