| Crates.io | rjapi |
| lib.rs | rjapi |
| version | 0.0.1 |
| created_at | 2025-09-22 09:13:28.378241+00 |
| updated_at | 2025-09-22 09:13:28.378241+00 |
| description | A framework-agnostic JSON:API 1.1 implementation for Rust |
| homepage | https://github.com/mohdbk/rjapi |
| repository | https://github.com/mohdbk/rjapi |
| max_upload_size | |
| id | 1849715 |
| size | 79,277 |
A framework-agnostic, ergonomic, and type-safe implementation of the JSON:API 1.1 specification for Rust applications.
Add this to your Cargo.toml:
[dependencies]
rjapi = "0.0.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
To make your models compatible with rjapi, implement the JsonApiResource trait.
use rjapi::JsonApiResource;
use serde::Serialize;
use serde_json::json;
#[derive(Serialize)]
struct Post {
id: String,
title: String,
content: String,
}
impl JsonApiResource for Post {
const RESOURCE_TYPE: &'static str = "posts";
fn id(&self) -> String {
self.id.clone()
}
fn attributes(&self) -> serde_json::Value {
json!({
"title": self.title,
"content": self.content,
})
}
}
Use the JsonApiResponse builder to construct type-safe, compliant JSON:API responses.
use rjapi::{JsonApiResponse, Resource};
# use rjapi::JsonApiResource;
# use serde::Serialize;
# use serde_json::json;
# #[derive(Serialize)]
# struct Post {
# id: String,
# title: String,
# content: String,
# }
# impl JsonApiResource for Post {
# const RESOURCE_TYPE: &'static str = "posts";
# fn id(&self) -> String { self.id.clone() }
# fn attributes(&self) -> serde_json::Value { json!({ "title": self.title, "content": self.content }) }
# }
let post = Post {
id: "1".to_string(),
title: "Hello, World!".to_string(),
content: "This is the first post.".to_string(),
};
let resource = Resource {
resource_type: Post::RESOURCE_TYPE.to_string(),
id: post.id(),
attributes: Some(post.attributes()),
relationships: None,
links: None,
meta: None,
};
let response = JsonApiResponse::new(resource).build();
println!("{}", serde_json::to_string_pretty(&response).unwrap());
The JsonApiRequest extractor simplifies request handling in your web framework.
use axum::{
extract::State,
http::StatusCode,
response::{IntoResponse, Response},
Json, Router,
};
use rjapi::{JsonApiResponse, JsonApiResource, Resource, JsonApiRequest};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use tokio::sync::RwLock;
// Application state
#[derive(Clone)]
struct AppState {
posts: Arc<RwLock<Vec<Post>>>,
}
# #[derive(Clone, Serialize, Deserialize)]
# struct Post {
# id: String,
# title: String,
# content: String,
# }
# impl JsonApiResource for Post {
# const RESOURCE_TYPE: &'static str = "posts";
# fn id(&self) -> String { self.id.clone() }
# fn attributes(&self) -> serde_json::Value { serde_json::json!({ "title": self.title, "content": self.content }) }
# }
// A specific type for post creation attributes
#[derive(Deserialize)]
struct PostAttributes {
title: String,
content: String,
}
// Axum handler for creating a post
async fn create_post(
State(state): State<AppState>,
Json(request): Json<JsonApiRequest<PostAttributes>>,
) -> impl IntoResponse {
let attributes = request.data.attributes;
let post = Post {
id: uuid::Uuid::new_v4().to_string(),
title: attributes.title,
content: attributes.content,
};
state.posts.write().await.push(post.clone());
let resource = Resource {
resource_type: Post::RESOURCE_TYPE.to_string(),
id: post.id(),
attributes: Some(serde_json::to_value(post).unwrap()),
..Default::default()
};
let response = JsonApiResponse::new(resource).build();
(StatusCode::CREATED, Json(response))
}
For full documentation, visit docs.rs/rjapi.
Check out the examples directory for more detailed usage examples:
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please read our Contributing Guide for details on how to submit pull requests, report issues, and suggest improvements.