From 4a6d62571c4ea5b3b7a8b1663a0637d02d9a9569 Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Wed, 13 May 2020 16:40:12 +0200 Subject: [PATCH] Fixed: fail on filtering to-many relationships (crashes later otherwise) Fixed: filters are not applied in GetById reauests --- .../QueryParameterServices/FilterService.cs | 7 +++ .../Services/DefaultResourceService.cs | 2 + .../Acceptance/Spec/AttributeFilterTests.cs | 46 +++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/src/JsonApiDotNetCore/QueryParameterServices/FilterService.cs b/src/JsonApiDotNetCore/QueryParameterServices/FilterService.cs index 0e3c4f3b8d..3af41bdb41 100644 --- a/src/JsonApiDotNetCore/QueryParameterServices/FilterService.cs +++ b/src/JsonApiDotNetCore/QueryParameterServices/FilterService.cs @@ -63,6 +63,13 @@ private FilterQueryContext GetQueryContexts(FilterQuery query, string parameterN queryContext.Relationship = GetRelationship(parameterName, query.Relationship); var attribute = GetAttribute(parameterName, query.Attribute, queryContext.Relationship); + if (queryContext.Relationship is HasManyAttribute) + { + throw new InvalidQueryStringParameterException(parameterName, + "Filtering on one-to-many and many-to-many relationships is currently not supported.", + $"Filtering on the relationship '{queryContext.Relationship.PublicRelationshipName}.{attribute.PublicAttributeName}' is currently not supported."); + } + if (!attribute.Capabilities.HasFlag(AttrCapabilities.AllowFilter)) { throw new InvalidQueryStringParameterException(parameterName, "Filtering on the requested attribute is not allowed.", diff --git a/src/JsonApiDotNetCore/Services/DefaultResourceService.cs b/src/JsonApiDotNetCore/Services/DefaultResourceService.cs index dac9ee7aff..2494c8ac0f 100644 --- a/src/JsonApiDotNetCore/Services/DefaultResourceService.cs +++ b/src/JsonApiDotNetCore/Services/DefaultResourceService.cs @@ -143,8 +143,10 @@ public virtual async Task GetAsync(TId id) _hookExecutor?.BeforeRead(pipeline, id.ToString()); var entityQuery = _repository.Get(id); + entityQuery = ApplyFilter(entityQuery); entityQuery = ApplyInclude(entityQuery); entityQuery = ApplySelect(entityQuery); + var entity = await _repository.FirstOrDefaultAsync(entityQuery); if (entity == null) diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs index 71b3e7c36e..07a3a8f65b 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs @@ -89,6 +89,52 @@ public async Task Can_Filter_On_Related_Attrs() list.Owner.FirstName = person.FirstName; } + [Fact] + public async Task Can_Filter_On_Related_Attrs_From_GetById() + { + // Arrange + var context = _fixture.GetService(); + var person = _personFaker.Generate(); + var todoItem = _todoItemFaker.Generate(); + todoItem.Owner = person; + context.TodoItems.Add(todoItem); + await context.SaveChangesAsync(); + + var httpMethod = new HttpMethod("GET"); + var route = $"/api/v1/todoItems/{todoItem.Id}?include=owner&filter[owner.firstName]=SOMETHING-ELSE"; + var request = new HttpRequestMessage(httpMethod, route); + + // Act + var response = await _fixture.Client.SendAsync(request); + var body = await response.Content.ReadAsStringAsync(); + + // Assert + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + public async Task Cannot_Filter_On_Related_ToMany_Attrs() + { + // Arrange + var httpMethod = new HttpMethod("GET"); + var route = "/api/v1/todoItems?include=childrenTodos&filter[childrenTodos.ordinal]=1"; + var request = new HttpRequestMessage(httpMethod, route); + + // Act + var response = await _fixture.Client.SendAsync(request); + + // Assert + var body = await response.Content.ReadAsStringAsync(); + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + + var errorDocument = JsonConvert.DeserializeObject(body); + Assert.Single(errorDocument.Errors); + Assert.Equal(HttpStatusCode.BadRequest, errorDocument.Errors[0].StatusCode); + Assert.Equal("Filtering on one-to-many and many-to-many relationships is currently not supported.", errorDocument.Errors[0].Title); + Assert.Equal("Filtering on the relationship 'childrenTodos.ordinal' is currently not supported.", errorDocument.Errors[0].Detail); + Assert.Equal("filter[childrenTodos.ordinal]", errorDocument.Errors[0].Source.Parameter); + } + [Fact] public async Task Cannot_Filter_If_Explicitly_Forbidden() {