#reddit #api-wrapper #api #wrapper #api-client #client

mr_splashy_pants

Very incomplete Rust bindings for the Reddit API

40 releases

0.1.39 Dec 17, 2021
0.1.38 Apr 22, 2021
0.1.35 Feb 27, 2021
0.1.33 Nov 16, 2020
0.1.15 Aug 29, 2020

#9 in #reddit

Download history 98/week @ 2024-02-22 42/week @ 2024-02-29

140 downloads per month

MIT/Apache

300KB
7K SLoC

Rust Documentation Crate

What is this?

WIP Rust bindings for the Reddit API

This is a WIP, you likely won't find it particularly useful

Set up

There are some hand rolled getting started instructions here: https://github.com/tobymurray/mr_splashy_pants/blob/master/getting-started/getting-started.md. You can use https://tobymurray.github.io/reddit-auth-generator/ to help generate an auth string.

Alternatively, you can follow https://github.com/reddit-archive/reddit/wiki/OAuth2 for more complete set up instructions.

Use

Set up a script with access to a Reddit account, collect the access token, the client ID, and the client secret. Once you have that, get a refresh token and an access token. Once you have that you can do:

let pants = Pants::new(
    USER_AGENT,
    "<access-token>",
    "<refresh_token>",
    "<client-id>",
    "<client-secret>",
);

For example, if you're using dotenv and reading values from the environment:

let pants = Pants::new(
    USER_AGENT,
    env::var("ACCESS_TOKEN").unwrap(),
    &env::var("REFRESH_TOKEN").unwrap(),
    &env::var("CLIENT_ID").unwrap(),
    &env::var("CLIENT_SECRET").unwrap(),
);

Then you can invoke things, e.g:

pants.me()

If your access token expires, it should automatically refresh.

Currently implemented with (partially) structured response:

Account:

Currently kind of implemented (no query parameters), with JSON response:

Account:

Listing

Links and Comments

  • POST /api/submit
    • Crossposting is also implemented (same API, different request body)
  • POST /api/del

Moderation

Users

To submit a post to Reddit:

// Build the submission 
let request_body = links_and_comments::ApiSubmit {
    ad: "".to_string(),
    api_type: "".to_string(),
    app: "".to_string(),
    collection_id: "".to_string(),
    event_end: "".to_string(),
    event_start: "".to_string(),
    event_tz: "".to_string(),
    extension: "".to_string(),
    flair_id: "".to_string(),
    flair_text: "".to_string(),
    g_recaptcha_response: "".to_string(),
    kind: "self".to_string(),
    nsfw: "".to_string(),
    resubmit: "".to_string(),
    richtext_json: "".to_string(),
    sendreplies: "".to_string(),
    spoiler: "".to_string(),
    sr: "name_of_subreddit".to_string(),
    text: "Here's an example of the post's body".to_string(),
    title: "This is the title of the post".to_string(),
    uh: "".to_string(),
    url: "".to_string(),
    video_poster_url: "".to_string(),
};


// then submit the post
let submission_name = pants.submit(request_body).await {
    Ok(response) => {
        println!("Response to submit is: {}", serde_json::to_string_pretty(&response).unwrap());
        response.json.data.name
    },
    Err(e) => panic!("An error ocurred: {}", e),
};

// remove it if you'd like
let delete_request_body = links_and_comments::ApiDel { id: submission_name };

pants.del(delete_request_body).await;

Streaming support for:

Disclaimer: This implementation of streaming is not compatible with very high traffic subreddits. If more than 25 posts are submitted within any 30 second period, this streaming method will miss some.

use futures_util::pin_mut;
use futures_util::stream::StreamExt;
...
let stream = pants.subreddit("testingground4bots").stream_new();
pin_mut!(stream);

while let Some(value) = tokio_test::block_on(stream.next()) {
    match value {
        Ok(data) => {
            println!("New post: {}", data);
        }
        Err(e) => {
            // Note, this can get noisy if the failure persists
            println!("Encountered an error: {}", e);
        }
    }
}

All other APIs are not implemented

Logging

Should things go sideways, the response bodies are logged at a trace log level. For example, using fern:

fern::Dispatch::new()
    .format(|out, message, record| {
        out.finish(format_args!(
            "{}[{}][{}] {}",
            chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
            record.target(),
            record.level(),
            message
        ))
    })
    .level(log::LevelFilter::Trace) // This has to be trace level
    .chain(std::io::stdout())
    .chain(fern::log_file("output.log")?)
    .apply()?;

Path to version 1.0

As it stands, I'm making arbitrary changes to the library to support whatever I happen to be working on at the time. Additionally, I'm new to Rust, so I generally don't have a good sense of what I'm doing. To that end, this library's interface should be considered unstable and often not good. Until 1.0, it's entirely possible that every new release will introduce breaking changes. I'm not clear on where I want to end up with this library - should it be a "low level" API wrapper that just provides types to the Reddit API? Should it try and provide some usability improvement over the raw API? Should it focus on streamlining the most common use cases for bots to interact with Reddit?

Until I have some clarity myself around these questions, this library should be expected to change dramatically.

Dependencies

~6–21MB
~309K SLoC