Skip to content

IValidatableObject validation executed on relationship objects #1204

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
Tommy228 opened this issue Oct 24, 2022 · 2 comments
Closed

IValidatableObject validation executed on relationship objects #1204

Tommy228 opened this issue Oct 24, 2022 · 2 comments
Labels

Comments

@Tommy228
Copy link
Contributor

DESCRIPTION

When I use an object implementing IValidatableObject on a relationship with linkage data only, then the validation is still executed.

This bug looks similar to #671 which had the same issue when using the [Required] attribute.

STEPS TO REPRODUCE

Consider the following models

[Resource]
public class Library : Identifiable<int>, IValidatableObject
{
    [Attr, Required] public string? Name { get; set; }

    [HasMany] public ICollection<Book> Books { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        // Should never happen as we have the [Required] attribute
        // However, this is still called when used on a relationship
        if (Name == null)
        {
            yield return new ValidationResult("Name is mandatory");
        }
    }
}

[Resource]
public class Book : Identifiable<int>
{
    [Attr] public string? Name { get; set; }

    [HasOne] public Library Library { get; set; }
}

First, create a library

{
    "data": {
        "type": "libraries",
        "attributes": {
            "name": "Test library"
        },
        "relationships": {
            "books": {
                "data": []
            }
        }
    }
}

Then, create a book and associate it with the created library.

{
    "data": {
        "type": "books",
        "attributes": {
            "name": "Test book"
        },
        "relationships": {
            "library": {
                "data": { 
                    "type": "libraries",
                    "id": "1" 
                }
            }
        }
    }
}

EXPECTED BEHAVIOR

The book is created.

ACTUAL BEHAVIOR

The custom validation code from Library is executed, causing this error

{
    "links": {
        "self": "http://localhost:5000/v1/books"
    },
    "errors": [
        {
            "id": "5d84f0da-0432-49e4-9214-6e4476fd35d6",
            "status": "422",
            "title": "Input validation failed.",
            "detail": "Name is mandatory",
            "source": {
                "pointer": "/data/relationships/library/data"
            }
        }
    ]
}

VERSIONS USED

  • JsonApiDotNetCore version: 5.0.3
  • ASP.NET Core version: 6.0.301
  • Entity Framework Core version: 6.0.10
  • Database provider: pgsql
@Tommy228 Tommy228 added the bug label Oct 24, 2022
@bkoelman
Copy link
Member

Hi @Tommy228, thanks for the detailed report.

To fix this, your implementation of IValidatableObject needs to do something similar to https://github.com/json-api-dotnet/JsonApiDotNetCore/blob/master/src/JsonApiDotNetCore/Configuration/JsonApiValidationFilter.cs.

The problem is that JSON:API uses partially filled objects in post/patch resource endpoints, or even objects with only Id populated. To distinguish between "this incoming property is invalid" vs "this property was never sent, so it contains a default value", inject and inspect ITargetedFields to choose what validation is actually needed.

I don't think there's anything we can fix in JADNC to solve this, therefore I don't think this is a bug.

@Tommy228
Copy link
Contributor Author

Hi @bkoelman, I tried the suggested solution with ITargetedFields and it indeed works, so I guess we can close this. Thanks for your time.

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