I am evaluating how to add hypermedia links to DTO responses. Although there is no standard, add List to the response DTOs seems to be the suggested approach.
Do yo
The way I do this currently is I pass back a response dto which implements an interface
public interface IHaveLinks
{
[IgnoreDataMember]
IEnumerable Links { get; }
}
public class Link
{
public string Name { get; set; }
public IReturn Request { get; set; }
public string Method { get; set; }
}
Then I use a response filter to generate the urls and populate the response headers with the links.
this.ResponseFilters.Add((req, res, dto) =>
{
if (!(dto is IHaveLinks))
return;
var links = (dto as IHaveLinks).Links
if(links == null || !links.Any())
return;
var linksText = links
.Select(x => string.Format("<{0}>; rel={1}"), x.Request.ToUrl(x.Method), x.Name));
var linkHeader = string.Join(", ", linksText);
res.AddHeader("Link", linkHeader);
});
This seems the cleanest way. The Link
object above effectively says "If you make this request with this method you will get back the named resource". The only HTTP thing that bleeds up to the BLL is Method
. But you could get rid of that and only pass back GET urls. Or map it to some generalised "operation"?
As an example:
public class ExampleService : Service
{
public ExamplesResponse Get(ExamplesRequest request)
{
var page = request.Page;
var data = // get data;
return new ExamplesResponse
{
Examples = data,
Links = new []
{
new Link { Name = "next", Request = request.AddPage(1), Method = "GET" },
new Link { Name = "previous", Request = request.AddPage(-1), Method = "GET" },
}
}
}
}
[Route("/examples/{Page}")]
public class ExamplesRequest : IReturn
{
public int Page { get; set; }
// ...
}
(The AddPage
method returns a clone of the request and sets the Page property appropriately.)
Hope that helps.