Skip to content

Commit bd75894

Browse files
wisepotatomaurei
authored andcommitted
Feat/serialization wiki (#561)
* docs: add decoupling architecture, wiki folder * docs: add v4 wiki * chore: restructure of intro * chore: v4
1 parent c55672b commit bd75894

File tree

3 files changed

+70
-31
lines changed

3 files changed

+70
-31
lines changed

wiki/v4/content/deprecation.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Deprecation
2+
3+
* Bulk
4+
* Operations
5+
* Resource entity seperation
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,111 @@
1-
# Architectual overview of serializers and deserializers
21

3-
The main change is that now serializers and deserializers are split into
4-
- base serializers (deserializers) that contain building (parsing) logic shared by server and client side implementations
5-
- server and client serializers (deserializers) that are responsible for any additional building (parsing) logic unique to their implementations.
2+
# Serialization
63

7-
In deserialization, some parts are relevant only for client-side parsing whereas others are only for server-side parsing. for example, a server deserializer will never have to deal with a `included` object list. Similarly, in serialization, a client serializer will for example never ever have to populate any other top-level members than the primary data (like `meta`, `included`). These are examples of implementation-specific parsing/building for which the responsibility is moved to the corresponding implementation.
4+
The main change for serialization is that we have split the serialization responsibilities into two parts:
85

9-
Throughout the document and the code when referring to fields, members, object types, the technical language of json:api spec is used. At the core of (de)serialization is the
6+
* **Response (de)serializers** - (de)Serialization regarding serving or interpreting a response.
7+
* **Request (de)serializer** - (de)Serialization regarding creating or interpreting a request.
8+
9+
This split is done because during deserialization, some parts are relevant only for *client*-side parsing whereas others are only for *server*-side parsing. for example, a server deserializer will never have to deal with a `included` object list. Similarly, in serialization, a client serializer will for example never ever have to populate any other top-level members than the primary data (like `meta`, `included`).
10+
11+
Throughout the document and the code when referring to fields, members, object types, the technical language of json:api spec is used. At the core of (de)serialization is the
1012
`Document` class, [see document spec](https://jsonapi.org/format/#document-structure).
1113

12-
## Deserialization
14+
## Changes
15+
16+
In this section we will detail the changes made to the (de)serialization compared to the previous version.
17+
18+
### Deserialization
19+
1320
The previous `JsonApiDeSerializer` implementation is now split into a `RequestDeserializer` and `ResponseDeserializer`. Both inherit from `BaseDocumentParser` which does the shared parsing.
1421

1522
#### BaseDocumentParser
16-
Responsible for
17-
- Converting the serialized string content into an intance of the `Document` class.
18-
- Building instances of the corresponding resource class (eg `Article`) by going through the document's primary data (`Document.Data`, [see primary data spec](https://jsonapi.org/format/#document-top-level)).
1923

20-
Responsibility of any implementation-specific parsing is shifted through the abstract `BaseDocumentParser.AfterProcessField()` method. This method is fired once each time after a `AttrAttribute` or `RelationshipAttribute` is processed. It allows a implementation of `BaseDocumentParser` to intercept the parsing and add steps that are only required for clients/servers.
24+
This (base) class is responsible for:
25+
26+
* Converting the serialized string content into an intance of the `Document` class. Which is the most basic version of JSON API which has a `Data`, `Meta` and `Included` property.
27+
* Building instances of the corresponding resource class (eg `Article`) by going through the document's primary data (`Document.Data`) For the spec for this: [Document spec](https://jsonapi.org/format/#document-top-level).
28+
29+
Responsibility of any implementation the base class-specific parsing is shifted through the abstract `BaseDocumentParser.AfterProcessField()` method. This method is fired once each time after a `AttrAttribute` or `RelationshipAttribute` is processed. It allows a implementation of `BaseDocumentParser` to intercept the parsing and add steps that are only required for new implementations.
2130

2231
#### ResponseDeserializer
23-
The client deserializer complements the base deserialization by
24-
* overriding the `AfterProcessField` method which takes care of the Included section
25-
* after a relationship was deserialized, it finds the appended included object and adds it attributs and (nested) relationships
32+
33+
The client deserializer complements the base deserialization by
34+
35+
* overriding the `AfterProcessField` method which takes care of the Included section \* after a relationship was deserialized, it finds the appended included object and adds it attributs and (nested) relationships
2636
* taking care of remaining top-level members. that are only relevant to a client-side parser (meta data, server-side errors, links).
2737

2838
#### RequestDeserializer
39+
2940
For server-side parsing, no extra parsing needs to be done after the base deserialization is completed. It only needs to keep track of which `AttrAttribute`s and `RelationshipAttribute`s were targeted by a request. This is needed for the internals of JADNC (eg the repository layer).
41+
3042
* The `AfterProcessField` method is overriden so that every attribute and relationship is registered with the `ITargetedFields` service after it is processed.
3143

3244
## Serialization
33-
Like with the deserializers, `JsonApiSerializer` is now split up into a `ResponseSerializer` and `RequestSerializer`. Both inherit from a shared `BaseDocumentBuilder` class. Additionally, `BaseDocumentBuilder` inherits from `ResourceObjectBuilder`, which is extended by `IncludedResourceObjectBuilder`.
45+
46+
Like with the deserializers, `JsonApiSerializer` is now split up into these classes (indentation implies hierarchy/extending):
47+
48+
* `IncludedResourceObjectBuilder`
49+
50+
* `ResourceObjectBuilder` - *abstract*
51+
* `DocumentBuilder` - *abstract* -
52+
* `ResponseSerializer`
53+
* `RequestSerializer`
3454

3555
### ResourceObjectBuilder
56+
3657
At the core of serialization is the `ResourceObject` class [see resource object spec](https://jsonapi.org/format/#document-resource-objects).
3758

38-
ResourceObjectBuilder is responsible for
39-
- Building a `ResourceObject` from an entity given a list of `AttrAttribute`s and `RelationshipAttribute`s.
40-
- Note: the resource object builder is NOT responsible for figuring out which attributes and relationships should be included in the serialization result, because this differs depending on an the implementation being client or server side.
41-
Instead, it is provided with the list.
59+
ResourceObjectBuilder is responsible for Building a `ResourceObject` from an entity given a list of `AttrAttribute`s and `RelationshipAttribute`s. - Note: the resource object builder is NOT responsible for figuring out which attributes and relationships should be included in the serialization result, because this differs depending on an the implementation being client or server side. Instead, it is provided with the list.
4260

4361
Additionally, client and server serializers also differ in how relationship members ([see relationship member spec](https://jsonapi.org/format/#document-resource-object-attributes) are formatted. The responsibility for handling this is again shifted, this time by virtual `ResourceObjectBuilder.GetRelationshipData()` method. This method is fired once each time a `RelationshipAttribute` is processed, allowing for additional serialization (like adding links or metadata).
4462

4563
This time, the `GetRelationshipData()` method is not abstract, but virtual with a default implementation. This default implementation is to just create a `RelationshipData` with primary data (like `{"related-foo": { "data": { "id": 1" "type": "foobar"}}}`). Some implementations (server, included builder) need additional logic, others don't (client).
4664

4765
### BaseDocumentBuilder
4866
Responsible for
49-
- Calling the base resource object serialization for one (or many) entities and wrapping the result in a `Document`.
67+
68+
- Calling the base resource object serialization for one (or many) entities and wrapping the result in a `Document`.
5069

5170
Thats all. It does not figure out which attributes or relationships are to be serialized.
5271

5372
### RequestSerializer
73+
5474
Responsible for figuring out which attributes and relationships need to be serialized and calling the base document builder with that.
5575
For example:
56-
- for a POST request, this is often (almost) all attributes.
57-
- for a PATCH request, this is usually a small subset of attributes.
76+
77+
- for a POST request, this is often (almost) all attributes.
78+
- for a PATCH request, this is usually a small subset of attributes.
5879

5980
Note that the client serializer is relatively skinny, because no top-level data (included, meta, links) will ever have to be added anywhere in the document.
6081

6182
### ResponseSerializer
83+
6284
Responsible for figuring out which attributes and relationships need to be serialized and calling the base document builder with that.
6385
For example, for a GET request, all attributes are usually included in the output, unless
64-
- Sparse field selection was applied in the client request
65-
- Runtime attribute hiding was applied, see [JADNC docs](https://json-api-dotnet.github.io/JsonApiDotNetCore/usage/resources/resource-definitions.html#runtime-attribute-filtering)
86+
87+
* Sparse field selection was applied in the client request
88+
* Runtime attribute hiding was applied, see [JADNC docs](https://json-api-dotnet.github.io/JsonApiDotNetCore/usage/resources/resource-definitions.html#runtime-attribute-filtering)
6689

6790
The server serializer is also responsible for adding top-level meta data and links and appending included relationships. For this the `GetRelationshipData()` is overriden:
68-
- it adds links to the `RelationshipData` object (if configured to do so, see `ILinksConfiguration`).
69-
- it checks if the processed relationship needs to be enclosed in the `included` list. If so, it calls the `IIncludedResourceObjectBuilder` to take care of that.
7091

92+
* it adds links to the `RelationshipData` object (if configured to do so, see `ILinksConfiguration`).
93+
* it checks if the processed relationship needs to be enclosed in the `included` list. If so, it calls the `IIncludedResourceObjectBuilder` to take care of that.
7194

7295
### IncludedResourceObjectBuilder
7396
Responsible for building the *included member* of a `Document`. Note that `IncludedResourceObjectBuilder` extends `ResourceObjectBuilder` and not `BaseDocumentBuilder` because it does not need to build an entire document but only resource objects.
7497

75-
Relationship *inclusion chains* are at the core of building the included member. For example, consider the request `articles?included=author.blogs.reviewers.favorite-food,reviewer.blogs.author.favorite-song`. It contains the following (complex) inclusion chains:
98+
Responsible for building the _included member_ of a `Document`. Note that `IncludedResourceObjectBuilder` extends `ResourceObjectBuilder` and not `DocumentBuilder` because it does not need to build an entire document but only resource objects.
99+
100+
Relationship _inclusion chains_ are at the core of building the included member. For example, consider the request `articles?included=author.blogs.reviewers.favorite-food,reviewer.blogs.author.favorite-song`. It contains the following (complex) inclusion chains:
101+
76102
1. `author.blogs.reviewers.favorite-food`
77103
2. `reviewer.blogs.author.favorite-song`
78104

79105
Like with the `RequestSerializer` and `ResponseSerializer`, the `IncludedResourceObjectBuilder` is responsible for calling the base resource object builder with the list of attributes and relationships. For this implementation, these lists depend strongly on the inclusion chains. The above complex example demonstrates this (note: in this example the relationships `author` and `reviewer` are of the same resource `people`):
80-
- people that were included as reviewers from inclusion chain (1) should come with their `favorite-food` included, but not those from chain (2)
81-
- people that were included as authors from inclusion chain (2) should come with their `favorite-song` included, but not those from chain (1).
82-
- a person that was included as both an reviewer and author (i.e. targeted by both chain (1) and (2)), both `favorite-food` and `favorite-song` need to be present.
83106

84-
To achieve this all of this, the `IncludedResourceObjectBuilder` needs to recursively parse an inclusion chain and make sure it does not append the same included more than once. This strategy is different from that of the ResponseSerializer, and for that reason it is a separate service.
107+
* people that were included as reviewers from inclusion chain (1) should come with their `favorite-food` included, but not those from chain (2)
108+
* people that were included as authors from inclusion chain (2) should come with their `favorite-song` included, but not those from chain (1).
109+
* a person that was included as both an reviewer and author (i.e. targeted by both chain (1) and (2)), both `favorite-food` and `favorite-song` need to be present.
85110

111+
To achieve this all of this, the `IncludedResourceObjectBuilder` needs to recursively parse an inclusion chain and make sure it does not append the same included more than once. This strategy is different from that of the ResponseSerializer, and for that reason it is a separate service.

wiki/v4/decoupling-architecture.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# V4 Architecture overview
2+
3+
We upgraded to .NET Core 3.0. Furthermore, for V4 we have some explaining to do, namely the most notable changes:
4+
5+
- [Serialization](./content/serialization.md)
6+
- [Extendability](./content/extendability.md)
7+
- [Testing](./content/testing.md) sdf
8+
- [Deprecation](./content/deprecation.md)

0 commit comments

Comments
 (0)