From 4362c5400d2d60161fc7cd476a5be11c634896c0 Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Thu, 22 Feb 2024 01:11:01 +0100 Subject: [PATCH 01/12] Fix spelling error in comment --- test/TestBuildingBlocks/FakerContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/TestBuildingBlocks/FakerContainer.cs b/test/TestBuildingBlocks/FakerContainer.cs index 72f9a05567..c29700c968 100644 --- a/test/TestBuildingBlocks/FakerContainer.cs +++ b/test/TestBuildingBlocks/FakerContainer.cs @@ -34,7 +34,7 @@ private static MethodBase GetTestMethod() if (testMethod == null) { // If called after the first await statement, the test method is no longer on the stack, - // but has been replaced with the compiler-generated async/wait state machine. + // but has been replaced with the compiler-generated async/await state machine. throw new InvalidOperationException("Fakers can only be used from within (the start of) a test method."); } From 330459c2d285cbfb2adbb5ba684ab9f583d8ea07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire?= Date: Sun, 25 Feb 2024 18:33:35 -0500 Subject: [PATCH 02/12] doc: fix POST status code (#1478) --- docs/usage/writing/creating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage/writing/creating.md b/docs/usage/writing/creating.md index ba0a21d52b..7e8a3243af 100644 --- a/docs/usage/writing/creating.md +++ b/docs/usage/writing/creating.md @@ -17,7 +17,7 @@ POST /articles HTTP/1.1 ``` When using client-generated IDs and only attributes from the request have changed, the server returns `204 No Content`. -Otherwise, the server returns `200 OK`, along with the updated resource and its newly assigned ID. +Otherwise, the server returns `201 Created`, along with the updated resource and its newly assigned ID. In both cases, a `Location` header is returned that contains the URL to the new resource. From fe957673dd9a60c881674accdee6219cf775cc55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire?= Date: Mon, 26 Feb 2024 04:20:43 -0500 Subject: [PATCH 03/12] doc: clarify wording around 204 for POST (#1481) * doc: clarify wording around 204 for POST * Update creating.md --- docs/usage/writing/creating.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/usage/writing/creating.md b/docs/usage/writing/creating.md index 7e8a3243af..8cc0c03e49 100644 --- a/docs/usage/writing/creating.md +++ b/docs/usage/writing/creating.md @@ -16,8 +16,8 @@ POST /articles HTTP/1.1 } ``` -When using client-generated IDs and only attributes from the request have changed, the server returns `204 No Content`. -Otherwise, the server returns `201 Created`, along with the updated resource and its newly assigned ID. +When using client-generated IDs and all attributes of the created resource are the same as in the request, the server +returns `204 No Content`. Otherwise, the server returns `201 Created`, along with the stored attributes and its newly assigned ID. In both cases, a `Location` header is returned that contains the URL to the new resource. From 442718726beaa41297a1cead397d558dddada480 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 23:23:24 +0000 Subject: [PATCH 04/12] Bump dotnet-reportgenerator-globaltool from 5.2.1 to 5.2.2 (#1482) --- .config/dotnet-tools.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 9658fff117..240023b45a 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "dotnet-reportgenerator-globaltool": { - "version": "5.2.1", + "version": "5.2.2", "commands": [ "reportgenerator" ] From 7a64b9d9a67689f3fa534cf7df3166f0a25b9277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire?= Date: Tue, 27 Feb 2024 19:59:18 -0500 Subject: [PATCH 05/12] Don't crash on empty query string parameter name (#1484) --- .../QueryStrings/QueryStringReader.cs | 5 +++++ .../QueryStrings/QueryStringTests.cs | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/JsonApiDotNetCore/QueryStrings/QueryStringReader.cs b/src/JsonApiDotNetCore/QueryStrings/QueryStringReader.cs index c412d03c94..e3c944a045 100644 --- a/src/JsonApiDotNetCore/QueryStrings/QueryStringReader.cs +++ b/src/JsonApiDotNetCore/QueryStrings/QueryStringReader.cs @@ -38,6 +38,11 @@ public void ReadAll(DisableQueryStringAttribute? disableQueryStringAttribute) foreach ((string parameterName, StringValues parameterValue) in _queryStringAccessor.Query) { + if (parameterName.Length == 0) + { + continue; + } + IQueryStringParameterReader? reader = _parameterReaders.FirstOrDefault(nextReader => nextReader.CanRead(parameterName)); if (reader != null) diff --git a/test/JsonApiDotNetCoreTests/IntegrationTests/QueryStrings/QueryStringTests.cs b/test/JsonApiDotNetCoreTests/IntegrationTests/QueryStrings/QueryStringTests.cs index 0aa955a219..4f6ee95ad2 100644 --- a/test/JsonApiDotNetCoreTests/IntegrationTests/QueryStrings/QueryStringTests.cs +++ b/test/JsonApiDotNetCoreTests/IntegrationTests/QueryStrings/QueryStringTests.cs @@ -63,6 +63,24 @@ public async Task Can_use_unknown_query_string_parameter() httpResponse.ShouldHaveStatusCode(HttpStatusCode.OK); } + [Theory] + [InlineData("")] + [InlineData("bar")] + public async Task Can_use_empty_query_string_parameter_name(string parameterValue) + { + // Arrange + var options = (JsonApiOptions)_testContext.Factory.Services.GetRequiredService(); + options.AllowUnknownQueryStringParameters = false; + + string route = $"calendars?={parameterValue}"; + + // Act + (HttpResponseMessage httpResponse, Document _) = await _testContext.ExecuteGetAsync(route); + + // Assert + httpResponse.ShouldHaveStatusCode(HttpStatusCode.OK); + } + [Theory] [InlineData("filter")] [InlineData("sort")] From 72bd6f81167efb2f2ebe9edc1f3c390b4f9824a9 Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Sat, 2 Mar 2024 03:59:04 +0100 Subject: [PATCH 06/12] Document PR workflow (#1487) --- .github/CONTRIBUTING.md | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 4205b1ceec..e7d3ce2494 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -39,7 +39,7 @@ When you are creating an enhancement suggestion, please include as many details - **Use a clear and descriptive title** for the issue to identify the suggestion. - **Provide a step-by-step description of the suggested enhancement** in as many details as possible. -- **Provide specific examples to demonstrate the usage.** Include copy/pasteable snippets which you use in those examples, as [Markdown code blocks](https://docs.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks). +- **Provide specific examples to demonstrate the usage.** Include copy/pasteable snippets which you use in those examples as [Markdown code blocks](https://docs.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks). - **Describe the current behavior and explain which behavior you expected to see instead** and why. - **Explain why this enhancement would be useful** to most users and isn't something that can or should be implemented in your API project directly. - **Verify that your enhancement does not conflict** with the [JSON:API specification](https://jsonapi.org/). @@ -56,7 +56,7 @@ Please follow these steps to have your contribution considered by the maintainer - Follow all instructions in the template. Don't forget to add tests and update documentation. - After you submit your pull request, verify that all status checks are passing. In release builds, all compiler warnings are treated as errors, so you should address them before push. -We use [CSharpGuidelines](https://csharpcodingguidelines.com/) as our coding standard (with a few minor exceptions). Coding style is validated during PR build, where we inject an extra settings layer that promotes various suggestions to warning level. This ensures a high-quality codebase without interfering too much when editing code. +We use [CSharpGuidelines](https://csharpcodingguidelines.com/) as our coding standard. Coding style is validated during PR build, where we inject an extra settings layer that promotes various IDE suggestions to warning level. This ensures a high-quality codebase without interfering too much while editing code. You can run the following [PowerShell scripts](https://github.com/PowerShell/PowerShell/releases) locally: - `pwsh ./inspectcode.ps1`: Scans the code for style violations and opens the result in your web browser. - `pwsh ./cleanupcode.ps1 [branch-name-or-commit-hash]`: Reformats the codebase to match with our configured style, optionally only changed files since the specified branch (usually master). @@ -86,13 +86,39 @@ public sealed class AppDbContext : DbContext } ``` +### Pull request workflow + +Please follow the steps and guidelines below for a smooth experience. + +Authors: +- When opening a new pull request, create it in **Draft** mode. +- After you've completed the work *and* all checks are green, click the **Ready for review** button. + - If you have permissions to do so, ask a team member for review. +- Once the review has started, don't force-push anymore. +- When you've addressed feedback from a conversation, mark it with a thumbs-up or add a some text. +- Don't close a conversation you didn't start. The creator closes it after verifying the concern has been addressed. +- Apply suggestions in a batch, instead of individual commits (to minimize email notifications). +- Re-request review when you're ready for another round. +- If you want to clean up your commits before merge, let the reviewer know in time. This is optional. + +Reviewers: +- If you're unable to review within a few days, let the author know what to expect. +- Use **Start a review** instead of **Add single comment** (to minimize email notifications). +- Consider to use suggestions (the ± button). +- Don't close a conversation you didn't start. Close the ones you opened after verifying the concern has been addressed. +- Once approved, use a merge commit only if all commits are clean. Otherwise, squash them into a single commit. + A commit is considered clean when: + - It is properly documented and covers all aspects of an isolated change (code, style, tests, docs). + - Checking out the commit results in a green build. + - Having this commit show up in the history is helpful (and can potentially be reverted). + ## Creating a release (for maintainers) - Verify documentation is up-to-date -- Bump the package version in Directory.Build.props +- Bump the package version in `Directory.Build.props` - Create a GitHub release -- Update https://github.com/json-api-dotnet/JsonApiDotNetCore.MongoDb to consume the new version and release -- Create a new branch in https://github.com/json-api-dotnet/MigrationGuide and update README.md in master +- Update [JsonApiDotNetCore.MongoDb](https://github.com/json-api-dotnet/JsonApiDotNetCore.MongoDb) to consume the new version and release +- Create a new branch in [MigrationGuide](https://github.com/json-api-dotnet/MigrationGuide) and update README.md in master, if major version change ## Backporting and hotfixes (for maintainers) @@ -101,7 +127,7 @@ public sealed class AppDbContext : DbContext git checkout tags/v2.5.1 -b release/2.5.2 ``` - Cherrypick the merge commit: `git cherry-pick {git commit SHA}` -- Bump the package version in Directory.Build.props +- Bump the package version in `Directory.Build.props` - Make any other compatibility, documentation, or tooling related changes - Push the branch to origin and verify the build - Once the build is verified, create a GitHub release, tagging the release branch From 8a7fcf1fe1e2c12ba56c59614f2cf019c451b4ab Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Sun, 3 Mar 2024 13:43:12 +0100 Subject: [PATCH 07/12] Add missing documentation for type parameters --- .../Queries/Expressions/QueryExpressionVisitor.cs | 6 ++++++ src/JsonApiDotNetCore/Repositories/DbContextResolver.cs | 3 +++ .../Repositories/EntityFrameworkCoreRepository.cs | 6 ++++++ src/JsonApiDotNetCore/Resources/IResourceChangeTracker.cs | 3 +++ .../Resources/QueryStringParameterHandlers.cs | 3 +++ .../Serialization/Objects/SingleOrManyData.cs | 3 +++ 6 files changed, 24 insertions(+) diff --git a/src/JsonApiDotNetCore/Queries/Expressions/QueryExpressionVisitor.cs b/src/JsonApiDotNetCore/Queries/Expressions/QueryExpressionVisitor.cs index 7dcf44b1f4..12242c29ff 100644 --- a/src/JsonApiDotNetCore/Queries/Expressions/QueryExpressionVisitor.cs +++ b/src/JsonApiDotNetCore/Queries/Expressions/QueryExpressionVisitor.cs @@ -5,6 +5,12 @@ namespace JsonApiDotNetCore.Queries.Expressions; /// /// Implements the visitor design pattern that enables traversing a tree. /// +/// +/// The type to use for passing custom state between visit methods. +/// +/// +/// The type that is returned from visit methods. +/// [PublicAPI] public abstract class QueryExpressionVisitor { diff --git a/src/JsonApiDotNetCore/Repositories/DbContextResolver.cs b/src/JsonApiDotNetCore/Repositories/DbContextResolver.cs index 794eecc6f2..bc275a96c1 100644 --- a/src/JsonApiDotNetCore/Repositories/DbContextResolver.cs +++ b/src/JsonApiDotNetCore/Repositories/DbContextResolver.cs @@ -4,6 +4,9 @@ namespace JsonApiDotNetCore.Repositories; /// +/// +/// The type of the to resolve. +/// [PublicAPI] public sealed class DbContextResolver : IDbContextResolver where TDbContext : DbContext diff --git a/src/JsonApiDotNetCore/Repositories/EntityFrameworkCoreRepository.cs b/src/JsonApiDotNetCore/Repositories/EntityFrameworkCoreRepository.cs index 4c3314ddab..a5f083932b 100644 --- a/src/JsonApiDotNetCore/Repositories/EntityFrameworkCoreRepository.cs +++ b/src/JsonApiDotNetCore/Repositories/EntityFrameworkCoreRepository.cs @@ -21,6 +21,12 @@ namespace JsonApiDotNetCore.Repositories; /// /// Implements the foundational Repository layer in the JsonApiDotNetCore architecture that uses Entity Framework Core. /// +/// +/// The resource type. +/// +/// +/// The resource identifier type. +/// [PublicAPI] public class EntityFrameworkCoreRepository : IResourceRepository, IRepositorySupportsTransaction where TResource : class, IIdentifiable diff --git a/src/JsonApiDotNetCore/Resources/IResourceChangeTracker.cs b/src/JsonApiDotNetCore/Resources/IResourceChangeTracker.cs index 1f69735f92..13404f2759 100644 --- a/src/JsonApiDotNetCore/Resources/IResourceChangeTracker.cs +++ b/src/JsonApiDotNetCore/Resources/IResourceChangeTracker.cs @@ -3,6 +3,9 @@ namespace JsonApiDotNetCore.Resources; /// /// Used to determine whether additional changes to a resource (side effects), not specified in a POST or PATCH request, have been applied. /// +/// +/// The resource type. +/// public interface IResourceChangeTracker where TResource : class, IIdentifiable { diff --git a/src/JsonApiDotNetCore/Resources/QueryStringParameterHandlers.cs b/src/JsonApiDotNetCore/Resources/QueryStringParameterHandlers.cs index b48c46e26e..7fe8970b53 100644 --- a/src/JsonApiDotNetCore/Resources/QueryStringParameterHandlers.cs +++ b/src/JsonApiDotNetCore/Resources/QueryStringParameterHandlers.cs @@ -6,4 +6,7 @@ namespace JsonApiDotNetCore.Resources; /// This is an alias type intended to simplify the implementation's method signature. See /// for usage details. /// +/// +/// The resource type. +/// public sealed class QueryStringParameterHandlers : Dictionary, StringValues, IQueryable>>; diff --git a/src/JsonApiDotNetCore/Serialization/Objects/SingleOrManyData.cs b/src/JsonApiDotNetCore/Serialization/Objects/SingleOrManyData.cs index 1126f84f26..99884d61e6 100644 --- a/src/JsonApiDotNetCore/Serialization/Objects/SingleOrManyData.cs +++ b/src/JsonApiDotNetCore/Serialization/Objects/SingleOrManyData.cs @@ -9,6 +9,9 @@ namespace JsonApiDotNetCore.Serialization.Objects; /// Represents the value of the "data" element, which is either null, a single object or an array of objects. Add /// to to properly roundtrip. /// +/// +/// The type of elements being wrapped, typically or . +/// [PublicAPI] public readonly struct SingleOrManyData // The "new()" constraint exists for parity with SingleOrManyDataConverterFactory, which creates empty instances From a3c92c71108d8a56f023bc415d08f65a44e718c4 Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Mon, 4 Mar 2024 00:25:53 +0100 Subject: [PATCH 08/12] Fixes in landing page --- docs/home/index.html | 56 ++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/docs/home/index.html b/docs/home/index.html index 2c3e57849b..582eb7f619 100644 --- a/docs/home/index.html +++ b/docs/home/index.html @@ -9,7 +9,7 @@ - + @@ -22,7 +22,10 @@

JsonApiDotNetCore

-

A framework for building JSON:API compliant REST APIs using .NET Core and Entity Framework Core. Includes support for Atomic Operations.

+

+ A framework for building JSON:API compliant REST APIs using .NET Core and Entity Framework Core. + Includes support for Atomic Operations. +

Read more Getting started Contribute on GitHub @@ -43,12 +46,13 @@

A framework for building JSON

Objectives

- The goal of this library is to simplify the development of APIs that leverage the full range of features provided by the JSON:API specification. + The goal of this library is to simplify the development of APIs that leverage the full range of features + provided by the JSON:API specification. You just need to focus on defining the resources and implementing your custom business logic.

- +

Eliminate boilerplate

We strive to eliminate as much boilerplate as possible by offering out-of-the-box features such as sorting, filtering and pagination.

@@ -69,28 +73,28 @@

Features

The following features are supported, from HTTP all the way down to the database

-
+

Filtering

Perform compound filtering using the filter query string parameter

-
+
-
+

Sorting

Order resources on one or multiple attributes using the sort query string parameter

-