Skip to content

Question: How to handle resource creation where attribute values depend on business logic #961

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
VincentVrijburg opened this issue Mar 3, 2021 · 4 comments
Labels

Comments

@VincentVrijburg
Copy link

DESCRIPTION

I have multiple resources where attributes and relations are required (set through the fluent API in the EF Core context).
Although I set the values of those attributes and relations, in my custom (overridden) controller method, it seems like JADNC ignores those values on creation.

What is the recommended approach?

STEPS TO REPRODUCE

JsonApi service:

services.AddJsonApi<DatabaseContext>(options =>
{
    options.Namespace = "v1";
    options.DefaultAttrCapabilities = AttrCapabilities.AllowView | AttrCapabilities.AllowSort |
                                      AttrCapabilities.AllowFilter;
    options.SerializerSettings.Formatting = Formatting.Indented;
});

Example resource

public class Example : Identifiable<Guid>
{
    // Required
    public string UserId { get; set; }
    public User User { get; set; }

    // Set through the json api
    [Attr(Capabilities = AttrCapabilities.AllowCreate | AttrCapabilities.AllowView | AttrCapabilities.AllowSort | AttrCapabilities.AllowFilter)]
    public string Query { get; set; }
    
    // Required
    [Attr]
    public string Value { get; set; }
    
    // Set automatically on create and update (trigger)
    [Attr]
    public DateTime Updated { get; set; }
    
    // Set automatically on create (trigger)
    [Attr]
    public DateTime Created { get; set; }
}

Example controller

[Authorize]
[NoHttpPatch]
[NoHttpDelete]
public class ExampleController : JsonApiController<Example, Guid>
{
    public ExampleController(
        IJsonApiOptions options, 
        ILoggerFactory loggerFactory, 
        IResourceService<Example, Guid> resourceService)
        : base(options, loggerFactory, resourceService)
    {
    }

    [HttpPost]
    public override async Task<IActionResult> PostAsync(Example resource, CancellationToken cancellationToken)
    {
        //var businessLogicResult = ...

        resource.UserId = HttpContext.User.GetUserId();
        resource.Value = businessLogicResult.value;
        resource.Requested = businessLogicResult.requestDate;
        
        return await base.PostAsync(resource, cancellationToken);
    }
}

EXPECTED BEHAVIOR

I expect the resource to be created with the assigned values.

ACTUAL BEHAVIOR

Violation of not-null constraints for resources with required attributes and relations (DbUpdateException).

VERSIONS USED

  • JsonApiDotNetCore version: 4.0.3
  • ASP.NET Core version: 3.1.12
  • Entity Framework Core version: 3.1.12
  • Database provider: Postgres
@bart-degreed
Copy link
Contributor

See this example.

@VincentVrijburg
Copy link
Author

The example definitely helps for required relationships and attributes but the question of where I should place the business logic emerges.

Only the attributes which are marked with the Create capability get copied over from resourceFromRequest to resourceForDatabase, in the {resource}Repository. This is understandable when you solely rely on the input from the request, but in my case, most of the attributes will be set based on business logic (dependent on one of the attributes in the request payload).

Are there any examples of this?

@bart-degreed
Copy link
Contributor

The Create capability is only used for request body validation and plays no role in copying. If you have properties whose value directly depends on other resource properties, I would make them calculated properties instead. But if they depend on injected services, you'll need to do something similar to what's described here (override CreateAsync).

We intend to make all this easier with #934 (suggestions welcome).

@bart-degreed
Copy link
Contributor

Closing, because the question has been answered,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

2 participants