Skip to content

Commit 0430da3

Browse files
committed
doc updates
1 parent 6e2834f commit 0430da3

File tree

13 files changed

+224
-123
lines changed

13 files changed

+224
-123
lines changed

docs/README.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Running
2+
3+
```
4+
./generate.sh
5+
docfx ./docfx.json --serve
6+
```

docs/api/.manifest

+42-13
Large diffs are not rendered by default.

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ dotnet ef migrations add AddPeople
135135
dotnet ef database update
136136
```
137137

138-
### Start the Ap
138+
### Start the App
139139

140140
```
141141
dotnet run

docs/usage/resource-graph.md

+44-23
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,34 @@ It is built at app startup and available as a singleton through Dependency Injec
88

99
## Constructing The Graph
1010

11-
### Entity Framework
11+
There are three ways the resource graph can be created:
12+
13+
1. Auto-discovery
14+
2. Specifying an entire DbContext
15+
3. Manually specifying each resource
16+
17+
### Auto-Discovery
18+
19+
Auto-discovery refers to process of reflecting on an assembly and
20+
detecting all of the json:api resources and services.
21+
22+
The following command will build the context graph using all `IIdentifiable`
23+
implementations. It also injects 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.
26+
27+
```c#
28+
// Startup.cs
29+
public void ConfigureServices(IServiceCollection services)
30+
{
31+
services.AddJsonApi(
32+
options => { /* ... */ },
33+
mvcBuilder,
34+
discovery => discovery.AddCurrentAssembly());
35+
}
36+
```
37+
38+
### Entity Framework DbContext
1239

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

@@ -20,9 +47,9 @@ public void ConfigureServices(IServiceCollection services)
2047
}
2148
```
2249

23-
### Defining Non-EF Resources
50+
### Manual Specification
2451

25-
If you have resources that are not members of a DbContext, you can manually add them to the graph.
52+
You can also manually construct the graph.
2653

2754
```c#
2855
// Startup.cs
@@ -32,36 +59,30 @@ public void ConfigureServices(IServiceCollection services)
3259

