Tapioca.HATEOAS 1.0.21

There is a newer version of this package available.
See the version list below for details.
dotnet add package Tapioca.HATEOAS --version 1.0.21                
NuGet\Install-Package Tapioca.HATEOAS -Version 1.0.21                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Tapioca.HATEOAS" Version="1.0.21" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Tapioca.HATEOAS --version 1.0.21                
#r "nuget: Tapioca.HATEOAS, 1.0.21"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Tapioca.HATEOAS as a Cake Addin
#addin nuget:?package=Tapioca.HATEOAS&version=1.0.21

// Install Tapioca.HATEOAS as a Cake Tool
#tool nuget:?package=Tapioca.HATEOAS&version=1.0.21                

Tapioca.HATEOAS

NuGet Donate with PayPal GitHub repo Last Commit Forks Stars .NET 8 Continuous Integration with GitHub, GitHub Actions and Nuget Packages

This is a smart library to implements HATEOAS pattern in your RESTFul API's, implemented based in this project.

How to use

1 - Import Tapioca.HATEOAS to your projetct

Import with command line
Install-Package Tapioca.HATEOAS -Version 1.0.15
Import with nuget package manager

Nuget Package Mannager

2 - Implements ISupportsHyperMedia in your exposed object.

namespace RESTFulSampleServer.Data.VO
{
    public class BookVO : ISupportsHyperMedia
    {
        public long? Id { get; set; }
        public string Title { get; set; }
        public string Author { get; set; }
        public decimal Price { get; set; }
        public DateTime LaunchDate { get; set; }

        public List<HyperMediaLink> Links { get; set; } = new List<HyperMediaLink>();
    }
}

3 - Implements your enricher with ObjectContentResponseEnricher<T>.

namespace RESTFulSampleServer.HyperMedia.Enricher
{
    public class BookEnricher : ContentResponseEnricher<BookVO>
    {
        protected override Task EnrichModel(BookVO content, IUrlHelper urlHelper)
        {
            var path = "api/book";
            string link = GetLink(content.Id, urlHelper, path);

            content.Links.Add(new HyperMediaLink()
            {
                Action = HttpActionVerb.GET,
                Href = link,
                Rel = RelationType.self,
                Type = ResponseTypeFormat.DefaultGet
            });
            content.Links.Add(new HyperMediaLink()
            {
                Action = HttpActionVerb.POST,
                Href = link,
                Rel = RelationType.self,
                Type = ResponseTypeFormat.DefaultPost
            });
            content.Links.Add(new HyperMediaLink()
            {
                Action = HttpActionVerb.PUT,
                Href = link,
                Rel = RelationType.self,
                Type = ResponseTypeFormat.DefaultPut
            });
            content.Links.Add(new HyperMediaLink()
            {
                Action = HttpActionVerb.DELETE,
                Href = link,
                Rel = RelationType.self,
                Type = "int"
            });
            return Task.CompletedTask;
        }

        private string GetLink(long id, IUrlHelper urlHelper, string path)
        {
            lock (this)
            {
                var url = new { controller = path, id };
                return new StringBuilder(urlHelper.Link("DefaultApi", url)).Replace("%2F", "/").ToString();
            };
        }
    }
}

4 - Add annotation [TypeFilter(typeof(HyperMediaFilter))] to your controller methods.

namespace RESTFulSampleServer.Controllers
{

    [ApiVersion("1")]
    [ApiController]
    [Authorize("Bearer")]
    [Route("api/[controller]/v{version:apiVersion}")]
    public class BookController : ControllerBase
    {

        private readonly ILogger<BookController> _logger;

        private IBookBusiness _bookBusiness;

        public BookController(ILogger<BookController> logger, IBookBusiness bookBusiness)
        {
            _logger = logger;
            _bookBusiness = bookBusiness;
        }

        [HttpGet]
        [ProducesResponseType((200), Type = typeof(List<BookVO>))]
        [ProducesResponseType(204)]
        [ProducesResponseType(400)]
        [ProducesResponseType(401)]
		
		// Adds HyperMedia filter
        [TypeFilter(typeof(HyperMediaFilter))]
        public IActionResult Get()
        {
            return Ok(_bookBusiness.FindAll());
        }

        [HttpGet("{id}")]
        [ProducesResponseType((200), Type = typeof(BookVO))]
        [ProducesResponseType(204)]
        [ProducesResponseType(400)]
        [ProducesResponseType(401)]
		
		// Adds HyperMedia filter
        [TypeFilter(typeof(HyperMediaFilter))]
        public IActionResult Get(long id)
        {
            var book = _bookBusiness.FindByID(id);
            if (book == null) return NotFound();
            return Ok(book);
        }

        [HttpPost]
        [ProducesResponseType((200), Type = typeof(BookVO))]
        [ProducesResponseType(400)]
        [ProducesResponseType(401)]
		
		// Adds HyperMedia filter
        [TypeFilter(typeof(HyperMediaFilter))]
        public IActionResult Post([FromBody] BookVO book)
        {
            if (book == null) return BadRequest();
            return Ok(_bookBusiness.Create(book));
        }

        [HttpPut]
        [ProducesResponseType((200), Type = typeof(BookVO))]
        [ProducesResponseType(400)]
        [ProducesResponseType(401)]
		
		// Adds HyperMedia filter
        [TypeFilter(typeof(HyperMediaFilter))]
        public IActionResult Put([FromBody] BookVO book)
        {
            if (book == null) return BadRequest();
            return Ok(_bookBusiness.Update(book));
        }

        [HttpDelete("{id}")]
        [ProducesResponseType(204)]
        [ProducesResponseType(400)]
        [ProducesResponseType(401)]
        public IActionResult Delete(long id)
        {
            _bookBusiness.Delete(id);
            return NoContent();
        }
    }
}

