Skip to content

Commit 61649e6

Browse files
author
Bart Koelman
committed
Updated documentation
1 parent ac84993 commit 61649e6

File tree

6 files changed

+142
-74
lines changed

6 files changed

+142
-74
lines changed

README.md

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,26 +45,14 @@ See [our documentation](https://www.jsonapi.net/) for detailed usage.
4545
```c#
4646
#nullable enable
4747

48+
[Resource]
4849
public class Article : Identifiable<int>
4950
{
5051
[Attr]
5152
public string Name { get; set; } = null!;
5253
}
5354
```
5455

55-
### Controllers
56-
57-
```c#
58-
public class ArticlesController : JsonApiController<Article, int>
59-
{
60-
public ArticlesController(IJsonApiOptions options, IResourceGraph resourceGraph,
61-
ILoggerFactory loggerFactory, IResourceService<Article, int> resourceService)
62-
: base(options, resourceGraph, loggerFactory, resourceService)
63-
{
64-
}
65-
}
66-
```
67-
6856
### Middleware
6957

7058
```c#

docs/getting-started/step-by-step.md

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ The shortest path to a running API looks like:
77
- Install
88
- Define models
99
- Define the DbContext
10-
- Define controllers
1110
- Add Middleware and Services
1211
- Seed the database
1312
- Start the app
@@ -40,6 +39,7 @@ The easiest way to do this is to inherit from `Identifiable<TId>`.
4039
```c#
4140
#nullable enable
4241

42+
[Resource]
4343
public class Person : Identifiable<int>
4444
{
4545
[Attr]
@@ -63,22 +63,6 @@ public class AppDbContext : DbContext
6363
}
6464
```
6565

66-
### Define Controllers
67-
68-
You need to create controllers that inherit from `JsonApiController<TResource, TId>`
69-
where `TResource` is the model that inherits from `Identifiable<TId>`.
70-
71-
```c#
72-
public class PeopleController : JsonApiController<Person, int>
73-
{
74-
public PeopleController(IJsonApiOptions options, IResourceGraph resourceGraph,
75-
ILoggerFactory loggerFactory, IResourceService<Person, int> resourceService)
76-
: base(options, resourceGraph, loggerFactory, resourceService)
77-
{
78-
}
79-
}
80-
```
81-
8266
### Middleware and Services
8367

8468
Finally, add the services by adding the following to your Startup.ConfigureServices:

docs/usage/extensibility/controllers.md

Lines changed: 95 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,99 @@
11
# Controllers
22

3-
You need to create controllers that inherit from `JsonApiController<TResource, TId>`
3+
To expose API endpoints, ASP.NET controllers need to be defined.
4+
5+
_since v5_
6+
7+
Controllers are auto-generated (using [source generators](https://docs.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview)) when you add `[Resource]` on your model class:
8+
9+
```c#
10+
[Resource] // Generates ArticlesController.g.cs
11+
public class Article : Identifiable<Guid>
12+
{
13+
// ...
14+
}
15+
```
16+
17+
## Resource Access Control
18+
19+
It is often desirable to limit which endpoints are exposed on your controller.
20+
A subset can be specified too:
21+
22+
```c#
23+
[Resource(GenerateControllerEndpoints =
24+
JsonApiEndpoints.GetCollection | JsonApiEndpoints.GetSingle)]
25+
public class Article : Identifiable<Guid>
26+
{
27+
// ...
28+
}
29+
```
30+
31+
Instead of passing a set of endpoints, you can use `JsonApiEndpoints.Query` to generate all read-only endpoints or `JsonApiEndpoints.Command` for all write-only endpoints.
32+
33+
When an endpoint is blocked, an HTTP 403 Forbidden response is returned.
34+
35+
```http
36+
DELETE http://localhost:14140/articles/1 HTTP/1.1
37+
```
38+
39+
```json
40+
{
41+
"links": {
42+
"self": "/articles"
43+
},
44+
"errors": [
45+
{
46+
"id": "dde7f219-2274-4473-97ef-baac3e7c1487",
47+
"status": "403",
48+
"title": "The requested endpoint is not accessible.",
49+
"detail": "Endpoint '/articles/1' is not accessible for DELETE requests."
50+
}
51+
]
52+
}
53+
```
54+
55+
## Augmenting controllers
56+
57+
Auto-generated controllers can easily be augmented because they are partial classes. For example:
58+
59+
```c#
60+
[DisableRoutingConvention]
61+
[Route("some/custom/route")]
62+
[DisableQueryString(JsonApiQueryStringParameters.Include)]
63+
partial class ArticlesController
64+
{
65+
[HttpPost]
66+
public IActionResult Upload()
67+
{
68+
// ...
69+
}
70+
}
71+
```
72+
73+
If you need to inject extra dependencies, tell the IoC container with `[ActivatorUtilitiesConstructor]` to prefer your constructor:
74+
75+
```c#
76+
partial class ArticlesController
77+
{
78+
private IAuthenticationService _authService;
79+
80+
[ActivatorUtilitiesConstructor]
81+
public ArticlesController(IAuthenticationService authService, IJsonApiOptions options,
82+
IResourceGraph resourceGraph, ILoggerFactory loggerFactory,
83+
IResourceService<Article, Guid> resourceService)
84+
: base(options, resourceGraph, loggerFactory, resourceService)
85+
{
86+
_authService = authService;
87+
}
88+
}
89+
```
90+
91+
In case you don't want to use auto-generated controllers and define them yourself (see below), remove
92+
`[Resource]` from your models or use `[Resource(GenerateControllerEndpoints = JsonApiEndpoints.None)]`.
93+
94+
## Earlier versions
95+
96+
In earlier versions of JsonApiDotNetCore, you needed to create controllers that inherit from `JsonApiController<TResource, TId>`. For example:
497

598
```c#
699
public class ArticlesController : JsonApiController<Article, Guid>
@@ -15,7 +108,7 @@ public class ArticlesController : JsonApiController<Article, Guid>
15108

16109
If you want to setup routes yourself, you can instead inherit from `BaseJsonApiController<TResource, TId>` and override its methods with your own `[HttpGet]`, `[HttpHead]`, `[HttpPost]`, `[HttpPatch]` and `[HttpDelete]` attributes added on them. Don't forget to add `[FromBody]` on parameters where needed.
17110

18-
## Resource Access Control
111+
### Resource Access Control
19112

20113
It is often desirable to limit which routes are exposed on your controller.
21114

@@ -37,25 +130,3 @@ public class ReportsController : JsonApiController<Report, int>
37130
```
38131

39132
For more information about resource service injection, see [Replacing injected services](~/usage/extensibility/layer-overview.md#replacing-injected-services) and [Resource Services](~/usage/extensibility/services.md).
40-
41-
When a route is blocked, an HTTP 403 Forbidden response is returned.
42-
43-
```http
44-
DELETE http://localhost:14140/people/1 HTTP/1.1
45-
```
46-
47-
```json
48-
{
49-
"links": {
50-
"self": "/api/v1/people"
51-
},
52-
"errors": [
53-
{
54-
"id": "dde7f219-2274-4473-97ef-baac3e7c1487",
55-
"status": "403",
56-
"title": "The requested endpoint is not accessible.",
57-
"detail": "Endpoint '/people/1' is not accessible for DELETE requests."
58-
}
59-
]
60-
}
61-
```

docs/usage/extensibility/services.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Resource Services
22

33
The `IResourceService` acts as a service layer between the controller and the data access layer.
4-
This allows you to customize it however you want. This is also a good place to implement custom business logic.
4+
This allows you to customize it however you want. While this is still a potential place to implement custom business logic,
5+
since v4, [Resource Definitions](~/usage/extensibility/resource-definitions.md) are more suitable for that.
56

67
## Supplementing Default Behavior
78

@@ -77,7 +78,7 @@ public class ProductService : IResourceService<Product, int>
7778

7879
## Limited Requirements
7980

80-
In some cases it may be necessary to only expose a few methods on a resource. For this reason, we have created a hierarchy of service interfaces that can be used to get the exact implementation you require.
81+
In some cases it may be necessary to only expose a few actions on a resource. For this reason, we have created a hierarchy of service interfaces that can be used to get the exact implementation you require.
8182

8283
This interface hierarchy is defined by this tree structure.
8384

@@ -152,7 +153,18 @@ public class Startup
152153
}
153154
```
154155

155-
Then in the controller, you should inherit from the JSON:API controller and pass the services into the named, optional base parameters:
156+
Then on your model, pass in the set of endpoints to expose (the ones that you've registered services for):
157+
158+
```c#
159+
[Resource(GenerateControllerEndpoints =
160+
JsonApiEndpoints.Create | JsonApiEndpoints.Delete)]
161+
public class Article : Identifiable<int>
162+
{
163+
// ...
164+
}
165+
```
166+
167+
Alternatively, when using a hand-written controller, you should inherit from the JSON:API controller and pass the services into the named, optional base parameters:
156168

157169
```c#
158170
public class ArticlesController : JsonApiController<Article, int>

docs/usage/resource-graph.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,28 +72,28 @@ public void ConfigureServices(IServiceCollection services)
7272

7373
## Resource Name
7474

75-
The public resource name is exposed through the `type` member in the JSON:API payload. This can be configured by the following approaches (in order of priority):
75+
The public resource name is exposed through the `type` member in the JSON:API payload. This can be configured using the following approaches (in order of priority):
7676

77-
1. The `publicName` parameter when manually adding a resource to the graph
77+
1. The `publicName` parameter when manually adding a resource to the graph.
7878
```c#
7979
services.AddJsonApi(resources: builder =>
8080
{
81-
builder.Add<Person, int>(publicName: "people");
81+
builder.Add<Person, int>(publicName: "individuals");
8282
});
8383
```
8484

85-
2. The model is decorated with a `ResourceAttribute`
85+
2. The `PublicName` property when a model is decorated with a `ResourceAttribute`.
8686
```c#
87-
[Resource("myResources")]
88-
public class MyModel : Identifiable<int>
87+
[Resource(PublicName = "individuals")]
88+
public class Person : Identifiable<int>
8989
{
9090
}
9191
```
9292

93-
3. The configured naming convention (by default this is camel-case).
93+
3. The configured naming convention (by default this is camel-case), after pluralization.
9494
```c#
95-
// this will be registered as "myModels"
96-
public class MyModel : Identifiable<int>
95+
// this will be registered as "people"
96+
public class Person : Identifiable<int>
9797
{
9898
}
9999
```

docs/usage/routing.md

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ An endpoint URL provides access to a resource or a relationship. Resource endpoi
66

77
In the relationship endpoint "/articles/1/relationships/comments", "articles" is the left side of the relationship and "comments" the right side.
88

9-
## Namespacing and Versioning URLs
9+
## Namespacing and versioning of URLs
1010
You can add a namespace to all URLs by specifying it in ConfigureServices.
1111

1212
```c#
@@ -18,15 +18,18 @@ public void ConfigureServices(IServiceCollection services)
1818

1919
Which results in URLs like: https://yourdomain.com/api/v1/people
2020

21-
## Default Routing Convention
21+
## Default routing convention
2222

23-
The library will configure routes for all controllers in your project. By default, routes are camel-cased. This is based on the [recommendations](https://jsonapi.org/recommendations/) outlined in the JSON:API spec.
23+
The library will configure routes for all auto-generated and hand-written controllers in your project. By default, routes are camel-cased. This is based on the [recommendations](https://jsonapi.org/recommendations/) outlined in the JSON:API spec.
2424

2525
```c#
26-
public class OrderLine : Identifiable<int>
26+
// Auto-generated
27+
[Resource]
28+
public class OrderSummary : Identifiable<int>
2729
{
2830
}
2931

32+
// Hand-written
3033
public class OrderLineController : JsonApiController<OrderLine, int>
3134
{
3235
public OrderLineController(IJsonApiOptions options, IResourceGraph resourceGraph,
@@ -38,6 +41,7 @@ public class OrderLineController : JsonApiController<OrderLine, int>
3841
```
3942

4043
```http
44+
GET /orderSummaries HTTP/1.1
4145
GET /orderLines HTTP/1.1
4246
```
4347

@@ -57,12 +61,21 @@ public class OrderLineController : ControllerBase
5761
GET /orderLines HTTP/1.1
5862
```
5963

60-
## Disabling the Default Routing Convention
64+
### Customized routes
6165

62-
It is possible to bypass the default routing convention for a controller.
66+
It is possible to override the default routing convention for an auto-generated or hand-written controller.
6367

6468
```c#
65-
[Route("v1/custom/route/lines-in-order"), DisableRoutingConvention]
69+
// Auto-generated
70+
[DisableRoutingConvention]
71+
[Route("v1/custom/route/summaries-for-orders")]
72+
partial class OrderSummariesController
73+
{
74+
}
75+
76+
// Hand-written
77+
[DisableRoutingConvention]
78+
[Route("v1/custom/route/lines-in-order")]
6679
public class OrderLineController : JsonApiController<OrderLine, int>
6780
{
6881
public OrderLineController(IJsonApiOptions options, IResourceGraph resourceGraph,
@@ -73,7 +86,7 @@ public class OrderLineController : JsonApiController<OrderLine, int>
7386
}
7487
```
7588

76-
## Advanced Usage: Custom Routing Convention
89+
## Advanced usage: Custom routing convention
7790

7891
It is possible to replace the built-in routing convention with a [custom routing convention](https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/application-model?view=aspnetcore-3.1#sample-custom-routing-convention) by registering an implementation of `IJsonApiRoutingConvention`.
7992

0 commit comments

Comments
 (0)