#json-api #json #api

ciboulette

Library to parse JSON:API requests and build responses

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

#40 in #json-api


Used in 2 crates

MIT/Apache

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

~5–10MB
~246K SLoC