3360
services.AddJsonApi(options => {
3461
options.BuildResourceGraph((builder) => {
35-
// MyModel is the internal type
36-
// "my-models" is the type alias exposed through the API
37-
builder.AddResource<MyModel>("my-models");
62+
builder.AddResource<MyModel>();
3863
});
3964
}, mvcBuilder);
4065
}
4166
```
4267

43-
### Resource Names
68+
### Public Resource Type Name
4469

45-
If a `DbContext` is specified when adding the services, the context will be used to define the resources and their names. By default, these names will be hyphenated.
70+
The public resource type name for is determined by the following criteria (in order of priority):
4671

72+
1. The model is decorated with a `ResourceAttribute`
4773
```c#
48-
public class AppDbContext : DbContext {
49-
// this will be translated into "my-models"
50-
public DbSet<MyModel> MyModels { get; set; }
51-
}
74+
[Resource("my-models")]
75+
public class MyModel : Identifiable { /* ... */ }
5276
```
5377

54-
You can also specify your own resource name.
55-
78+
2. The `DbSet` is decorated with a `ResourceAttribute`
5679
```c#
57-
public class AppDbContext : DbContext {
58-
// this will be translated into "someModels"
59-
[Resource("someModels")]
60-
public DbSet<MyModel> MyModels { get; set; }
61-
}
80+
[Resource("my-models")]
81+
public DbSet<MyModel> MyModel { get; set; }
6282
```
6383

64-
65-
66-
67-
84+
3. The configured naming convention (by default this is kebab-case).
85+
```c#
86+
// this will be registered as "my-models"
87+
public class MyModel : Identifiable { /* ... */ }
88+
```
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,24 @@
1-
# Resources
1+
# Attributes
22

3-
At a minimum, resources must implement `IIdentifiable<TId>` where `TId` is the type of the primary key. The easiest way to do this is to inherit `Identifiable<TId>`.
4-
5-
```c#
6-
public class Person : Identifiable<Guid>
7-
{ }
8-
```
9-
10-
You can use the non-generic `Identifiable` if your primary key is an integer.
11-
12-
```c#
13-
public class Person : Identifiable
14-
{ }
15-
16-
// is the same as
17-
18-
public class Person : Identifiable<int>
19-
{ }
20-
```
21-
22-
If you need to hang annotations or attributes on the `Id` property,
23-
you can override the virtual property.
3+
If you want an attribute on your model to be publicly available, add the `AttrAttribute`.
244

255
```c#
266
public class Person : Identifiable
27-
{
28-
[Key]
29-
[Column("person_id")]
30-
public override int Id { get; set; }
7+
{
8+
[Attr]
9+
public string FirstName { get; set; }
3110
}
3211
```
3312

34-
If your resource must inherit from another class,
35-
you can always implement the interface yourself.
36-
In this example, `ApplicationUser` inherits `IdentityUser`
37-
which already contains an Id property of type string.
13+
## Public name
3814

15+
There are two ways the public attribute name is determined:
16+
1. By convention, specified by @JsonApiDotNetCore.Configuration.JsonApiOptions#JsonApiDotNetCore_Configuration_JsonApiOptions_ResourceNameFormatter
3917
```c#
40-
public class ApplicationUser : IdentityUser, IIdentifiable<string>
41-
{
42-
[NotMapped]
43-
public string StringId { get => Id; set => Id = value; }
44-
}
18+
options.ResourceNameFormatter = new DefaultResourceNameFormatter();
4519
```
4620

47-
## Attributes
48-
49-
If you want an attribute on your model to be publicly available,
50-
add the `AttrAttribute` and provide the outbound name.
51-
21+
2. Individually using the attribute's constructor
5222
```c#
5323
public class Person : Identifiable
5424
{
@@ -57,19 +27,19 @@ public class Person : Identifiable
5727
}
5828
```
5929

60-
### Immutability
30+
## Immutability
6131

6232
Attributes can be marked as immutable which will prevent `PATCH` requests from updating them.
6333

6434
```c#
6535
public class Person : Identifiable<int>
6636
{
67-
[Attr("first-name", immutable: true)]
37+
[Attr(immutable: true)]
6838
public string FirstName { get; set; }
6939
}
7040
```
7141

72-
### Filter|Sort-ability
42+
## Filter|Sort-ability
7343

7444
All attributes are filterable and sortable by default.
7545
You can disable this by setting `IsFiterable` and `IsSortable` to `false `.
@@ -78,12 +48,12 @@ Requests to filter or sort these attributes will receive an HTTP 400 response.
7848
```c#
7949
public class Person : Identifiable<int>
8050
{
81-
[Attr("first-name", isFilterable: false, isSortable: false)]
51+
[Attr(isFilterable: false, isSortable: false)]
8252
public string FirstName { get; set; }
8353
}
8454
```
8555

86-
### Complex Attributes
56+
## Complex Attributes
8757

8858
Models may contain complex attributes.
8959
Serialization of these types is done by Newtonsoft.Json,
@@ -93,7 +63,7 @@ You can also use global options to specify the `JsonSerializer` that gets used.
9363
```c#
9464
public class Foo : Identifiable
9565
{
96-
[Attr("bar")]
66+
[Attr]
9767
public Bar Bar { get; set; }
9868
}
9969

@@ -112,7 +82,7 @@ and retrieval.
11282
```c#
11383
public class Foo : Identifiable
11484
{
115-
[Attr("bar"), NotMapped]
85+
[Attr, NotMapped]
11686
public Bar Bar { get; set; }
11787

11888
public string BarJson
@@ -126,34 +96,4 @@ public class Foo : Identifiable
12696
: JsonConvert.DeserializeObject(value);
12797
};
12898
}
129-
```
130-
131-
## Relationships
132-
133-
In order for navigation properties to be identified in the model,
134-
they should be labeled with the appropriate attribute (either `HasOne` or `HasMany`).
135-
136-
```c#
137-
public class Person : Identifiable<int>
138-
{
139-
[Attr("first-name")]
140-
public string FirstName { get; set; }
141-
142-
[HasMany("todo-items")]
143-
public virtual List<TodoItem> TodoItems { get; set; }
144-
}
145-
```
146-
147-
Dependent relationships should contain a property in the form `{RelationshipName}Id`. For example, a TodoItem may have an Owner and so the Id attribute should be OwnerId.
148-
149-
```c#
150-
public class TodoItem : Identifiable<int>
151-
{
152-
[Attr("description")]
153-
public string Description { get; set; }
154-
155-
[HasOne("owner")]
156-
public virtual Person Owner { get; set; }
157-
public int OwnerId { get; set; }
158-
}
15999
```

docs/usage/resources/index.md

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Resources
2+
3+
At a minimum, resources must implement `IIdentifiable<TId>` where `TId` is the type of the primary key. The easiest way to do this is to inherit `Identifiable<TId>`.
4+
5+
```c#
6+
public class Person : Identifiable<Guid>
7+
{ }
8+
```
9+
10+
You can use the non-generic `Identifiable` if your primary key is an integer.
11+
12+
```c#
13+
public class Person : Identifiable
14+
{ }
15+
16+
// is the same as
17+
18+
public class Person : Identifiable<int>
19+
{ }
20+
```
21+
22+
If you need to hang annotations or attributes on the `Id` property,
23+
you can override the virtual property.
24+
25+
```c#
26+
public class Person : Identifiable
27+
{
28+
[Key]
29+
[Column("person_id")]
30+
public override int Id { get; set; }
31+
}
32+
```
33+
34+
If your resource must inherit from another class,
35+
you can always implement the interface yourself.
36+
In this example, `ApplicationUser` inherits `IdentityUser`
37+
which already contains an Id property of type string.
38+
39+
```c#
40+
public class ApplicationUser : IdentityUser, IIdentifiable<string>
41+
{
42+
[NotMapped]
43+
public string StringId { get => Id; set => Id = value; }
44+
}
45+
```

docs/usage/resources/relationships.md

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Relationships
2+
3+
In order for navigation properties to be identified in the model,
4+
they should be labeled with the appropriate attribute (either `HasOne`, `HasMany` or `HasManyThrough`).
5+
6+
## HasOne
7+
8+
Dependent relationships should contain a property in the form `{RelationshipName}Id`.
9+
For example, a TodoItem may have an Owner and so the Id attribute should be OwnerId.
10+
11+
```c#
12+
public class TodoItem : Identifiable<int>
13+
{
14+
[Attr("description")]
15+
public string Description { get; set; }
16+
17+
[HasOne("owner")]
18+
public virtual Person Owner { get; set; }
19+
public int OwnerId { get; set; }
20+
}
21+
```
22+
23+
The convention used used to locate the foreign key property (e.g. `OwnerId`) can be changed on
24+
the @JsonApiDotNetCore.Configuration.JsonApiOptions#JsonApiDotNetCore_Configuration_JsonApiOptions_RelatedIdMapper
25+
26+
## HasMany
27+
28+
```c#
29+
public class Person : Identifiable<int>
30+
{
31+
[Attr("first-name")]
32+
public string FirstName { get; set; }
33+
34+
[HasMany("todo-items")]
35+
public virtual List<TodoItem> TodoItems { get; set; }
36+
}
37+
```
38+
39+
## HasManyThrough
40+
41+
Currently EntityFrameworkCore [does not support](https://github.com/aspnet/EntityFrameworkCore/issues/1368) Many-to-Many relationships without a join entity.
42+
For this reason, we have decided to fill this gap by allowing applications to declare a relationships as `HasManyThrough`.
43+
JsonApiDotNetCore will expose this attribute to the client the same way as any other `HasMany` attribute.
44+
However, under the covers it will use the join type and EntityFramework's APIs to get and set the relationship.
45+
46+
```c#
47+
public class Article : Identifiable
48+
{
49+
[NotMapped] // ← tells EF to ignore this property
50+
[HasManyThrough(nameof(ArticleTags))] // ← tells JADNC to use this as an alias to ArticleTags.Tags
51+
public List<Tag> Tags { get; set; }
52+
53+
// this is the EF join relationship
54+
public List<ArticleTag> ArticleTags { get; set; }
55+
}
56+
```

docs/usage/toc.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
# [Resources](resources.md)
1+
# [Resources](resources/index.md)
2+
## [Attributes](resources/attributes.md)
3+
## [Relationships](resources/relationships.md)
4+
25
# [Resource Graph](resource-graph.md)
36
# [Metadata](meta.md)
47
# [Filtering](filtering.md)

src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
namespace JsonApiDotNetCore.Configuration
1313
{
1414
/// <summary>
15-
/// Global options.
16-
/// https://json-api-dotnet.github.io/#/global-options
15+
/// Global options
1716
/// </summary>
1817
public class JsonApiOptions
1918
{

0 commit comments

Comments
 (0)