Skip to content

Latest commit

History

40 Commits

Folders and files

NameName
Last commit message
Last commit date

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")]structTodoResource{id:Uuid,attributes:TodoAttributes,relations:TodoRelations}#[derive(Serialize,Clone)]structTodoAttributes{title:String,done:bool}#[derive(IntoRelationships,FromRelationships,Clone)]structTodoRelations{#[jsonapi(resource_type = "users")]assignee:Option<Uuid>,}structTodoStore{inner:RwLock<BTreeMap<Uuid,Todo>>}implStoreforTodoStore{typeResource = TodoResource;typeCtx = Session<User>;// per-request session, see auth::Session}implShowforTodoStore{typeShown = TodoResource;// plain async fn: Diesel, an HTTP call, whatever — your business.asyncfnshow(&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

FeatureDefaultAdds
serveryesUuid as a valid resource id type (FromID for Uuid)
actixwebnoOperation traits (Store/Show/List/Create/Update/Delete), route mounting (actix::resource), body extractors, and session middleware (auth)
dieselnodiesel::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

Packages

Used by

Contributors

Languages