http-rs / surf

Fast and friendly HTTP client framework for async Rust
https://docs.rs/surf
Apache License 2.0
1.45k stars 119 forks source link

How to post multipart form data inside a body form? #221

Closed Siilwyn closed 3 years ago

Siilwyn commented 3 years ago

Trying to figure out how to post a new profile picture to the Slack API, doing the equivalent of this curl command: curl -X POST -F 'token=mytokenstring' -F 'image=@/home/siilwyn/avatar.png' https://slack.com/api/users.setPhoto.

This is what I've got so far, but returns Error: Custom("unsupported value"):

use async_std::task;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct Body {
    token: String,
    image: std::vec::Vec<u8>
}

fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
    task::block_on(async {
        let mut reader = surf::get("https://avatar.tobi.sh/").await?;
        let res = surf::post("https://slack.com/api/users.setPhoto")
            .body_form(&Body {
                token: "mytoken".to_string(),
                image: reader.body_bytes().await?
            })?
            .await?;
        dbg!(res);
        Ok(())
    })
}

Perhaps I should use surf::get.body_file instead of converting the body to a vector? Any help is much appreciated.

goto-bus-stop commented 3 years ago

Uploading files as part of a form typically requires the request to use the multipart/form-data MIME type and format, which Surf cannot currently generate. There are a couple of form data libraries out there though I can't specifically recommend any of them (not because they are bad but because I don't know). It would be nice to integrate multipart/form-data requests in the future.

Siilwyn commented 3 years ago

Ah okay, that's a bummer. Thanks for your quick answer though!