forked from
nonbinary.computer/jacquard
A better Rust ATProto crate
1# Jacquard
2
3A suite of Rust crates for the AT Protocol.
4
5[](https://crates.io/crates/jacquard) [](https://docs.rs/jacquard) [](./LICENSE)
6
7## Goals
8
9- Validated, spec-compliant, easy to work with, and performant baseline types (including typed at:// uris)
10- Batteries-included, but easily replaceable batteries.
11 - Easy to extend with custom lexicons
12- lexicon Value type for working with unknown atproto data (dag-cbor or json)
13- order of magnitude less boilerplate than some existing crates
14 - either the codegen produces code that's easy to work with, or there are good handwritten wrappers
15- didDoc type with helper methods for getting handles, multikey, and PDS endpoint
16- use as much or as little from the crates as you need
17
18
19## Example
20
21Dead simple api client. Logs in, prints the latest 5 posts from your timeline.
22
23```rust
24use clap::Parser;
25use jacquard::CowStr;
26use jacquard::api::app_bsky::feed::get_timeline::GetTimeline;
27use jacquard::api::com_atproto::server::create_session::CreateSession;
28use jacquard::client::{BasicClient, Session};
29use miette::IntoDiagnostic;
30
31#[derive(Parser, Debug)]
32#[command(author, version, about = "Jacquard - AT Protocol client demo")]
33struct Args {
34 /// Username/handle (e.g., alice.mosphere.at)
35 #[arg(short, long)]
36 username: CowStr<'static>,
37
38 /// PDS URL (e.g., https://bsky.social)
39 #[arg(long, default_value = "https://bsky.social")]
40 pds: CowStr<'static>,
41
42 /// App password
43 #[arg(short, long)]
44 password: CowStr<'static>,
45}
46
47#[tokio::main]
48async fn main() -> miette::Result<()> {
49 let args = Args::parse();
50
51 // Create HTTP client
52 let base = url::Url::parse(&args.pds).into_diagnostic()?;
53 let client = BasicClient::new(base);
54
55 // Create session
56 let session = Session::from(
57 client
58 .send(
59 CreateSession::new()
60 .identifier(args.username)
61 .password(args.password)
62 .build(),
63 )
64 .await?
65 .into_output()?,
66 );
67
68 println!("logged in as {} ({})", session.handle, session.did);
69 client.set_session(session).await.into_diagnostic()?;
70
71 // Fetch timeline
72 println!("\nfetching timeline...");
73 let timeline = client
74 .send(GetTimeline::new().limit(5).build())
75 .await?
76 .into_output()?;
77
78 println!("\ntimeline ({} posts):", timeline.feed.len());
79 for (i, post) in timeline.feed.iter().enumerate() {
80 println!("\n{}. by {}", i + 1, post.post.author.handle);
81 println!(
82 " {}",
83 serde_json::to_string_pretty(&post.post.record).into_diagnostic()?
84 );
85 }
86
87 Ok(())
88}
89```
90
91## Development
92
93This repo uses [Flakes](https://nixos.asia/en/flakes) from the get-go.
94
95```bash
96# Dev shell
97nix develop
98
99# or run via cargo
100nix develop -c cargo run
101
102# build
103nix build
104```
105
106There's also a [`justfile`](https://just.systems/) for Makefile-esque commands to be run inside of the devShell, and you can generally `cargo ...` or `just ...` whatever just fine if you don't want to use Nix and have the prerequisites installed.