json-api-dotnet / JsonApiDotNetCore

A framework for building JSON:API compliant REST APIs using ASP.NET and Entity Framework Core.

Home Page:https://www.jsonapi.net

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Customize paging for each controller ?

patcharees opened this issue · comments

SUMMARY

I developed a service that provides multiples APIs. One API has no paging feature (return all data), the rest have paging. How can I customize paging feature for each controller?

DETAILS

I set global options by
options.DefaultPageSize = new PageSize(10);

but for a specific controller I want
options.DefaultPageSize = null;

How can I do that?

STEPS TO REPRODUCE

  1. On start up
services.AddJsonApi(
    options =>
    {
        options.Namespace = "api/v1";
        options.IncludeTotalResourceCount = true;
        options.DefaultPageSize = new PageSize(10); //null
        options.MaximumPageSize = new PageSize(100);
        options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver()
        {
            NamingStrategy = new Newtonsoft.Json.Serialization.CamelCaseNamingStrategy(false, false),
        };
        options.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
        options.ValidateModelState = true;

        options.UseRelativeLinks = true;
        options.ResourceLinks = JsonApiDotNetCore.Resources.Annotations.LinkTypes.None;
        options.TopLevelLinks = JsonApiDotNetCore.Resources.Annotations.LinkTypes.Paging;
        options.RelationshipLinks = JsonApiDotNetCore.Resources.Annotations.LinkTypes.None;
    },
    resources: builder =>
    {
        builder.Add<Resource1, string>("res1");
        builder.Add<Resource2, string>("res2");
        builder.Add<Resource3, string>("res3");
    });

VERSIONS USED

  • JsonApiDotNetCore version: 4,2.0

Have you tried sending ?page[size]=0?

I got an error below when specify ?page[size]=0.
However I expect there is a solution that I can override in the code; means no need to add the page size in the URL.

{
    "errors": [
        {
            "id": "b8f852fc-d369-4566-b924-e1f797b1938f",
            "status": "400",
            "title": "The specified paging is invalid.",
            "detail": "Page size cannot be unconstrained.",
            "source": {
                "parameter": "page[size]"
            }
        }
    ]
}

You get this error because your code contains options.MaximumPageSize = new PageSize(100). It needs to be removed to allow unconstrained.

The way this works is that global options specify a default page size, which can always be overridden from the request URL. There's no configuration to control this per resource type.

To control the effectively used page size during a request, register your own scoped implementation of IPaginationContext. Because you're using an old version, try adding the registration before and after calling AddJsonApi() to ensure your implementation gets picked up.

Another solution is to create a resource definition for the specific resource type, and overrule the page size to unconstrained at request time. See the sample here, so in your case:

return new PaginationExpression(existingPagination?.PageNumber ?? PageNumber.ValueOne, /* unconstrained */ null);

I tried page[size]=0 and resource definition. They work both. Thanks :)

However is it possible to override options.ResourceLinks by resource definition?

No, but it can be overruled per resource type using an attribute, see https://www.jsonapi.net/api/JsonApiDotNetCore.Configuration.JsonApiOptions.html#JsonApiDotNetCore_Configuration_JsonApiOptions_ResourceLinks. Why do you want to do that from code, ie is there dynamic logic required to determine links visibility?

Thanks!
There are some endpoints (controllers) that return summary of data, which I am thinking to disable links (if possible)

Links visibility is determined in LinkBuilder. You can implement ILinkBuilder yourself to control this. I wouldn't mind making its private Should* methods protected virtual, if it helps. Beware though this affects resource types, not controllers. It matters in cases such as /books/1/author, where BooksController renders Person.

Another place to control this is during serialization. See the IJsonApiWriter and ResponseModelAdapter for details. You can optionally inject IJsonApiRequest to determine the endpoint by inspecting PrimaryResourceType (I'm not taking atomic operations into account here for simplicity).

I decided to override on the resource type, and it works.
Thanks :)

Glad to hear this works for you.