Skip to content

Commit 28e76fa

Browse files
committed
docs: update routing related docs
1 parent 05f0ad9 commit 28e76fa

File tree

3 files changed

+102
-54
lines changed

3 files changed

+102
-54
lines changed

docs/usage/resource-graph.md

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,30 @@ It is built at app startup and available as a singleton through Dependency Injec
1010

1111
There are three ways the resource graph can be created:
1212

13-
1. Auto-discovery
13+
1. Manually specifying each resource
1414
2. Specifying an entire DbContext
15-
3. Manually specifying each resource
15+
3. Auto-discovery
1616

17-
### Auto-Discovery
17+
It is also possible to combine the three of them at once. Be aware that some configuration might overlap,
18+
for example you could manually add a resource to the graph which is also auto-discovered. In such a scenario, the configuration
19+
is prioritized by the order of the list above.
1820

19-
Auto-discovery refers to the process of reflecting on an assembly and
20-
detecting all of the json:api resources and services.
21+
### Manual Specification
2122

22-
The following command will build the resource graph using all `IIdentifiable`
23-
implementations. It also injects resource definitions and service layer overrides which we will
24-
cover in a later section. You can enable auto-discovery for the
25-
current assembly by adding the following to your `Startup` class.
23+
You can manually construct the graph.
2624

2725
```c#
2826
// Startup.cs
2927
public void ConfigureServices(IServiceCollection services)
3028
{
31-
services.AddJsonApi(
32-
options => { /* ... */ },
33-
discovery => discovery.AddCurrentAssembly());
29+
services.AddJsonApi(resources: builder =>
30+
{
31+
builder.AddResource<Person>();
32+
});
3433
}
3534
```
3635

37-
### Entity Framework Core DbContext
36+
### Specifying an Entity Framework Core DbContext
3837

3938
If you are using Entity Framework Core as your ORM, you can add an entire `DbContext` with one line.
4039

