diff --git a/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs b/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs index ca6caad1f8..923ca074e5 100644 --- a/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs @@ -139,6 +139,18 @@ protected virtual List<AttrAttribute> GetAttributes(Type entityType) foreach (var prop in properties) { + if (prop.Name == nameof(Identifiable.Id)) + { + var idAttr = new AttrAttribute() + { + PublicAttributeName = JsonApiOptions.ResourceNameFormatter.FormatPropertyName(prop), + PropertyInfo = prop, + InternalAttributeName = prop.Name + }; + attributes.Add(idAttr); + continue; + } + var attribute = (AttrAttribute)prop.GetCustomAttribute(typeof(AttrAttribute)); if (attribute == null) continue; diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs index 82c3d2ec75..5261140e5d 100644 --- a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs @@ -141,6 +141,7 @@ public ResourceObject GetData(ContextEntity contextEntity, IIdentifiable entity, private bool ShouldIncludeAttribute(AttrAttribute attr, object attributeValue) { return OmitNullValuedAttribute(attr, attributeValue) == false + && attr.InternalAttributeName != nameof(Identifiable.Id) && ((_jsonApiContext.QuerySet == null || _jsonApiContext.QuerySet.Fields.Count == 0) || _jsonApiContext.QuerySet.Fields.Contains(attr.InternalAttributeName)); @@ -280,10 +281,13 @@ private ResourceObject GetIncludedEntity(IIdentifiable entity) data.Attributes = new Dictionary<string, object>(); - contextEntity.Attributes.ForEach(attr => + foreach(var attr in contextEntity.Attributes) { + if (attr.InternalAttributeName == nameof(Identifiable.Id)) + continue; + data.Attributes.Add(attr.PublicAttributeName, attr.GetValue(entity)); - }); + } return data; } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs index 618db7dd10..69bcccb2a2 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs @@ -69,6 +69,54 @@ public async Task Can_Get_TodoItems() Assert.True(deserializedBody.Count <= expectedEntitiesPerPage); } + [Fact] + public async Task Can_Filter_By_Resource_Id() + { + // Arrange + var todoItem = _todoItemFaker.Generate(); + _context.TodoItems.Add(todoItem); + _context.SaveChanges(); + + var httpMethod = new HttpMethod("GET"); + var route = $"/api/v1/todo-items?filter[id]={todoItem.Id}"; + var request = new HttpRequestMessage(httpMethod, route); + + // Act + var response = await _fixture.Client.SendAsync(request); + var body = await response.Content.ReadAsStringAsync(); + var deserializedBody = _fixture.GetService<IJsonApiDeSerializer>().DeserializeList<TodoItem>(body); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotEmpty(deserializedBody); + Assert.Contains(deserializedBody, (i) => i.Id == todoItem.Id); + } + + [Fact] + public async Task Can_Filter_By_Relationship_Id() + { + // Arrange + var person = new Person(); + var todoItem = _todoItemFaker.Generate(); + todoItem.Owner = person; + _context.TodoItems.Add(todoItem); + _context.SaveChanges(); + + var httpMethod = new HttpMethod("GET"); + var route = $"/api/v1/todo-items?filter[owner.id]={person.Id}"; + var request = new HttpRequestMessage(httpMethod, route); + + // Act + var response = await _fixture.Client.SendAsync(request); + var body = await response.Content.ReadAsStringAsync(); + var deserializedBody = _fixture.GetService<IJsonApiDeSerializer>().DeserializeList<TodoItem>(body); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotEmpty(deserializedBody); + Assert.Contains(deserializedBody, (i) => i.OwnerId == person.Id); + } + [Fact] public async Task Can_Filter_TodoItems() { diff --git a/test/UnitTests/Builders/ContextGraphBuilder_Tests.cs b/test/UnitTests/Builders/ContextGraphBuilder_Tests.cs index eab003309f..a88ecceb67 100644 --- a/test/UnitTests/Builders/ContextGraphBuilder_Tests.cs +++ b/test/UnitTests/Builders/ContextGraphBuilder_Tests.cs @@ -94,7 +94,7 @@ public void Attrs_Without_Names_Specified_Will_Use_Default_Formatter() // assert var resource = graph.GetContextEntity(typeof(TestResource)); - Assert.Equal("compound-attribute", resource.Attributes.Single().PublicAttributeName); + Assert.Contains(resource.Attributes, (i) => i.PublicAttributeName == "compound-attribute"); } [Fact] @@ -110,7 +110,7 @@ public void Attrs_Without_Names_Specified_Will_Use_Configured_Formatter() // assert var resource = graph.GetContextEntity(typeof(TestResource)); - Assert.Equal("compoundAttribute", resource.Attributes.Single().PublicAttributeName); + Assert.Contains(resource.Attributes, (i) => i.PublicAttributeName == "compoundAttribute"); } [Fact]