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

Use IResourceService outside of the path of a request

verdie-g opened this issue · comments

I would need to create a resource outside of the path of a JSON:API request. My exact use-case is in the redirection endpoint of an OpenID authentication, I need to get or create a user so I wrote something like that

var userService = ctx.HttpContext.RequestServices.GetRequiredService<IResourceService<User, long>>();
User? user = null;
try
{
     user = await userService.GetAsync(userId, CancellationToken.None);
}
catch (ResourceNotFoundException)
{
}

if (user == null)
{
    user = new User
    {
        Id = userId,
    };
    await userService.CreateAsync(user, CancellationToken.None);
}

unfortunately it throws InvalidOperationException: Expected IJsonApiRequest.PrimaryResourceType not to be null at this point.

Is this use-case supported?

In a regular request, IJsonApiRequest is populated by the middleware, which the rest of the pipeline depends on. It's one of those ambient interfaces, listed at https://www.jsonapi.net/getting-started/faq.html#what-if-i-want-to-use-something-other-than-entity-framework-core. In your case, try something like the following:

var request = (JsonApiRequest)ctx.HttpContext.RequestServices.GetRequiredService<IJsonApiRequest>();
var resourceGraph = ctx.HttpContext.RequestServices.GetRequiredService<IResourceGraph>();

request.Kind = EndpointKind.Primary;
request.PrimaryResourceType = resourceGraph.GetResourceType<User>();

For the CreateAsync call, you'll need to set up ITargetedFields likewise.

Thanks! Would it make sense to make that use-case smoother (e g. No downcast, no manually building an object). It looks like I would be relying on implementation details here and the use-case is not that exotic. Another similar use-case would be a IHostedService to periodically make some db operations.

What do you have in mind? It's quite similar to trying to unittest a method that depends on HttpContext: you'll need to set one up yourself because there's none available. I consider this an advanced use case and am fine with it being not too straightforward, because it's easy to mess things up. It can be done, but it requires to know what's going on. Similar to #1144.

You can call CopyFrom instead of the cast. And it's not really relying on implementation details, these types are public for usages like this.

What do you have in mind?

In my latest large project I had 3 workers (https://github.com/verdie-g/crpg/tree/master/src/WebApi/Workers). I suppose I could get away with your code snippet but I feel like I always have these kinds of workers in my project.

I meant to ask: in what way do you think JsonApiDotNetCore should be changed to smoothen your experience? What would that look like?

What I don't understand is why the JADNC pipeline is needed when the background job is just doing database updates. It would be more efficient to directly execute cleanup via EF Core.

What I don't understand is why the JADNC pipeline is needed when the background job is just doing database updates. It would be more efficient to directly execute cleanup via EF Core.

Yes on this point I was thinking that I didn't want to bypass the IResourceService which could contain the business logic but I believe directly using EF Core would perfectly work in my use-cases. I think you would know better than me if in the general case it's acceptable to bypass IResourceService.

Yeah, sounds like you don't need things like consuming query string parameters, detecting side-effects during update, model state validation, counting resources, render links, etc.

Alright, thanks your answers! I'll close the issue for now and I may re-open later in my project if I find out that it's a real issue.