1 unstable release

Uses new Rust 2024

new 0.1.0 May 8, 2025

#367 in Web programming

Download history 107/week @ 2025-05-05

107 downloads per month

MIT/Apache

71KB
2K SLoC

Rust client for Sanity.io

Porting @sanity/client in Rust

This project is to easily query and parse documents from sanity.io and use it in your async rust runtime.

Table of Contents

Installation

cargo add https://github.com/Riley1101/sanity-rs

Features and Roadmap

  • Base
    • Raw string query
    • support String raw response
    • serde integration with generics
  • PortableText Renderer
    • Base sanity portable text
    • Extract rust-portabletext crate
  • ORM
    • get_by_id
    • get_by_ids
    • more options
  • Mutations
  • Subscribe

Getting started

Creating client

use sanity_rs::client::{ SanityClient , create_client};
use sanity_rs::config::SanityConfig;

let sanity_project_id = std::env::var("SANITY_PROJECT_ID")
    .map_err(|_| ConfigurationError::MissingProjectID)
    .expect("Missing project ID");
let sanity_dataset = std::env::var("SANITY_DATASET")
    .map_err(|_| ConfigurationError::MissingDataset)
    .expect("Missing dataset");
let config = SanityConfig::new(sanity_project_id, sanity_dataset);
let client = create_client(config);

Querying documents

#[tokio::test]
async fn fetch_a_document() -> Result<(), RequestError> {
    dotenv().ok();
    let sanity_project_id = std::env::var("SANITY_PROJECT_ID")
        .map_err(|_| ConfigurationError::MissingProjectID)
        .expect("Missing project ID");
    let sanity_dataset = std::env::var("SANITY_DATASET")
        .map_err(|_| ConfigurationError::MissingDataset)
        .expect("Missing dataset");
    let config: SanityConfig = SanityConfig::new(sanity_project_id, sanity_dataset);
    let mut client = create_client(config);
    let query = r#"
        *[_id == "0c80e597-8275-40b7-a3f5-1a3d3448bc39"][0]{
        _id,
        _createdAt
        }
    "#;
    let value: Result<QueryResult<Record>, RequestError> = client.query(query).await?.json();
    assert!(value.is_ok());
    Ok(())
}

Using ORM trait

Currently there are a few ORM methods you can use to query documents.

#[tokio::test]
async fn orm_get_by_id() -> Result<(), RequestError> {
    dotenv().ok();
    let sanity_project_id = std::env::var("SANITY_PROJECT_ID")
        .map_err(|_| ConfigurationError::MissingProjectID)
        .expect("Missing project ID");
    let sanity_dataset = std::env::var("SANITY_DATASET")
        .map_err(|_| ConfigurationError::MissingDataset)
        .expect("Missing dataset");
    let config: SanityConfig = SanityConfig::new(sanity_project_id, sanity_dataset);
    let mut client = create_client(config);

    let v = client
        .get_by_id("0c80e597-8275-40b7-a3f5-1a3d3448bc39")
        .body("{_id,_createdAt}")
        .send()
        .await?
        .json::<QueryResult<Record>>();
    assert!(v.is_ok());
    Ok(())
}

#[tokio::test]
async fn orm_get_by_ids() -> Result<(), RequestError> {
    dotenv().ok();
    let sanity_project_id = std::env::var("SANITY_PROJECT_ID")
        .map_err(|_| ConfigurationError::MissingProjectID)
        .expect("Missing project ID");
    let sanity_dataset = std::env::var("SANITY_DATASET")
        .map_err(|_| ConfigurationError::MissingDataset)
        .expect("Missing dataset");
    let config: SanityConfig = SanityConfig::new(sanity_project_id, sanity_dataset);
    let mut client = create_client(config);

    let v = client
        .get_by_ids(&[
            "09139a58-311b-4779-8fa4-723f19242a8e",
            "09139a58-311b-4779-8fa4-723f19242a8e",
        ])
        .body("{_id,_createdAt}")
        .send()
        .await?
        .json::<QueryResult<Vec<Record>>>();
    assert!(v.is_ok());
    Ok(())
}

PortableText to HTML

You can now use default use sanity_rs::portabletext::renderer::ToHTML; to render portable texts into HTML documents.

Each PortableTextNode can call HTML trait to call html() function. Here is an example using default renderer.

let mut client = client.lock().await;
let v = client
    .get_by_id(&id)
    .body("{title,description,_id,body}")
    .send()
    .await
    .unwrap()
    .json::<QueryResult<ArticleWithBody>>();

let article = match v {
    Ok(res) => res.result,
    Err(_e) => ArticleWithBody {
        title: "Not Found".to_string(),
        description: "Article not found".to_string(),
        body: None,
        _id: "0".to_string(),
    },
};
let body = article.body.unwrap_or_default();
let body = ToHTML::new(body).render();
let response = format!("{result}", result = body); // result HTML string

Examples

Checkout examples/ folder for more examples.

Dependencies

~5–20MB
~204K SLoC