sanity-rs 0.1.0

Porting @sanity/client in Rust
Documentation
# 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

- [Features and Roadmap]#features-and-roadmap
- [Getting started]#getting-started
  - [Creating client]#creating-client
  - [Querying documents]#querying-documents
  - [Using ORM trait]#using-orm-trait
- [PortableText to HTML]#portabletext-to-html
- [Examples]#examples

## Installation 

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

## Features and Roadmap

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

## Getting started

### Creating client

```rust
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

```rust
#[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.

```rust
#[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.

```rust
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.

- [Tokio example]examples/simple-tokio
- [Full Server Side Rendering example with Actix Web ]examples/actix-web-static-page