Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ dotnet add package Intility.JsonApiToolkit
options.MaxFilterDepth = 5; // Default: 3
options.MaxPageSize = 200; // Default: 100
options.DefaultPageSize = 25; // Default: 10
options.StrictPagination = true; // Default: false
options.EnableDatabaseProjection = true; // Default: false
});
```
Expand Down
5 changes: 3 additions & 2 deletions docs/docs/querying.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ JsonApiToolkit provides robust support for JSON:API querying, including filterin
The `sort` parameter allows multiple sort criteria. Prefixing a field with a minus (`-`) indicates descending order.
- Example: `GET /api/books?sort=title,-publishedDate`

- **Pagination (`page[number]` and `page[size]`):**
- **Pagination (`page[number]` and `page[size]`):**
Control how many results are returned and which page to view.
- Example: `GET /api/books?page[number]=2&page[size]=5`
- By default, invalid pagination values (page number less than 1, page size exceeding `MaxPageSize`) are silently clamped to valid ranges. Enable `StrictPagination` to return 400 errors instead (see [Security](security.md#strict-pagination)).

- **Inclusion (`include`):**
Specify which related resources should be included in the response.
Expand Down Expand Up @@ -121,7 +122,7 @@ JsonApiToolkit enforces the following query limits to ensure predictable perform
| Max Filter Depth | 3 | Maximum nesting of filter groups |
| Max Filter Value Length | 1000 | Maximum characters per filter value |
| Max Include Depth | 3 | Maximum include path depth (e.g., `author.posts.comments`) |
| Max Page Size | 100 | Maximum items per page (silently clamped) |
| Max Page Size | 100 | Maximum items per page (clamped or rejected based on `StrictPagination`) |

These limits are configurable via `JsonApiOptions`. See the [Security](security.md#query-complexity-limits) documentation for configuration details.

Expand Down
47 changes: 46 additions & 1 deletion docs/docs/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ builder.Services.AddJsonApiToolkit(options => {
options.MaxIncludeDepth = 3; // Max include path depth (default: 3)
options.MaxPageSize = 100; // Max page size, clamped (default: 100)
options.DefaultPageSize = 10; // Default when not specified (default: 10)
options.StrictPagination = false; // Reject invalid pagination (default: false)
});
```

Expand All @@ -108,7 +109,7 @@ builder.Services.AddJsonApiToolkit(options => {
| `MaxFilterDepth` | Returns 400 Bad Request |
| `MaxFilterValueLength` | Returns 400 Bad Request |
| `MaxIncludeDepth` | Returns 400 Bad Request |
| `MaxPageSize` | Silently clamped to max value |
| `MaxPageSize` | Clamped (default) or 400 Bad Request (`StrictPagination`) |

### Error Response

Expand Down Expand Up @@ -168,6 +169,50 @@ When filtering on a non-allowed relationship:
> [!NOTE]
> This validation only applies when `[AllowedIncludes]` is present. Without the attribute, all filter paths are allowed.

## Strict Pagination

By default, JsonApiToolkit silently clamps invalid pagination parameters to valid ranges for backwards compatibility. Enable `StrictPagination` to return 400 Bad Request errors instead.

### Configuration

```csharp
builder.Services.AddJsonApiToolkit(options => {
options.StrictPagination = true;
});
```

### Behavior

When `StrictPagination` is enabled, the following values are rejected with 400 Bad Request:

- `page[number]` less than 1 (e.g., `page[number]=0` or `page[number]=-5`)
- `page[size]` less than 1 (e.g., `page[size]=0` or `page[size]=-10`)
- `page[size]` exceeding `MaxPageSize` (e.g., `page[size]=200` when `MaxPageSize=100`)

When disabled (default), these values are silently clamped:

- `page[number]` less than 1 becomes 1
- `page[size]` exceeding `MaxPageSize` becomes `MaxPageSize`

### Error Response

```json
{
"errors": [{
"status": "400",
"code": "INVALID_PAGE_SIZE",
"title": "Invalid page size",
"detail": "Page size '200' exceeds maximum allowed size of 100. Reduce page size or configure a higher limit via JsonApiOptions.MaxPageSize.",
"source": { "parameter": "page[size]" },
"meta": {
"value": 200,
"max": 100,
"configKey": "JsonApiOptions.MaxPageSize"
}
}]
}
```

## DoS Protection

The query complexity limits protect against several denial-of-service attack vectors:
Expand Down