Skip to content

Commit 4bbd1b6

Browse files
committed
fix: remove filter
1 parent 6464d1e commit 4bbd1b6

File tree

5 files changed

+84
-92
lines changed

5 files changed

+84
-92
lines changed

src/JsonApiDotNetCore/Configuration/JsonApiApplicationBuilder.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ public void ConfigureMvc()
9292
{
9393
options.EnableEndpointRouting = true;
9494
options.Filters.AddService<IAsyncJsonApiExceptionFilter>();
95-
options.Filters.AddService<IAsyncResourceTypeMatchFilter>();
9695
options.Filters.AddService<IAsyncQueryStringActionFilter>();
9796
options.Filters.AddService<IAsyncConvertEmptyActionResultFilter>();
9897
ConfigureMvcOptions?.Invoke(options);
@@ -159,7 +158,6 @@ private void AddMiddlewareLayer()
159158
_services.AddSingleton<IJsonApiApplicationBuilder>(this);
160159
_services.TryAddSingleton<IExceptionHandler, ExceptionHandler>();
161160
_services.TryAddScoped<IAsyncJsonApiExceptionFilter, AsyncJsonApiExceptionFilter>();
162-
_services.TryAddScoped<IAsyncResourceTypeMatchFilter, AsyncResourceTypeMatchFilter>();
163161
_services.TryAddScoped<IAsyncQueryStringActionFilter, AsyncQueryStringActionFilter>();
164162
_services.TryAddScoped<IAsyncConvertEmptyActionResultFilter, AsyncConvertEmptyActionResultFilter>();
165163
_services.TryAddSingleton<IJsonApiInputFormatter, JsonApiInputFormatter>();

src/JsonApiDotNetCore/Middleware/AsyncResourceTypeMatchFilter.cs

Lines changed: 0 additions & 75 deletions
This file was deleted.

src/JsonApiDotNetCore/Middleware/IAsyncResourceTypeMatchFilter.cs

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/JsonApiDotNetCore/Serialization/JsonApiReader.cs

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
using System;
22
using System.Collections;
3+
using System.Collections.Generic;
34
using System.IO;
5+
using System.Net.Http;
6+
using System.Linq;
47
using System.Threading.Tasks;
8+
using JsonApiDotNetCore.Configuration;
59
using JsonApiDotNetCore.Errors;
610
using JsonApiDotNetCore.Middleware;
711
using JsonApiDotNetCore.Resources;
812
using JsonApiDotNetCore.Serialization.Objects;
13+
using Microsoft.AspNetCore.Http;
914
using Microsoft.AspNetCore.Http.Extensions;
1015
using Microsoft.AspNetCore.Mvc.Formatters;
1116
using Microsoft.Extensions.Logging;
@@ -16,17 +21,20 @@ namespace JsonApiDotNetCore.Serialization
1621
public class JsonApiReader : IJsonApiReader
1722
{
1823
private readonly IJsonApiDeserializer _deserializer;
19-
private readonly IJsonApiRequest _request;
24+
private readonly IJsonApiRequest _jsonApiRequest;
25+
private readonly IResourceContextProvider _resourceContextProvider;
2026
private readonly TraceLogWriter<JsonApiReader> _traceWriter;
2127

2228
public JsonApiReader(IJsonApiDeserializer deserializer,
23-
IJsonApiRequest request,
29+
IJsonApiRequest jsonApiRequest,
30+
IResourceContextProvider resourceContextProvider,
2431
ILoggerFactory loggerFactory)
2532
{
2633
if (loggerFactory == null) throw new ArgumentNullException(nameof(loggerFactory));
2734

2835
_deserializer = deserializer ?? throw new ArgumentNullException(nameof(deserializer));
29-
_request = request ?? throw new ArgumentNullException(nameof(request));
36+
_jsonApiRequest = jsonApiRequest ?? throw new ArgumentNullException(nameof(jsonApiRequest));
37+
_resourceContextProvider = resourceContextProvider;
3038
_traceWriter = new TraceLogWriter<JsonApiReader>(loggerFactory);
3139
}
3240

@@ -63,22 +71,46 @@ public async Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
6371

6472
ValidatePatchRequestIncludesId(context, model, body);
6573

74+
ValidateIncomingResourceType(context, model);
75+
6676
return await InputFormatterResult.SuccessAsync(model);
6777
}
6878

79+
private void ValidateIncomingResourceType(InputFormatterContext context, object model)
80+
{
81+
if (context.HttpContext.IsJsonApiRequest() && IsPatchOrPostRequest(context.HttpContext.Request))
82+
{
83+
var endPointResourceTypes = GetEndpointResourceType();
84+
var bodyResourceTypes = GetBodyResourceTypes(model);
85+
86+
foreach (var bodyResourceType in bodyResourceTypes)
87+
{
88+
if (bodyResourceType != null && endPointResourceTypes != null && bodyResourceType != endPointResourceTypes)
89+
{
90+
var resourceFromEndpoint = _resourceContextProvider.GetResourceContext(endPointResourceTypes);
91+
var resourceFromBody = _resourceContextProvider.GetResourceContext(bodyResourceType);
92+
93+
throw new ResourceTypeMismatchException(new HttpMethod(context.HttpContext.Request.Method),
94+
context.HttpContext.Request.Path,
95+
resourceFromEndpoint, resourceFromBody);
96+
}
97+
}
98+
}
99+
}
100+
69101
private void ValidatePatchRequestIncludesId(InputFormatterContext context, object model, string body)
70102
{
71-
if (context.HttpContext.Request.Method == "PATCH")
103+
if (context.HttpContext.Request.Method == HttpMethods.Patch)
72104
{
73105
bool hasMissingId = model is IList list ? HasMissingId(list) : HasMissingId(model);
74106
if (hasMissingId)
75107
{
76108
throw new InvalidRequestBodyException("Payload must include 'id' element.", null, body);
77109
}
78110

79-
if (_request.Kind == EndpointKind.Primary && TryGetId(model, out var bodyId) && bodyId != _request.PrimaryId)
111+
if (_jsonApiRequest.Kind == EndpointKind.Primary && TryGetId(model, out var bodyId) && bodyId != _jsonApiRequest.PrimaryId)
80112
{
81-
throw new ResourceIdMismatchException(bodyId, _request.PrimaryId, context.HttpContext.Request.GetDisplayUrl());
113+
throw new ResourceIdMismatchException(bodyId, _jsonApiRequest.PrimaryId, context.HttpContext.Request.GetDisplayUrl());
82114
}
83115
}
84116
}
@@ -134,5 +166,27 @@ private async Task<string> GetRequestBody(Stream body)
134166
// https://github.com/aspnet/AspNetCore/issues/7644
135167
return await reader.ReadToEndAsync();
136168
}
169+
170+
private bool IsPatchOrPostRequest(HttpRequest request)
171+
{
172+
return request.Method == HttpMethods.Patch || request.Method == HttpMethods.Post;
173+
}
174+
175+
private IEnumerable<Type> GetBodyResourceTypes(object model)
176+
{
177+
if (model is ICollection<IIdentifiable> resourceCollection)
178+
{
179+
return resourceCollection.Select(r => r.GetType()).Distinct();
180+
}
181+
182+
return model == null ? new Type[0] : new[] { model.GetType() };
183+
}
184+
185+
private Type GetEndpointResourceType()
186+
{
187+
return _jsonApiRequest.Kind == EndpointKind.Primary
188+
? _jsonApiRequest.PrimaryResource.ResourceType
189+
: _jsonApiRequest.SecondaryResource?.ResourceType;
190+
}
137191
}
138192
}

