json-api-dotnet/JsonApiDotNetCore

Async GetMeta resource definition hook

kostas-kapasakis opened this issue · 5 comments

Is your feature request related to a problem? Please describe.
No

Describe the solution you'd like
It would be ideal to be able to have an asynchronous GetMetaAsync in order to use Repositories and Services to provide resource specific information.,

In several scenarios that we may want to show meta information for each resource which are not static , the current synchronous implementation unfortunately would lead to break async , await chains that would lead to performance issues,

An example is a scenario in which the meta section would hold authorization information for the resource and would retrieve them from a logic that required data from DB , thus services and repositories calls .

Describe alternatives you've considered
As alternative solutions currently we have thought that we either add a respective property in the resource class or just using GetAwaiter().GetResult() in the asynchronous calls inside the GetMeta().

Additional context
Not sure if the GetMeta has a different scope or wasnt meant to be dealing with async operations , so please correct me if thats the case.

Thanks in advance.

It's unclear to me what you're proposing. Where would this method exist? IResourceDefinition.GetMeta executes as part of rendering the response, I don't like the idea of executing additional queries from there, which introduces an N+1 problem. I would expect such logic to run from IResourceService if the data originates from another system, or as part of IResourceRepository if the data exists in the same database (joined with the existing query). From there, it could be stored in the resource itself (in a non-publicly exposed property), which gets later converted to JSON:API meta. It highly depends on what exactly you need.

Hello @bkoelman thanks for the response.

I like the idea that you propose , but as far as I searched I wasnt able to affect the resource's meta section outside of the GetMeta hook.

Is there a way to affect the resource's meta section outside of the GetMeta hook ?

No, there isn't, that's why I suggested to fetch the data upfront and store in it resource properties, so it's available for you to produce meta.

I see . thanks now it makes more sense.

In terms of timing , would you suggest fetching data on the service or is there a more suitable definition hook for that ?

As I said, it depends on what you need.

  • If the information to produce meta exists in the same database table, it's most efficient to include these properties on the resource class directly. You can hide them from the outside while still being able to reference them by adding [Attr(Capabilities = AttrCapabilities.None)] on them, and then force fetching them from IResourceDefinition.OnApplySparseFieldSet using the .Including() extension method.
  • If the information exists in another table, you'll need to query it yourself by overriding methods on IResourceService. Something like:
    var ids = resources.Select(resource => resource.Id).ToArray();
    var metaEntries =
        from row in otherTable
        where ids.Contains(row.ResourceId)
        select row;
    and store the results in a scoped object that you inject in your IResourceDefinition.
  • If the information exists in an external system, it entirely depends on what API is available to fetch what you need. Try to avoid executing 10 extra queries (assuming a page size of 10), which is far worse than GetAwaiter().GetResult().

Provide the exact details on what you're trying to accomplish, including which endpoints need to contain meta, where the data comes from, etc. if you need more specific guidance.