5 - Add HyperMediaFilterOptions to your Program.cs.

	var filterOptions = new HyperMediaFilterOptions();
	filterOptions.ContentResponseEnricherList.Add(new PersonEnricher());
	filterOptions.ContentResponseEnricherList.Add(new BookEnricher());

6 - Add a MapControllerRoute to your route like was defined in your enricher.

	app.MapControllers();
	* app.MapControllerRoute("DefaultApi", "{controller=values}/v{version=apiVersion}/{id?}"); *

	app.Run();

7 - Enjoy

Response as JSON
[
    {
        "id": 1,
        "title": "Working effectively with legacy code",
        "author": "Michael C. Feathers",
        "price": 49.00,
        "launchDate": "2017-11-29T13:50:05.878",
        "links": [
            {
                "rel": "self",
                "href": "https://localhost:44300/api/book/v1/1",
                "type": "application/json",
                "action": "GET"
            },
            {
                "rel": "self",
                "href": "https://localhost:44300/api/book/v1/1",
                "type": "application/json",
                "action": "POST"
            },
            {
                "rel": "self",
                "href": "https://localhost:44300/api/book/v1/1",
                "type": "application/json",
                "action": "PUT"
            },
            {
                "rel": "self",
                "href": "https://localhost:44300/api/book/v1/1",
                "type": "int",
                "action": "DELETE"
            }
        ]
    },
    {
        "id": 2,
        "title": "Design Patterns",
        "author": "Ralph Johnson, Erich Gamma, John Vlissides e Richard Helm",
        "price": 45.00,
        "launchDate": "2017-11-29T15:15:13.636",
        "links": [
            {
                "rel": "self",
                "href": "https://localhost:44300/api/book/v1/2",
                "type": "application/json",
                "action": "GET"
            },
            {
                "rel": "self",
                "href": "https://localhost:44300/api/book/v1/2",
                "type": "application/json",
                "action": "POST"
            },
            {
                "rel": "self",
                "href": "https://localhost:44300/api/book/v1/2",
                "type": "application/json",
                "action": "PUT"
            },
            {
                "rel": "self",
                "href": "https://localhost:44300/api/book/v1/2",
                "type": "int",
                "action": "DELETE"
            }
        ]
    }
]
Response as XML
<ArrayOfBookVO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <BookVO>
        <Id>1</Id>
        <Title>Working effectively with legacy code</Title>
        <Author>Michael C. Feathers</Author>
        <Price>49.00</Price>
        <LaunchDate>2017-11-29T13:50:05.878</LaunchDate>
        <Links>
            <HyperMediaLink>
                <Rel>self</Rel>
                <Href>https://localhost:44300/api/book/v1/1</Href>
                <Type>application/json</Type>
                <Action>GET</Action>
            </HyperMediaLink>
            <HyperMediaLink>
                <Rel>self</Rel>
                <Href>https://localhost:44300/api/book/v1/1</Href>
                <Type>application/json</Type>
                <Action>POST</Action>
            </HyperMediaLink>
            <HyperMediaLink>
                <Rel>self</Rel>
                <Href>https://localhost:44300/api/book/v1/1</Href>
                <Type>application/json</Type>
                <Action>PUT</Action>
            </HyperMediaLink>
            <HyperMediaLink>
                <Rel>self</Rel>
                <Href>https://localhost:44300/api/book/v1/1</Href>
                <Type>int</Type>
                <Action>DELETE</Action>
            </HyperMediaLink>
        </Links>
    </BookVO>
    <BookVO>
        <Id>2</Id>
        <Title>Design Patterns</Title>
        <Author>Ralph Johnson, Erich Gamma, John Vlissides e Richard Helm</Author>
        <Price>45.00</Price>
        <LaunchDate>2017-11-29T15:15:13.636</LaunchDate>
        <Links>
            <HyperMediaLink>
                <Rel>self</Rel>
                <Href>https://localhost:44300/api/book/v1/2</Href>
                <Type>application/json</Type>
                <Action>GET</Action>
            </HyperMediaLink>
            <HyperMediaLink>
                <Rel>self</Rel>
                <Href>https://localhost:44300/api/book/v1/2</Href>
                <Type>application/json</Type>
                <Action>POST</Action>
            </HyperMediaLink>
            <HyperMediaLink>
                <Rel>self</Rel>
                <Href>https://localhost:44300/api/book/v1/2</Href>
                <Type>application/json</Type>
                <Action>PUT</Action>
            </HyperMediaLink>
            <HyperMediaLink>
                <Rel>self</Rel>
                <Href>https://localhost:44300/api/book/v1/2</Href>
                <Type>int</Type>
                <Action>DELETE</Action>
            </HyperMediaLink>
        </Links>
    </BookVO>
</ArrayOfBookVO>

Suggestions are welcome. Feel free to sugest improvements.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
8.0.101.3 161 2/11/2024
8.0.101.2 114 2/11/2024
1.0.25 103 2/10/2024
1.0.24 129 2/10/2024
1.0.21 121 2/10/2024
1.0.19 130 2/10/2024
1.0.18 117 2/10/2024
1.0.17 104 2/10/2024
1.0.16 120 2/10/2024
1.0.15 114 2/10/2024
1.0.14 106 2/10/2024
1.0.13 91 2/10/2024
1.0.12 138 2/10/2024
1.0.11 116 2/10/2024
1.0.10 107 2/10/2024
1.0.9 110 2/10/2024
1.0.8 109 2/10/2024
1.0.7 107 2/10/2024
1.0.6 118 2/10/2024
1.0.5 114 2/9/2024
1.0.4 5,929 5/20/2018

This is a smart library to implements HATEOAS docummentation in your RESTFul API's