M. Koch
M. Koch

Reputation: 822

How to generate HATEOAS links for paging in ASP.NET Core 6 Web API controller to return in Link header?

I need to create HATEOAS pagination links for first, last, next, and previous and add them to the Link header of the response.

A PagedResultDTO is returned from the application layer to the controller in the API layer. Besids the records it holds information about TotalCount, PageNumber, PageSize, and PageCount.

I'm confused with the options provided by the framework. Many posts use UriHelper, but it seems that LinkGenerator is the newer and the current helper class. Looking at the documentation I don't understand the difference of the various methods that LinkGenerator provides. Is there any good post that explains the use cases for the various methods?

Since a request can have various other query parameters e.g. for sorting, filtering, searching, embedding they need to be kept and returned when the links get created. E.g. a controller declaration can look like:

public ActionResult<PagedResultDTO<GetCountriesDTO>> GetCountries(
   [FromHeader(Name = "If-None-Match")] string? eTags, 
   [CommaSeparated] IEnumerable<string> languages, 
   string? sort, 
   string? search, 
   int? pageNumber, 
   int? pageSize)

([CommaSeperated] is an extension that accepts multiple values separated by comma and creates a List without having to repeat the query parameter. If pageNumber and pageCount are not set and don't have default values set in a specific controller method my use case handlers will set default values.)

For a request like:

GET https://example.com/api/countries?languages=de-DE,en-US&sort=name

I need to generate:

<https://example.com/api/countries?languages=de-DE,en-US&sort=name&pageNumber=2&pageSize=20>; rel="next",
<https://example.com/api/countries?languages=de-DE,en-US&sort=name&pageNumber=1&pageSize=20>; rel="first",
<https://example.com/api/countries?languages=de-DE,en-US&sort=name&pageNumber=10&pageSize=20>; rel="last"

All query parameters not related to paging need to be kept in the generated links. Does LinkGenerator support a straightforward way to generate those pagination links? Is there any structure that supports the Link header format already? I wonder if should just create the links manually using the Request object?

Upvotes: 0

Views: 903

Answers (1)

M. Koch
M. Koch

Reputation: 822

I created now my own code using a dictionary that holds the passed query parameters.

Dictionary<string, string> query = new();
foreach (KeyValuePair<string, StringValues> item in httpContext.Request.Query)
{
    query.Add(item.Key, string.Join(",", item.Value));
}

I then update pageNumber and pageSize for each link. If it was not set before and defaults are used the parameters are added, e.g.:

query["pageNumber"] = "1";
query["pageSize"] = pageSize.ToString();

I then use LinkGenerator to create the link:

linkGenerator.GetUriByAction(httpContext, values: query)

Upvotes: 1

Related Questions