Skip to content

Commit 246f8bc

Browse files
committed
Document advanced use cases
1 parent 6cf286c commit 246f8bc

28 files changed

+340
-17
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ To build the code from this repository locally, run:
256256
dotnet build
257257
```
258258

259-
Running tests locally requires access to a PostgreSQL database. If you have docker installed, this can started via:
259+
Running tests locally requires access to a PostgreSQL database. If you have docker installed, this can be started via:
260260

261261
```bash
262262
pwsh run-docker-postgres.ps1

docs/getting-started/faq.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ The [OpenAPI support in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/c
1111
and doesn't provide the level of extensibility needed for JsonApiDotNetCore.
1212

1313
#### What's available to implement a JSON:API client?
14-
It depends on the programming language used. There's an overwhelming list of client libraries at https://jsonapi.org/implementations/#client-libraries.
14+
To generate a typed client (specific to the resource types in your project), consider using our [OpenAPI](https://www.jsonapi.net/usage/openapi.html) NuGet package.
15+
16+
If you need a generic client, it depends on the programming language used. There's an overwhelming list of client libraries at https://jsonapi.org/implementations/#client-libraries.
1517

1618
The JSON object model inside JsonApiDotNetCore is tweaked for server-side handling (be tolerant at inputs and strict at outputs).
17-
While you technically *could* use our `JsonSerializer` converters from a .NET client application with some hacks, we don't recommend it.
19+
While you technically *could* use our `JsonSerializer` converters from a .NET client application with some hacks, we don't recommend doing so.
1820
You'll need to build the resource graph on the client and rely on internal implementation details that are subject to change in future versions.
1921

20-
In the long term, we'd like to solve this through OpenAPI, which enables the generation of a (statically typed) client library in various languages.
21-
2222
#### How can I debug my API project?
2323
Due to auto-generated controllers, you may find it hard to determine where to put your breakpoints.
2424
In Visual Studio, controllers are accessible below **Solution Explorer > Project > Dependencies > Analyzers > JsonApiDotNetCore.SourceGenerators**.

docs/request-examples/index.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@
22

33
Runnable example projects can be found [here](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/master/src/Examples):
44

5-
- GettingStarted: A simple project with minimal configuration to have a runnable project in minutes.
5+
- GettingStarted: A simple project with minimal configuration to develop a runnable project in minutes.
66
- JsonApiDotNetCoreExample: Showcases commonly-used features, such as resource definitions, atomic operations, and OpenAPI.
77
- OpenApiNSwagClientExample: Uses [NSwag](https://github.com/RicoSuter/NSwag) to generate a typed OpenAPI client.
88
- OpenApiKiotaClientExample: Uses [Kiota](https://learn.microsoft.com/en-us/openapi/kiota/) to generate a typed OpenAPI client.
99
- MultiDbContextExample: Shows how to use multiple `DbContext` classes, for connecting to multiple databases.
10-
- DatabasePerTenantExample: Uses a different database per tenant. See [here](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/master/test/JsonApiDotNetCoreTests/IntegrationTests/MultiTenancy) for using multiple tenants in the same database.
11-
- NoEntityFrameworkExample: Uses a read-only in-memory repository instead of a real database.
10+
- DatabasePerTenantExample: Uses a different database per tenant. See [here](~/usage/advanced/multi-tenancy.md) for using multiple tenants in the same database.
11+
- NoEntityFrameworkExample: Uses a read-only in-memory repository, instead of a real database.
1212
- DapperExample: Uses [Dapper](https://github.com/DapperLib/Dapper) to execute SQL queries.
1313
- ReportsExample: Uses a resource service that returns aggregated data.
1414

15-
Additional use cases are provided as integration tests [here](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/master/test/JsonApiDotNetCoreTests/IntegrationTests).
15+
> [!NOTE]
16+
> The example projects only cover highly-requested features. More advanced use cases can be found [here](~/usage/advanced/index.md).
1617
1718
# Example requests
1819

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Alternate Routes
2+
3+
The code [here](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/master/test/JsonApiDotNetCoreTests/IntegrationTests/CustomRoutes) shows how the default JSON:API routes can be changed.
4+
5+
The classes `TownsController` and `CiviliansController`:
6+
- Are decorated with `[DisableRoutingConvention]` to turn off the default JSON:API routing convention.
7+
- Are decorated with the ASP.NET `[Route]` attribute to specify at which route the controller is exposed.
8+
- Are augmented with non-standard JSON:API action methods, whose `[HttpGet]` attributes specify a custom route.

docs/usage/advanced/archiving.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Archiving
2+
3+
The code [here](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/master/test/JsonApiDotNetCoreTests/IntegrationTests/Archiving) demonstrates how to implement archived resources.
4+
5+
> [!TIP]
6+
> This scenario is comparable with [Soft Deletion](~/usage/advanced/soft-deletion.md).
7+
> The difference is that archived resources are accessible to JSON:API clients, whereas soft-deleted resources _never_ are.
8+
9+
- Archived resources can be fetched by ID, but don't show up in searches by default.
10+
- Resources can only be created in a non-archived state and then archived/unarchived using a PATCH resource request.
11+
- The archive date is stored in the database, but cannot be modified through JSON:API.
12+
- To delete a resource, it must be archived first.
13+
14+
This feature is implemented using a custom resource definition. It intercepts write operations and recursively scans incoming filters.

docs/usage/advanced/auth-scopes.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Authorization Scopes
2+
3+
The code [here](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/master/test/JsonApiDotNetCoreTests/IntegrationTests/Authorization/Scopes) shows how scope-based authorization can be used.
4+
5+
- For simplicity, this code assumes the granted scopes are passed in a plain-text HTTP header. A more realistic use case would be to obtain the scopes from an OAuth token.
6+
- The HTTP header lists which resource types can be read from and/or written to.
7+
- An [ASP.NET Action Filter](https://learn.microsoft.com/aspnet/core/mvc/controllers/filters) validates incoming JSON:API resource/relationship requests.
8+
- The incoming request path is validated against the permitted read/write permissions per resource type.
9+
- The resource types used in query string parameters are validated against the permitted set of resource types.
10+
- A customized operations controller verifies that all incoming operations are allowed.

docs/usage/advanced/blobs.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# BLOBs
2+
3+
The code [here](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/master/test/JsonApiDotNetCoreTests/IntegrationTests/Blobs) shows how Binary Large Objects (BLOBs) can be used.
4+
5+
- The `ImageContainer` resource type contains nullable and non-nullable `byte[]` properties.
6+
- BLOBs are queried and persisted using Entity Framework Core.
7+
- The BLOB data is returned as a base-64 encoded string in the JSON response.
8+
9+
Blobs are handled automatically; there's no need for custom code.

docs/usage/advanced/composite-keys.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Composite Keys
2+
3+
The code [here](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/master/test/JsonApiDotNetCoreTests/IntegrationTests/CompositeKeys) shows how database tables with composite keys can be used.
4+
5+
- The `DbContext` configures `Car` to have a composite primary key consisting of the `RegionId` and `LicensePlate` columns.
6+
- The `Car.Id` property is overridden to provide a unique ID for JSON:API. It is marked with `[NotMapped]`, meaning no `Id` column exists in the database table.
7+
- The `Engine` and `Dealership` resource types define relationships that generate composite foreign keys in the database.
8+
- A custom resource repository is used to rewrite IDs from filter/sort query string parameters into `RegionId` and `LicensePlate` lookups.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Content Negotiation
2+
3+
The code [here](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/master/test/JsonApiDotNetCoreTests/IntegrationTests/ContentNegotiation) demonstrates how content negotiation in JSON:API works.
4+
5+
Additionally, the code [here](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/master/test/JsonApiDotNetCoreTests/IntegrationTests/ContentNegotiation/CustomExtensions) provides
6+
a custom "server-time" JSON:API extension that returns the local or UTC server time in top-level `meta`.
7+
- This extension can be used in the `Accept` and `Content-Type` HTTP headers.
8+
- In a request body, the optional `useLocalTime` property in top-level `meta` indicates whether to return the local or UTC time.
9+
10+
This feature is implemented using the following extensibility points:
11+
12+
- At startup, the "server-time" extension is added in `JsonApiOptions`, which permits clients to use it.
13+
- A custom `JsonApiContentNegotiator` chooses which extensions are active for an incoming request, taking the "server-time" extension into account.
14+
- A custom `IDocumentAdapter` captures the incoming request body, providing access to the `useLocalTime` property in `meta`.
15+
- A custom `IResponseMeta` adds the server time to the response, depending on the activated extensions in `IJsonApiRequest` and the captured request body.

docs/usage/advanced/eager-loading.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Eager Loading Related Resources
2+
3+
The code [here](https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/master/test/JsonApiDotNetCoreTests/IntegrationTests/EagerLoading) uses the `[EagerLoad]` attribute to facilitate calculated properties that depend on related resources.
4+
The related resources are fetched from the database, but not returned to the client unless explicitly requested using the `include` query string parameter.
5+
6+
- The `Street` resource type uses `EagerLoad` on its `Buildings` to-many relationship because its `DoorTotalCount` calculated property depends on it.
7+
- The `Building` resource type uses `EagerLoad` on its `Windows` to-many relationship because its `WindowCount` calculated property depends on it.
8+
- The `Building` resource type uses `EagerLoad` on its `PrimaryDoor` to-one required relationship because its `PrimaryDoorColor` calculated property depends on it.
9+
- Because this is a required relationship, special handling occurs in `Building`, `BuildingRepository`, and `BuildingDefinition`.
10+
- The `Building` resource type uses `EagerLoad` on its `SecondaryDoor` to-one optional relationship because its `SecondaryDoorColor` calculated property depends on it.
11+
12+
As can be seen from the usages above, a chain of `EagerLoad` attributes can result in fetching a chain of related resources from the database.

0 commit comments

Comments
 (0)