'How do I implement this Python post request in Rust?

I have the following python script that uploads a image to imgurl:

headers = {"Authorization": "Client-ID "+client_id}
data = {
    "key": client_secret,
    "image": base64.b64encode(file),
    "type": "base64",
}
r = requests.post("https://api.imgur.com/3/upload.json",headers=headers,data=data)
if json.loads(r.content)["status"] == 200:
    link = json.loads(r.content)["data"]["link"]
    print(link)

I am trying to remake that on rust, this is how far i came:

use curl::easy::{Easy,List};

fn main() {
    let mut list = List::new();
    list.append("Authorization  Client-ID MYCLIENTID").unwrap();
    let mut easy = Easy::new();
    easy.url("https://api.imgur.com/3/upload.json").unwrap();
    easy.http_headers(list).unwrap();
    easy.post(true).unwrap();
    easy.write_function(|data| {
        stdout().write_all(data).unwrap();
        Ok(data.len())
    }).unwrap();
    easy.perform().unwrap();
}

I have no idea how to make the data part of the python script on rust.
I tried using reqwest but i found no working examples on post requests with multipart/form-data.



Solution 1:[1]

Easy Curl

You can use read_function

use data_encoding::BASE64;
use std::collections::HashMap;

fn main() {
    let mut data = HashMap::new();
    data.insert("key", client_secret);
    data.insert("image", BASE64.encode(file));
    data.insert("type", "base64");
    let post_data = format!("{:?}", data);

    let mut list = List::new();
    list.append("Authorization  Client-ID MYCLIENTID").unwrap();
    let mut easy = Easy::new();
    easy.url("https://api.imgur.com/3/upload.json").unwrap();
    easy.http_headers(list).unwrap();
    easy.post(true).unwrap();
    easy.read_function(|into| {
        Ok(post_data.as_bytes().read(into).unwrap())
    });
    easy.write_function(|data| {
        stdout().write_all(data).unwrap();
        Ok(data.len())
    }).unwrap();
    easy.perform().unwrap();
}

Or post_fields_copy

use data_encoding::BASE64;
use std::collections::HashMap;

fn main() {
    let mut data = HashMap::new();
    data.insert("key", client_secret);
    data.insert("image", BASE64.encode(file));
    data.insert("type", "base64");
    let post_data = format!("{:?}", data);

    let mut list = List::new();
    list.append("Authorization  Client-ID MYCLIENTID").unwrap();
    let mut easy = Easy::new();
    easy.url("https://api.imgur.com/3/upload.json").unwrap();
    easy.http_headers(list).unwrap();
    easy.post(true).unwrap();
    easy.post_fields_copy(post_data.as_bytes());
    easy.write_function(|data| {
        stdout().write_all(data).unwrap();
        Ok(data.len())
    }).unwrap();
    easy.perform().unwrap();
}

Reqwest

use reqwest::header::HeaderName;

fn main() {
    let mut data = HashMap::new();
    data.insert("key", client_secret);
    data.insert("image", BASE64.encode(file));
    data.insert("type", "base64");

    let mut headers = reqwest::header::HeaderMap::new();
    let name: HeaderName = "Authorization".parse().unwrap();
    headers.insert(name, "Client-ID MYCLIENTID".parse().unwrap());
    let client = reqwest::blocking::Client::new();
    let res = client.post("https://api.imgur.com/3/upload.json")
        .headers(headers)
        .json(&data)
        .send();
}

Solution 2:[2]

I try to use curl and reqwest to complete, you can refer to curl's test case

use std::io::{stdout, Write};
use curl::easy::{Easy, Form, List};

fn main() {

    let mut list = List::new();
    list.append("Authorization:  Client-ID MYCLIENTID").unwrap();

    let mut easy = Easy::new();
    easy.url("http://127.0.0.1:8000/").unwrap();
    easy.http_headers(list).unwrap();

    let mut form = Form::new();
    form.part("key").contents("key".as_bytes()).add();
    form.part("image").contents("image".as_bytes()).add();
    form.part("type").contents("type".as_bytes()).add();

    easy.write_function(|data| {
        stdout().write_all(data).unwrap();
        Ok(data.len())
    }).unwrap();

    easy.httppost(form);
    easy.perform().unwrap();
}
Path: /
Headers:
Host: 127.0.0.1:8000
Accept: */*
Authorization: Client-ID MYCLIENTID
Content-Length: 337
Content-Type: multipart/form-data; boundary=------------------------7f3cd45715114afd



Body:
--------------------------7f3cd45715114afd
Content-Disposition: form-data; name="key"

key
--------------------------7f3cd45715114afd
Content-Disposition: form-data; name="image"

image
--------------------------7f3cd45715114afd
Content-Disposition: form-data; name="type"

type
--------------------------7f3cd45715114afd--


127.0.0.1 - - [19/Mar/2022 01:48:29] "POST / HTTP/1.1" 200 -

add reqewst implementation

reqwest = { version = "0.11.10", features = ['multipart', "blocking"] }

use reqwest::blocking::multipart;
use reqwest::header::HeaderName;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let form = multipart::Form::new()
        .text("key", "key")
        .text("type", "type");

    let mut headers = reqwest::header::HeaderMap::new();
    let name: HeaderName = "Authorization".parse().unwrap();
    headers.insert(name, "Client-ID MYCLIENTID".parse().unwrap());
    let client = reqwest::blocking::Client::new();
    let res = client.post("http://127.0.0.1:8000/")
        .headers(headers)
        .multipart(form)
        .send()?;
    Ok(())
}
Path: /
Headers:
authorization: Client-ID MYCLIENTID
content-type: multipart/form-data; boundary=333d5f9f981ff8c4-52968a2548643dba-06b19c9eb1896219-083c4cc6b1618966
content-length: 319
accept: */*
host: 127.0.0.1:8000



Body:
--333d5f9f981ff8c4-52968a2548643dba-06b19c9eb1896219-083c4cc6b1618966
Content-Disposition: form-data; name="key"

key
--333d5f9f981ff8c4-52968a2548643dba-06b19c9eb1896219-083c4cc6b1618966
Content-Disposition: form-data; name="type"

type
--333d5f9f981ff8c4-52968a2548643dba-06b19c9eb1896219-083c4cc6b1618966--


127.0.0.1 - - [19/Mar/2022 02:27:40] "POST / HTTP/1.1" 200 -

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Chandan
Solution 2