Skip to content

qmuloadmin/jsonapi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

jsonapi

Serde types for JSON:API documents, plus (optionally) a deep actix-web integration that turns a resource definition and a hand-written store into spec-compliant CRUD endpoints — routing, query parsing, envelope building, pagination links, content types, and error rendering, all owned by this crate.

Quickstart

Define a resource with the derive macros, implement whichever operation traits your store supports, mount it. (Lifted from examples/src/main.rs, which is a complete runnable server — see below.)

#[derive(IntoResponse, ResourceType)]
#[jsonapi(name = "todos")]
struct TodoResource { id: Uuid, attributes: TodoAttributes, relations: TodoRelations }

#[derive(Serialize, Clone)]
struct TodoAttributes { title: String, done: bool }

#[derive(IntoRelationships, FromRelationships, Clone)]
struct TodoRelations {
    #[jsonapi(resource_type = "users")]
    assignee: Option<Uuid>,
}

struct TodoStore { inner: RwLock<BTreeMap<Uuid, Todo>> }

impl Store for TodoStore {
    type Resource = TodoResource;
    type Ctx = Session<User>;   // per-request session, see auth::Session
}

impl Show for TodoStore {
    type Shown = TodoResource;
    // plain async fn: Diesel, an HTTP call, whatever — your business.
    async fn show(&self, ctx: Session<User>, id: Uuid, q: ShowQuery) -> Result<Self::Shown, Error> { ... }
}
// ...List, Create, Update, Delete similarly.

HttpServer::new(move || {
    App::new()
        .app_data(store.clone())
        .wrap(UserSessionMiddleware::new(DemoUserFactory))
        .service(resource::<TodoStore>().show().list().create().update().delete())
})
.bind(("127.0.0.1", 8080))?
.run()
.await

Each builder method (.show(), .list(), ...) only compiles if the store implements the matching trait — capability is an implementation, there's no runtime "not supported" path.

Features

Feature Default Adds
server yes Uuid as a valid resource id type (FromID for Uuid)
actixweb no Operation traits (Store/Show/List/Create/Update/Delete), route mounting (actix::resource), body extractors, and session middleware (auth)
diesel no diesel::result::Errorjsonapi::Error mapping (NotFound→404, unique violation→409, FK/check violation→400, else 500)

URL conventions handled for you

  • Filters are FLAT top-level query params: name[eq]=x, name[contains]=y — via [StringMatch]; price[gte]=10&price[lte]=20 — via [Range<T>]. The names page, sort, and include are reserved (parsed separately) and must not be used as filter field names. Spec-style nesting under filter[...] is still available, opt-in, by giving your filter type a single filter: Inner field — see ListQuery::parse.
  • sort=-created,name — parses into an ordered Vec<(K, Direction)>; unknown keys are a 400, not silently ignored
  • page[size]=25&page[after]=<cursor> — the cursor-pagination profile: response links.next/links.prev and per-item meta.page.cursor, built from the CursorPage::from_probe (LIMIT size+1) idiom
  • include=author,comments.author — parsed into path segments; whether/how to honor it is the store's choice
  • application/vnd.api+json on every response (documents and errors alike)

Strict plain-JSON clients

Every response this crate renders — documents and error documents alike — carries Content-Type: application/vnd.api+json, per spec. Some HTTP tooling is strict about Accept: application/json and balks at that media type even though the body is ordinary JSON. Wrap the app with [actix::NegotiateContentType] to relabel the header (not the body) to application/json whenever a request's Accept explicitly prefers it:

App::new().wrap(jsonapi::actix::NegotiateContentType).service(/* ... */)

It's opt-in and covers success documents, error documents, extractor failures, and hand-written routes uniformly, since it works at the middleware layer rather than in any one handler.

Examples

examples/ is a small standalone crate with a complete "todos" JSON:API server (cargo run --bin todo-server) wiring the derive macros, the operation traits, cursor pagination, and session-middleware-based authorization together end to end. Start there.

About

A JSONAPI Server implementation for rust

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages