docs: add OpenAPI integration guide#99
Conversation
Erlend Ellefsen (erlendellefsen)
commented
Mar 27, 2026
- Add integrations/open-api.md with Microsoft.AspNetCore.OpenApi setup
- Content type transformer to replace application/json with application/vnd.api+json
- Operation transformer for JSON:API query parameters (filter, fields, include, sort, page)
- Recommend Scalar as UI for .NET 9+
There was a problem hiding this comment.
Pull request overview
Adds a practical OpenAPI integration guide for JsonApiToolkit users (focused on Microsoft.AspNetCore.OpenApi + Scalar), and updates repository assistant guidance.
Changes:
- Expanded
docs/docs/integrations/open-api.mdwith setup steps and sample OpenAPI transformers (content type + JSON:API query params). - Simplified and refocused
CLAUDE.md(formatting, debugging, non-obvious behaviors).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| docs/docs/integrations/open-api.md | Adds an end-to-end OpenAPI/Scalar setup guide and transformer examples for JSON:API compatibility. |
| CLAUDE.md | Replaces the previous broad repository guide with a shorter set of formatting/debugging/behavior notes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ## Debugging | ||
|
|
||
| ## Refactoring Roadmap | ||
| Set `"JsonApiToolkit": "Debug"` in appsettings.json to enable detailed query processing logs. |
There was a problem hiding this comment.
The debugging guidance is a bit ambiguous as written: in practice the repo uses Serilog:MinimumLevel:Override:JsonApiToolkit or Logging:LogLevel:JsonApiToolkit (see docs/docs/debugging.md). Consider updating this to show the full configuration path so consumers don't set a top-level "JsonApiToolkit": "Debug" key that has no effect.
| Set `"JsonApiToolkit": "Debug"` in appsettings.json to enable detailed query processing logs. | |
| Set `"Serilog:MinimumLevel:Override:JsonApiToolkit": "Debug"` (for Serilog) or `"Logging:LogLevel:JsonApiToolkit": "Debug"` (for built-in logging) in appsettings.json to enable detailed query processing logs. |
| - **JSON column detection**: Collections and complex objects without an `Id` property are mapped as JSON attributes, not relationships. This handles EF Core owned entities stored as JSON columns. | ||
| - **Pagination clamping**: Invalid page numbers are silently clamped (negative/zero -> page 1, overflow -> last page). | ||
| - **Malformed query params**: Bad filter/sort/include syntax is logged and skipped, not thrown as exceptions. | ||
| - **Filtered includes**: Dot notation in filters (e.g. `filter[author.name]=John`) applies to included resources when `include=author` is also set. |
There was a problem hiding this comment.
The "Filtered includes" bullet appears to describe dot-notation filters (filter[author.name]=...) applying to included resources. In the code, dot-notation filters are treated as primary-resource filters, while filtered includes use bracket syntax (filter[rel][field][op]=...) with IsIncludeFilter=true (see JsonApiToolkit/Parsing/JsonApiFilterParser.cs). This bullet should be adjusted to match the actual syntax/behavior to avoid misleading contributors.
| - **Filtered includes**: Dot notation in filters (e.g. `filter[author.name]=John`) applies to included resources when `include=author` is also set. | |
| - **Filtered includes**: Filters on included resources use bracket syntax (e.g. `filter[author][name][eq]=John`) and apply when `include=author` is also set. Dot-notation filters (e.g. `filter[author.name]=John`) are interpreted as filters on the primary resource. |
| # CLAUDE.md | ||
|
|
||
| This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. | ||
| ## Code Formatting | ||
|
|
There was a problem hiding this comment.
This PR's title/description are focused on adding the OpenAPI integration guide, but it also substantially rewrites CLAUDE.md (removing the project overview, commands, and architecture notes). If that change is intentional, it should be called out in the PR description (or split into a separate PR) to make review scope clearer.
| if (content == null || !content.TryGetValue("application/json", out var schema)) | ||
| return; | ||
|
|
||
| content.Remove("application/json"); | ||
| content["application/vnd.api+json"] = schema; |
There was a problem hiding this comment.
In ReplaceContentType, the TryGetValue(..., out var schema) variable is a media type object, not a schema. Renaming it (e.g., mediaType) would make the example clearer and avoid confusing it with OpenApiSchema used later.
| if (content == null || !content.TryGetValue("application/json", out var schema)) | |
| return; | |
| content.Remove("application/json"); | |
| content["application/vnd.api+json"] = schema; | |
| if (content == null || !content.TryGetValue("application/json", out var mediaType)) | |
| return; | |
| content.Remove("application/json"); | |
| content["application/vnd.api+json"] = mediaType; |
| Name = "filter[field]", | ||
| In = ParameterLocation.Query, | ||
| Schema = new OpenApiSchema { Type = JsonSchemaType.String }, | ||
| Description = "Filter by attribute. Operators: `eq`, `ne`, `gt`, `lt`, `like`, `in`, `isnull`. Example: `filter[title][like]=Hobbit`" |
There was a problem hiding this comment.
The filter[field] parameter example/description is inconsistent with the toolkit's documented filter syntax and operator set. The docs list additional operators (ge, le, nin, isnotnull, etc.) in docs/docs/querying.md, and the example shown here uses filter[title][like]=... (which doesn't match the fixed name filter[field]). Consider either documenting a generic placeholder name (and calling out that it must be replaced) and/or aligning the operator list with the Querying docs (or linking to it).
| Description = "Filter by attribute. Operators: `eq`, `ne`, `gt`, `lt`, `like`, `in`, `isnull`. Example: `filter[title][like]=Hobbit`" | |
| Description = "Filter by attribute. Replace `field` with the attribute name. Operators: `eq`, `ne`, `gt`, `ge`, `lt`, `le`, `like`, `in`, `nin`, `isnull`, `isnotnull`. Example: `filter[title][like]=Hobbit`. See [Querying](../querying.md) for full syntax." |
| public Task TransformAsync( | ||
| OpenApiOperation operation, | ||
| OpenApiOperationTransformerContext context, | ||
| CancellationToken cancellationToken) | ||
| { | ||
| operation.Parameters ??= []; | ||
|
|
There was a problem hiding this comment.
JsonApiParametersTransformer currently adds query parameters to every operation type. JSON:API query params like filter, fields, include, sort, and page[...] generally apply to GET endpoints; adding them to POST/PATCH/DELETE operations makes the generated OpenAPI misleading. Consider checking the operation type from the transformer context (or similar metadata) and only appending these parameters for GET operations (and ideally only collection endpoints for paging).
| ### Code Formatting | ||
| ```bash | ||
| # Format code with CSharpier | ||
| dotnet tool restore |
There was a problem hiding this comment.
The formatting snippet omits dotnet csharpier check ., but CI runs dotnet csharpier check . (see .github/workflows/ci-cd.yml). Including the check command here would better reflect the repo's required workflow and avoid suggesting that only format is needed.
| dotnet tool restore | |
| dotnet tool restore | |
| dotnet csharpier check . |
🤖 I have created a release *beep* *boop* --- ## [1.7.3](v1.7.2...v1.7.3) (2026-04-07) ### Bug Fixes * resolve all 36 open CodeQL code scanning alerts ([#102](#102)) ([25cf2ef](25cf2ef)) ### Documentation * add OpenAPI integration guide ([#99](#99)) ([72c0ee1](72c0ee1)) ### CI * add Claude code review and auto-docs workflows ([3c9eba1](3c9eba1)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: intility-release-bot[bot] <175299729+intility-release-bot[bot]@users.noreply.github.com>