5 releases
0.1.4 | May 13, 2021 |
---|---|
0.1.3 | May 13, 2021 |
0.1.2 | May 2, 2021 |
0.1.1 | Apr 29, 2021 |
0.1.0 | Apr 28, 2021 |
#39 in #json-api
Used in 2 crates
370KB
10K
SLoC
Ciboulette
A JSON:API library.
See the documentation
lib.rs
:
Introduction
Ciboulette is a JSON:API
library.
It allows one to parse request and build response respecting the JSON:API
specifications.
It aims to have a low memory footprint and be fast.
High level view of components
At a high level, an API
is constitued of resource types. The resource type are organized
in a graph representing their relationships as edges.
In addition to the graph, an adgacent map is used to efficiently retrieve resource types by their alias. This whole structure is held in a store.
Resource types
The resource types can be built using a resource type builder. It's made of :
- A name, that will later be used as an alias to fetch the resource types from the store's graph.
- A id type, which will be used to deserialize the ids the requests.
- A schema which will be used to deserialize the body of the requests and serialize the response.
Relationship options
Many-to-Many
The option struct map a resource "A" to another resource "C" through another resource "B" (bucket)
Resource A Resource B (bucket) Resource C
┌─────────────────┐ ┌─────────────────────────────────────────────┐ ┌─────────────────┐
│ │ │ │ │ │
│ peoples──►id───┼──┼──►people_id◄──people-article──►article_id◄──┼──┼──id◄──articles │
│ │ │ │ │ │
└─────────────────┘ └─────────────────────────────────────────────┘ └─────────────────┘
When creating a Many-to-Many relationships (A <-> C
), we'll also create a Many-to-One relationship between the table
A -> B
, C -> B
, B -> A
and B -> C
so that we can reference the relationship directly.
One-to-Many / Many-to-One
The option struct map a "many" resource to a "one" resource.
Many table One table
┌──────────────────────────────────────────────────┐ ┌──────────────────────────────────────┐
│ │ │ │
│ many_table_element_0──────────►many_table_key_0──┼──┼──►one_table_id◄───one_table_element │
│ │ │ ▲ ▲ │
│ │ │ │ │ │
│ many_table_element_1──────────►many_table_key_1──┼──┼─────┘ │ │
│ │ │ │ │
│ │ │ │ │
│ many_table_element_2──────────►many_table_key_2──┼──┼────────────┘ │
│ │ │ │
│ │ └──────────────────────────────────────┘
└──────────────────────────────────────────────────┘
In the option a field is used to determined if a Many-to-One/One-to-Many relationship is part of Many-to-Many relationship.
Requests
Every requests boils down to the same components. But there is some quirks :
- Creation request can be valid without resource id,
- Update request can have a body of resource identifier.
Every requests must first be deserialized using the request builder. Then it can be built into an generic request. From that, one can convert to the desired request type depending on the intention. Trying to convert a generic request to an incompatible sub-type will result in an error. The correct conversion map goes like this :
Intention | Request type |
---|---|
Create | Create request |
Read | Read request |
Update | Update request |
Delete | Delete request |
Every sub-type of requests implement a common trait to allow for genericity.
Responses
A response is built from a request and a list of response element.
Depending on the request, the response will be built to the correct format.
Response elements
Each response should have a single main resource type.
The response elements are composed as follow for an element part of the main resource type:
Response element field | Always required | Description |
---|---|---|
type |
✅ | The current element resource type |
identifier |
✅ | The current element resource identifier |
data |
❌ | The JSON data of the resource, if any |
related .rel_chain |
❌ (only for related data) |
Chain of relation metadata from the main resource type |
related .element |
❌ (only for related data) |
The resource identifier of the element it relates to |
Dependencies
~6–11MB
~243K SLoC