test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/ResourceTypeMismatchTests.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,29 @@ public async Task Patching_Through_Relationship_Link_With_Mismatching_Resource_T
8080
Assert.Equal("Resource type mismatch between request body and endpoint URL.", errorDocument.Errors[0].Title);
8181
Assert.Equal("Expected resource of type 'people' in PATCH request body at endpoint '/api/v1/todoItems/1/relationships/owner', instead of 'todoItems'.", errorDocument.Errors[0].Detail);
8282
}
83+
84+
[Fact]
85+
public async Task Patching_Through_Relationship_Link_With_Multiple_Resources_Types_Returns_Conflict()
86+
{
87+
// Arrange
88+
string content = JsonConvert.SerializeObject(new
89+
{
90+
data = new object[]
91+
{
92+
new { type = "todoItems", id = 1 },
93+
new { type = "articles", id = 2 },
94+
}
95+
});
96+
97+
// Act
98+
var (body, _) = await Patch("/api/v1/todoItems/1/relationships/childrenTodos", content);
99+
100+
// Assert
101+
var errorDocument = JsonConvert.DeserializeObject<ErrorDocument>(body);
102+
Assert.Single(errorDocument.Errors);
103+
Assert.Equal(HttpStatusCode.Conflict, errorDocument.Errors[0].StatusCode);
104+
Assert.Equal("Resource type mismatch between request body and endpoint URL.", errorDocument.Errors[0].Title);
105+
Assert.Equal("Expected resource of type 'todoItems' in PATCH request body at endpoint '/api/v1/todoItems/1/relationships/childrenTodos', instead of 'articles'.", errorDocument.Errors[0].Detail);
106+
}
83107
}
84108
}

0 commit comments

Comments
 (0)