@@ -58,33 +57,61 @@ public void ConfigureServices(IServiceCollection services)
5857
}
5958
```
6059

61-
### Manual Specification
60+
### Auto-discovery
6261

63-
You can also manually construct the graph.
62+
Auto-discovery refers to the process of reflecting on an assembly and
63+
detecting all of the json:api resources and services.
64+
65+
The following command will build the resource graph using all `IIdentifiable`
66+
implementations. It also injects resource definitions and service layer overrides which we will
67+
cover in a later section. You can enable auto-discovery for the
68+
current assembly by adding the following to your `Startup` class.
6469

6570
```c#
6671
// Startup.cs
6772
public void ConfigureServices(IServiceCollection services)
6873
{
69-
services.AddJsonApi(resources: builder =>
70-
{
71-
builder.AddResource<Person>();
72-
});
74+
services.AddJsonApi(
75+
options => { /* ... */ },
76+
discovery => discovery.AddCurrentAssembly());
7377
}
7478
```
7579

76-
### Public Resource Type Name
80+
### Public Resource Name
7781

78-
The public resource type name is determined by the following criteria (in order of priority):
82+
The public resource name is exposed in the json:api payload as the `type` member.
83+
How this is exposed can be configured in with the following approaches (in order of priority):
7984

80-
1. The model is decorated with a `ResourceAttribute`
85+
1. The `publicResourceName` option when manually adding a resource to the graph
8186
```c#
82-
[Resource("my-models")]
87+
services.AddJsonApi(resources: builder =>
88+
{
89+
builder.AddResource<Person>(publicResourceName: "people");
90+
});
91+
```
92+
93+
2. The model is decorated with a `ResourceAttribute`
94+
```c#
95+
[Resource("myResources")]
8396
public class MyModel : Identifiable { /* ... */ }
8497
```
8598

86-
2. The configured naming convention (by default this is camel-case).
99+
3. The configured naming convention (by default this is camel-case).
87100
```c#
88101
// this will be registered as "myModels"
89102
public class MyModel : Identifiable { /* ... */ }
90103
```
104+
This convention can be changed by setting the `SerializerSettings` property on `IJsonApiOptions`.
105+
```c#
106+
public void ConfigureServices(IServiceCollection services)
107+
{
108+
services.AddJsonApi(
109+
options =>
110+
{
111+
options.SerializerSettings.ContractResolver = new DefaultContractResolver
112+
{
113+
NamingStrategy = new KebabCaseNamingStrategy()
114+
}
115+
});
116+
}
117+
```

docs/usage/routing.md

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,55 @@
11
# Routing
2-
3-
By default the library will configure routes for each controller.
4-
Based on the [recommendations](https://jsonapi.org/recommendations/) outlined in the json:api spec, routes are camel-cased.
2+
The library will configure routes for each controller. By default, based on the [recommendations](https://jsonapi.org/recommendations/) outlined in the json:api spec, routes are camel-cased.
53

64
```http
75
GET /api/compoundModels HTTP/1.1
86
```
97

10-
## Namespacing and Versioning URLs
8+
There are two ways the library will try to create a route for a controller:
9+
1. **By inspecting the controller for an associated resource**. The library will try to first use the public resource name of the resource associated to a controller. This means that the value of the `type` member of the json:api document for a resource will be equal to the route.
10+
Note that this implies that it is possible to configure a route configuring the exposed resource name. See [this section](~/usage/resource-graph.md#public-resource-name) on how this can be achieved.
11+
For example:
12+
```c#
13+
// controller
14+
public class MyResourceController : JsonApiController<MyApiResource> { /* .... */ }
15+
16+
// request
17+
GET /myApiResources HTTP/1.1
18+
19+
// response
20+
HTTP/1.1 200 OK
21+
Content-Type: application/vnd.api+json
22+
23+
{
24+
"data": [{
25+
"type": "myApiResources",
26+
"id": "1",
27+
"attributes": { ... }
28+
}]
29+
}
30+
```
31+
2. **By using the name of the controller**. If no associated resource was detected for a controller, the library will construct a route from the name of the controller by using the configured naming strategy (*camelCase* by default, see [this section](~/usage/resource-graph.md#public-resource-name) on how to configure this).
32+
In the following example the controller does not inherit from `BaseJsonApiController<T>` and the library is unable associate a resource to it.
33+
```c#
34+
// controller
35+
public class MyResourceController : ControllerBase { /* .... */ }
36+
37+
// request
38+
GET /myResources HTTP/1.1
39+
```
1140

41+
## Customized the Routing Convention
42+
It is possible to fully customize routing behaviour by registering a `IJsonApiRoutingConvention` implementation **before** calling `AddJsonApi( ... )`.
43+
```c#
44+
// Startup.cs
45+
public void ConfigureServices(IServiceCollection services)
46+
{
47+
services.AddSingleton<IJsonApiConvention, CustomRoutingConvention>();
48+
services.AddJsonApi( /* ... */ );
49+
}
50+
```
51+
52+
## Namespacing and Versioning URLs
1253
You can add a namespace to all URLs by specifying it in ConfigureServices
1354

1455
```c#
@@ -20,40 +61,20 @@ public void ConfigureServices(IServiceCollection services)
2061
```
2162
Which results in URLs like: https://yourdomain.com/api/v1/people
2263

23-
## Disable Convention
24-
25-
You can disable the default casing convention and specify your own template by using the `DisableRoutingConvention` attribute.
64+
## Disabling the Default Routing Convention
65+
It is possible to completely bypass the default routing convention for a particular controller and specify a custom routing template by using the `DisableRoutingConvention` attribute.
66+
In the following example, the `CamelCasedModel` resource can be accessed on `/myCustomResources` (assuming that the default naming strategy is used).
2667

2768
```c#
2869
[Route("[controller]")]
2970
[DisableRoutingConvention]
30-
public class CamelCasedModelsController : JsonApiController<CamelCasedModel>
71+
public class MyCustomResourceController : JsonApiController<CamelCasedModel>
3172
{
32-
public CamelCasedModelsController(
73+
public MyCustomResourceController(
3374
IJsonApiOptions jsonApiOptions,
3475
ILoggerFactory loggerFactory,
3576
IResourceService<CamelCasedModel> resourceService)
3677
: base(jsonApiOptions, loggerFactory, resourceService)
3778
{ }
3879
}
3980
```
40-
41-
It is important to note that your routes must still end with the model name in the same format as the resource name. This is so that we can build accurate resource links in the json:api document. For example, if you define a resource as MyModels, the controller route must match.
42-
43-
```c#
44-
public void ConfigureServices(IServiceCollection services)
45-
{
46-
services.AddJsonApi(resources: builder =>
47-
builder.AddResource<TodoItem>("my-models")); // kebab-cased
48-
}
49-
50-
// controller definition
51-
[Route("api/my-models"), DisableRoutingConvention]
52-
public class MyModelsController : JsonApiController<TodoItem>
53-
{
54-
//...
55-
}
56-
```
57-
58-
See [this](~/usage/resource-graph.md#public-resource-type-name) for
59-
more information on how the resource name is determined.

src/JsonApiDotNetCore/Builders/JsonApiApplicationBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ public void ConfigureMvc()
9797
public void AddResourceGraph(Type dbContextType, Action<IResourceGraphBuilder> configureResources)
9898
{
9999
using var intermediateProvider = _services.BuildServiceProvider();
100-
AddResourcesFromDbContext(dbContextType, intermediateProvider, _resourceGraphBuilder);
101100
AutoDiscoverResources(_serviceDiscoveryFacade);
101+
AddResourcesFromDbContext(dbContextType, intermediateProvider, _resourceGraphBuilder);
102102
UserConfigureResources(configureResources, _resourceGraphBuilder);
103103
_services.AddSingleton(_resourceGraphBuilder.Build());
104104
}

0 commit comments

Comments
 (0)