HttpClient

Struct HttpClient 

Source
pub struct HttpClient { /* private fields */ }

Implementations§

Source§

impl HttpClient

Source

pub fn new() -> Self

Examples found in repository?
examples/coingecko_oracle.rs (line 22)
13fn main() {
14    // read coin id from stdin
15    let mut buf = [0; 1024];
16    let len = read_stdin(&mut buf).unwrap();
17    let coin_id = std::str::from_utf8(&buf[..len as usize])
18        .unwrap_or_default()
19        .trim();
20
21    // perform http request
22    let client = HttpClient::new();
23    let url = format!(
24        "https://api.coingecko.com/api/v3/simple/price?ids={}&vs_currencies=usd",
25        coin_id
26    );
27    let response = client.get(&url).send().unwrap();
28    let body = response.bytes().to_vec(); // e.g. {"bitcoin":{"usd":67675}}
29
30    // println!("{}", String::from_utf8(body.clone()).unwrap());
31
32    // parse the json response; extrac usd price
33    let json: serde_json::Result<HashMap<String, HashMap<String, f64>>> =
34        serde_json::from_slice(&body);
35    let Ok(data) = json else {
36        eprintln!("Failed to parse JSON");
37        return;
38    };
39    let Some(coin_data) = data.get(coin_id) else {
40        eprintln!("Coin not found in response.");
41        return;
42    };
43    let Some(usd_price) = coin_data.get("usd") else {
44        eprintln!("USD price not found for {}.", coin_id);
45        return;
46    };
47
48    let coin_price = CoinPrice {
49        id: coin_id.to_string(),
50        price: (*usd_price * 1_000_000.0) as u64, // price in 6 decimals
51        currency: "usd".to_string(),
52    };
53    println!("{}", json!(coin_price));
54}
Source

pub fn builder() -> HttpClientBuilder

Examples found in repository?
examples/http_client.rs (line 40)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    println!("====================================");
6    println!("HTTP v2 Client Demo");
7    println!("====================================");
8
9    println!("\n1. GET request:");
10    match get("https://httpbin.org/get").send() {
11        Ok(response) => {
12            println!("GET Status: {}", response.status());
13            println!("GET Success: {}", response.is_success());
14        }
15        Err(e) => println!("GET Error: {}", e),
16    }
17
18    println!("\n2. POST with JSON:");
19    let json_data = serde_json::json!({
20        "name": "Blockless SDK",
21        "version": "2.0",
22        "api_style": "reqwest-like"
23    });
24    match post("https://httpbin.org/post").json(&json_data)?.send() {
25        Ok(response) => {
26            println!("POST JSON Status: {}", response.status());
27            if let Ok(response_json) = response.json::<serde_json::Value>() {
28                if let Some(received_json) = response_json.get("json") {
29                    println!("Received JSON: {}", received_json);
30                }
31            }
32        }
33        Err(e) => println!("POST JSON Error: {}", e),
34    }
35
36    println!("\n3. Client instance with default configuration:");
37    let mut default_headers = HashMap::new();
38    default_headers.insert("User-Agent".to_string(), "Blockless-SDK/2.0".to_string());
39    default_headers.insert("Accept".to_string(), "application/json".to_string());
40    let client = HttpClient::builder()
41        .default_headers(default_headers)
42        .timeout(10000)
43        .build();
44    match client
45        .get("https://httpbin.org/get")
46        .query("search", "blockless")
47        .query("limit", "10")
48        .query("format", "json")
49        .send()
50    {
51        Ok(response) => {
52            println!("Client GET Status: {}", response.status());
53            if let Ok(json_data) = response.json::<serde_json::Value>() {
54                if let Some(args) = json_data.get("args") {
55                    println!("Query params: {}", args);
56                }
57            }
58        }
59        Err(e) => println!("Client GET Error: {}", e),
60    }
61
62    println!("\n4. Authentication examples:");
63    match client
64        .get("https://httpbin.org/basic-auth/user/pass")
65        .basic_auth("user", "pass")
66        .send()
67    {
68        Ok(response) => {
69            println!("Basic auth status: {}", response.status());
70            if let Ok(json_data) = response.json::<serde_json::Value>() {
71                println!("Authenticated: {:?}", json_data.get("authenticated"));
72            }
73        }
74        Err(e) => println!("Basic auth error: {}", e),
75    }
76
77    match client
78        .get("https://httpbin.org/bearer")
79        .bearer_auth("test-token-12345")
80        .send()
81    {
82        Ok(response) => {
83            println!("Bearer auth status: {}", response.status());
84            if let Ok(json_data) = response.json::<serde_json::Value>() {
85                println!("Token received: {:?}", json_data.get("token"));
86            }
87        }
88        Err(e) => println!("Bearer auth error: {}", e),
89    }
90
91    println!("\n5. Different request body types:");
92    let mut form_data = HashMap::new();
93    form_data.insert("name".to_string(), "Blockless".to_string());
94    form_data.insert("type".to_string(), "distributed computing".to_string());
95    match client
96        .post("https://httpbin.org/post")
97        .form(form_data)
98        .send()
99    {
100        Ok(response) => {
101            println!("Form POST Status: {}", response.status());
102            if let Ok(json_data) = response.json::<serde_json::Value>() {
103                if let Some(form) = json_data.get("form") {
104                    println!("Form data received: {}", form);
105                }
106            }
107        }
108        Err(e) => println!("Form POST Error: {}", e),
109    }
110
111    println!("\n6. Multipart form with file upload:");
112    let multipart_fields = vec![
113        MultipartField::text("description", "SDK test file"),
114        MultipartField::file(
115            "upload",
116            b"Hello from Blockless SDK v2!".to_vec(),
117            "hello.txt",
118            Some("text/plain".to_string()),
119        ),
120    ];
121    match client
122        .post("https://httpbin.org/post")
123        .multipart(multipart_fields)
124        .send()
125    {
126        Ok(response) => {
127            println!("Multipart POST Status: {}", response.status());
128            if let Ok(json_data) = response.json::<serde_json::Value>() {
129                if let Some(files) = json_data.get("files") {
130                    println!("Files uploaded: {}", files);
131                }
132            }
133        }
134        Err(e) => println!("Multipart POST Error: {}", e),
135    }
136
137    println!("\n7. Binary data:");
138    let binary_data = vec![0x48, 0x65, 0x6c, 0x6c, 0x6f]; // "Hello" in bytes
139    match client
140        .post("https://httpbin.org/post")
141        .header("Content-Type", "application/octet-stream")
142        .body_bytes(binary_data)
143        .send()
144    {
145        Ok(response) => {
146            println!("Binary POST Status: {}", response.status());
147        }
148        Err(e) => println!("Binary POST Error: {}", e),
149    }
150
151    println!("\n8. Advanced request building:");
152    match client
153        .put("https://httpbin.org/put")
154        .header("X-Custom-Header", "custom-value")
155        .header("X-API-Version", "2.0")
156        .query("action", "update")
157        .query("id", "12345")
158        .timeout(5000)
159        .body("Updated data")
160        .send()
161    {
162        Ok(response) => {
163            println!("PUT Status: {}", response.status());
164            if let Ok(json_data) = response.json::<serde_json::Value>() {
165                if let Some(headers) = json_data.get("headers") {
166                    println!("Custom headers received: {}", headers);
167                }
168            }
169        }
170        Err(e) => println!("PUT Error: {}", e),
171    }
172
173    println!("\nDemo completed 🚀");
174    Ok(())
175}
More examples
Hide additional examples
examples/ipfs_api.rs (line 14)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("IPFS RPC API Demo - HTTP v2 Client");
5    println!("=================================");
6    println!("Make sure your IPFS node is running on localhost:5001");
7    println!("Docker command: docker run --rm -it --name ipfs_host -p 4001:4001 -p 4001:4001/udp -p 8080:8080 -p 5001:5001 ipfs/kubo");
8    println!("Note: If you get CORS errors, configure CORS with:");
9    println!("  docker exec ipfs_host ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '[\"*\"]'");
10    println!("  docker exec ipfs_host ipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods '[\"GET\", \"POST\", \"PUT\", \"DELETE\", \"OPTIONS\"]'");
11    println!("  docker restart ipfs_host\n");
12
13    // Create HTTP client configured for IPFS RPC API
14    let client = HttpClient::builder()
15        .timeout(30000) // 30 seconds for file operations
16        .build();
17
18    let ipfs_api_base = "http://localhost:5001/api/v0";
19
20    // Example 1: Simple POST request - Get node version
21    println!("1. GET node version (POST with no body):");
22    match client.post(format!("{}/version", ipfs_api_base)).send() {
23        Ok(response) => {
24            println!("   Status: {}", response.status());
25            if response.is_success() {
26                if let Ok(version_info) = response.json::<serde_json::Value>() {
27                    println!(
28                        "   IPFS Version: {}",
29                        version_info
30                            .get("Version")
31                            .and_then(|v| v.as_str())
32                            .unwrap_or("unknown")
33                    );
34                    println!(
35                        "   Commit: {}",
36                        version_info
37                            .get("Commit")
38                            .and_then(|c| c.as_str())
39                            .unwrap_or("unknown")
40                    );
41                }
42            }
43        }
44        Err(e) => println!("   Error: {} (Is IPFS running?)", e),
45    }
46
47    // Example 2: POST with query parameters - Get node ID
48    println!("\n2. GET node ID (POST with query parameters):");
49    match client
50        .post(format!("{}/id", ipfs_api_base))
51        .query("format", "json")
52        .send()
53    {
54        Ok(response) => {
55            println!("   Status: {}", response.status());
56            if response.is_success() {
57                if let Ok(id_info) = response.json::<serde_json::Value>() {
58                    println!(
59                        "   Node ID: {}",
60                        id_info
61                            .get("ID")
62                            .and_then(|id| id.as_str())
63                            .unwrap_or("unknown")
64                    );
65                    if let Some(addresses) = id_info.get("Addresses") {
66                        if let Some(addr_array) = addresses.as_array() {
67                            if !addr_array.is_empty() {
68                                println!("   First Address: {}", addr_array[0]);
69                            }
70                        }
71                    }
72                }
73            }
74        }
75        Err(e) => println!("   Error: {}", e),
76    }
77
78    // Example 3: POST with multipart file upload - Add file to IPFS
79    println!("\n3. ADD file to IPFS (POST with multipart upload):");
80    let file_content = b"Hello from Blockless SDK HTTP v2 client!\nThis file was uploaded to IPFS using multipart form data.";
81    let multipart_fields = vec![MultipartField::file(
82        "file", // IPFS expects 'file' as the field name
83        file_content.to_vec(),
84        "hello-blockless.txt",
85        Some("text/plain".to_string()),
86    )];
87
88    match client
89        .post(format!("{}/add", ipfs_api_base))
90        .query("pin", "true") // Pin the file after adding
91        .multipart(multipart_fields)
92        .send()
93    {
94        Ok(response) => {
95            println!("   Status: {}", response.status());
96            if response.is_success() {
97                if let Ok(add_result) = response.json::<serde_json::Value>() {
98                    let hash = add_result
99                        .get("Hash")
100                        .and_then(|h| h.as_str())
101                        .unwrap_or("unknown");
102                    let name = add_result
103                        .get("Name")
104                        .and_then(|n| n.as_str())
105                        .unwrap_or("unknown");
106                    let size = add_result
107                        .get("Size")
108                        .and_then(|s| s.as_str())
109                        .unwrap_or("0");
110                    println!("   Added file: {}", name);
111                    println!("   IPFS Hash: {}", hash);
112                    println!("   Size: {} bytes", size);
113
114                    // Store hash for later examples
115                    if hash != "unknown" {
116                        demonstrate_file_operations(&client, ipfs_api_base, hash)?;
117                    }
118                }
119            }
120        }
121        Err(e) => println!("   Error: {}", e),
122    }
123
124    // Example 4: Repository stats (POST with query parameters)
125    println!("\n4. GET repository statistics (POST with boolean parameters):");
126    match client
127        .post(format!("{}/repo/stat", ipfs_api_base))
128        .query("human", "true")
129        .send()
130    {
131        Ok(response) => {
132            println!("   Status: {}", response.status());
133            if response.is_success() {
134                if let Ok(repo_stats) = response.json::<serde_json::Value>() {
135                    println!(
136                        "   Repo Size: {}",
137                        repo_stats
138                            .get("RepoSize")
139                            .unwrap_or(&serde_json::Value::Number(0.into()))
140                    );
141                    println!(
142                        "   Storage Max: {}",
143                        repo_stats
144                            .get("StorageMax")
145                            .unwrap_or(&serde_json::Value::Number(0.into()))
146                    );
147                    println!(
148                        "   Num Objects: {}",
149                        repo_stats
150                            .get("NumObjects")
151                            .unwrap_or(&serde_json::Value::Number(0.into()))
152                    );
153                }
154            }
155        }
156        Err(e) => println!("   Error: {}", e),
157    }
158
159    // Example 5: Pin operations - List pinned objects
160    println!("\n5. LIST pinned objects (POST with type filter):");
161    match client
162        .post(format!("{}/pin/ls", ipfs_api_base))
163        .query("type", "recursive")
164        .query("stream", "true")
165        .send()
166    {
167        Ok(response) => {
168            println!("   Status: {}", response.status());
169            if response.is_success() {
170                if let Ok(pin_list) = response.json::<serde_json::Value>() {
171                    if let Some(keys) = pin_list.get("Keys").and_then(|k| k.as_object()) {
172                        println!("   Pinned objects count: {}", keys.len());
173                        // Show first few pinned objects
174                        for (hash, info) in keys.iter().take(3) {
175                            if let Some(pin_type) = info.get("Type") {
176                                println!("   - {} ({})", hash, pin_type);
177                            }
178                        }
179                        if keys.len() > 3 {
180                            println!("   ... and {} more", keys.len() - 3);
181                        }
182                    }
183                }
184            }
185        }
186        Err(e) => println!("   Error: {}", e),
187    }
188
189    // Example 6: Module-level convenience function
190    println!("\n6. GET swarm peers (using module-level function):");
191    match post(format!("{}/swarm/peers", ipfs_api_base))
192        .query("verbose", "false")
193        .send()
194    {
195        Ok(response) => {
196            println!("   Status: {}", response.status());
197            if response.is_success() {
198                if let Ok(peers_info) = response.json::<serde_json::Value>() {
199                    if let Some(peers) = peers_info.get("Peers").and_then(|p| p.as_array()) {
200                        println!("   Connected peers: {}", peers.len());
201                        // Show first few peers
202                        for peer in peers.iter().take(2) {
203                            if let Some(peer_id) = peer.get("Peer") {
204                                if let Some(addr) = peer.get("Addr") {
205                                    println!(
206                                        "   - Peer: {}...{}",
207                                        &peer_id.as_str().unwrap_or("")[..8],
208                                        &peer_id.as_str().unwrap_or("")[peer_id
209                                            .as_str()
210                                            .unwrap_or("")
211                                            .len()
212                                            .saturating_sub(8)..]
213                                    );
214                                    println!("     Address: {}", addr);
215                                }
216                            }
217                        }
218                        if peers.len() > 2 {
219                            println!("   ... and {} more peers", peers.len() - 2);
220                        }
221                    }
222                }
223            }
224        }
225        Err(e) => println!("   Error: {}", e),
226    }
227
228    println!("\n✅ IPFS API Demo completed!");
229    println!("This example demonstrated:");
230    println!("  • POST requests with no body (version, id)");
231    println!("  • POST with query parameters (repo/stat, pin/ls)");
232    println!("  • POST with multipart file upload (add)");
233    println!("  • POST with binary responses (cat - in demonstrate_file_operations)");
234    println!("  • Module-level convenience functions (swarm/peers)");
235    println!("  • Different response types (JSON, binary)");
236
237    Ok(())
238}
Source

pub fn get<U: Into<String>>(&self, url: U) -> RequestBuilder

Examples found in repository?
examples/coingecko_oracle.rs (line 27)
13fn main() {
14    // read coin id from stdin
15    let mut buf = [0; 1024];
16    let len = read_stdin(&mut buf).unwrap();
17    let coin_id = std::str::from_utf8(&buf[..len as usize])
18        .unwrap_or_default()
19        .trim();
20
21    // perform http request
22    let client = HttpClient::new();
23    let url = format!(
24        "https://api.coingecko.com/api/v3/simple/price?ids={}&vs_currencies=usd",
25        coin_id
26    );
27    let response = client.get(&url).send().unwrap();
28    let body = response.bytes().to_vec(); // e.g. {"bitcoin":{"usd":67675}}
29
30    // println!("{}", String::from_utf8(body.clone()).unwrap());
31
32    // parse the json response; extrac usd price
33    let json: serde_json::Result<HashMap<String, HashMap<String, f64>>> =
34        serde_json::from_slice(&body);
35    let Ok(data) = json else {
36        eprintln!("Failed to parse JSON");
37        return;
38    };
39    let Some(coin_data) = data.get(coin_id) else {
40        eprintln!("Coin not found in response.");
41        return;
42    };
43    let Some(usd_price) = coin_data.get("usd") else {
44        eprintln!("USD price not found for {}.", coin_id);
45        return;
46    };
47
48    let coin_price = CoinPrice {
49        id: coin_id.to_string(),
50        price: (*usd_price * 1_000_000.0) as u64, // price in 6 decimals
51        currency: "usd".to_string(),
52    };
53    println!("{}", json!(coin_price));
54}
More examples
Hide additional examples
examples/http_client.rs (line 45)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    println!("====================================");
6    println!("HTTP v2 Client Demo");
7    println!("====================================");
8
9    println!("\n1. GET request:");
10    match get("https://httpbin.org/get").send() {
11        Ok(response) => {
12            println!("GET Status: {}", response.status());
13            println!("GET Success: {}", response.is_success());
14        }
15        Err(e) => println!("GET Error: {}", e),
16    }
17
18    println!("\n2. POST with JSON:");
19    let json_data = serde_json::json!({
20        "name": "Blockless SDK",
21        "version": "2.0",
22        "api_style": "reqwest-like"
23    });
24    match post("https://httpbin.org/post").json(&json_data)?.send() {
25        Ok(response) => {
26            println!("POST JSON Status: {}", response.status());
27            if let Ok(response_json) = response.json::<serde_json::Value>() {
28                if let Some(received_json) = response_json.get("json") {
29                    println!("Received JSON: {}", received_json);
30                }
31            }
32        }
33        Err(e) => println!("POST JSON Error: {}", e),
34    }
35
36    println!("\n3. Client instance with default configuration:");
37    let mut default_headers = HashMap::new();
38    default_headers.insert("User-Agent".to_string(), "Blockless-SDK/2.0".to_string());
39    default_headers.insert("Accept".to_string(), "application/json".to_string());
40    let client = HttpClient::builder()
41        .default_headers(default_headers)
42        .timeout(10000)
43        .build();
44    match client
45        .get("https://httpbin.org/get")
46        .query("search", "blockless")
47        .query("limit", "10")
48        .query("format", "json")
49        .send()
50    {
51        Ok(response) => {
52            println!("Client GET Status: {}", response.status());
53            if let Ok(json_data) = response.json::<serde_json::Value>() {
54                if let Some(args) = json_data.get("args") {
55                    println!("Query params: {}", args);
56                }
57            }
58        }
59        Err(e) => println!("Client GET Error: {}", e),
60    }
61
62    println!("\n4. Authentication examples:");
63    match client
64        .get("https://httpbin.org/basic-auth/user/pass")
65        .basic_auth("user", "pass")
66        .send()
67    {
68        Ok(response) => {
69            println!("Basic auth status: {}", response.status());
70            if let Ok(json_data) = response.json::<serde_json::Value>() {
71                println!("Authenticated: {:?}", json_data.get("authenticated"));
72            }
73        }
74        Err(e) => println!("Basic auth error: {}", e),
75    }
76
77    match client
78        .get("https://httpbin.org/bearer")
79        .bearer_auth("test-token-12345")
80        .send()
81    {
82        Ok(response) => {
83            println!("Bearer auth status: {}", response.status());
84            if let Ok(json_data) = response.json::<serde_json::Value>() {
85                println!("Token received: {:?}", json_data.get("token"));
86            }
87        }
88        Err(e) => println!("Bearer auth error: {}", e),
89    }
90
91    println!("\n5. Different request body types:");
92    let mut form_data = HashMap::new();
93    form_data.insert("name".to_string(), "Blockless".to_string());
94    form_data.insert("type".to_string(), "distributed computing".to_string());
95    match client
96        .post("https://httpbin.org/post")
97        .form(form_data)
98        .send()
99    {
100        Ok(response) => {
101            println!("Form POST Status: {}", response.status());
102            if let Ok(json_data) = response.json::<serde_json::Value>() {
103                if let Some(form) = json_data.get("form") {
104                    println!("Form data received: {}", form);
105                }
106            }
107        }
108        Err(e) => println!("Form POST Error: {}", e),
109    }
110
111    println!("\n6. Multipart form with file upload:");
112    let multipart_fields = vec![
113        MultipartField::text("description", "SDK test file"),
114        MultipartField::file(
115            "upload",
116            b"Hello from Blockless SDK v2!".to_vec(),
117            "hello.txt",
118            Some("text/plain".to_string()),
119        ),
120    ];
121    match client
122        .post("https://httpbin.org/post")
123        .multipart(multipart_fields)
124        .send()
125    {
126        Ok(response) => {
127            println!("Multipart POST Status: {}", response.status());
128            if let Ok(json_data) = response.json::<serde_json::Value>() {
129                if let Some(files) = json_data.get("files") {
130                    println!("Files uploaded: {}", files);
131                }
132            }
133        }
134        Err(e) => println!("Multipart POST Error: {}", e),
135    }
136
137    println!("\n7. Binary data:");
138    let binary_data = vec![0x48, 0x65, 0x6c, 0x6c, 0x6f]; // "Hello" in bytes
139    match client
140        .post("https://httpbin.org/post")
141        .header("Content-Type", "application/octet-stream")
142        .body_bytes(binary_data)
143        .send()
144    {
145        Ok(response) => {
146            println!("Binary POST Status: {}", response.status());
147        }
148        Err(e) => println!("Binary POST Error: {}", e),
149    }
150
151    println!("\n8. Advanced request building:");
152    match client
153        .put("https://httpbin.org/put")
154        .header("X-Custom-Header", "custom-value")
155        .header("X-API-Version", "2.0")
156        .query("action", "update")
157        .query("id", "12345")
158        .timeout(5000)
159        .body("Updated data")
160        .send()
161    {
162        Ok(response) => {
163            println!("PUT Status: {}", response.status());
164            if let Ok(json_data) = response.json::<serde_json::Value>() {
165                if let Some(headers) = json_data.get("headers") {
166                    println!("Custom headers received: {}", headers);
167                }
168            }
169        }
170        Err(e) => println!("PUT Error: {}", e),
171    }
172
173    println!("\nDemo completed 🚀");
174    Ok(())
175}
Source

pub fn post<U: Into<String>>(&self, url: U) -> RequestBuilder

Examples found in repository?
examples/http_client.rs (line 96)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    println!("====================================");
6    println!("HTTP v2 Client Demo");
7    println!("====================================");
8
9    println!("\n1. GET request:");
10    match get("https://httpbin.org/get").send() {
11        Ok(response) => {
12            println!("GET Status: {}", response.status());
13            println!("GET Success: {}", response.is_success());
14        }
15        Err(e) => println!("GET Error: {}", e),
16    }
17
18    println!("\n2. POST with JSON:");
19    let json_data = serde_json::json!({
20        "name": "Blockless SDK",
21        "version": "2.0",
22        "api_style": "reqwest-like"
23    });
24    match post("https://httpbin.org/post").json(&json_data)?.send() {
25        Ok(response) => {
26            println!("POST JSON Status: {}", response.status());
27            if let Ok(response_json) = response.json::<serde_json::Value>() {
28                if let Some(received_json) = response_json.get("json") {
29                    println!("Received JSON: {}", received_json);
30                }
31            }
32        }
33        Err(e) => println!("POST JSON Error: {}", e),
34    }
35
36    println!("\n3. Client instance with default configuration:");
37    let mut default_headers = HashMap::new();
38    default_headers.insert("User-Agent".to_string(), "Blockless-SDK/2.0".to_string());
39    default_headers.insert("Accept".to_string(), "application/json".to_string());
40    let client = HttpClient::builder()
41        .default_headers(default_headers)
42        .timeout(10000)
43        .build();
44    match client
45        .get("https://httpbin.org/get")
46        .query("search", "blockless")
47        .query("limit", "10")
48        .query("format", "json")
49        .send()
50    {
51        Ok(response) => {
52            println!("Client GET Status: {}", response.status());
53            if let Ok(json_data) = response.json::<serde_json::Value>() {
54                if let Some(args) = json_data.get("args") {
55                    println!("Query params: {}", args);
56                }
57            }
58        }
59        Err(e) => println!("Client GET Error: {}", e),
60    }
61
62    println!("\n4. Authentication examples:");
63    match client
64        .get("https://httpbin.org/basic-auth/user/pass")
65        .basic_auth("user", "pass")
66        .send()
67    {
68        Ok(response) => {
69            println!("Basic auth status: {}", response.status());
70            if let Ok(json_data) = response.json::<serde_json::Value>() {
71                println!("Authenticated: {:?}", json_data.get("authenticated"));
72            }
73        }
74        Err(e) => println!("Basic auth error: {}", e),
75    }
76
77    match client
78        .get("https://httpbin.org/bearer")
79        .bearer_auth("test-token-12345")
80        .send()
81    {
82        Ok(response) => {
83            println!("Bearer auth status: {}", response.status());
84            if let Ok(json_data) = response.json::<serde_json::Value>() {
85                println!("Token received: {:?}", json_data.get("token"));
86            }
87        }
88        Err(e) => println!("Bearer auth error: {}", e),
89    }
90
91    println!("\n5. Different request body types:");
92    let mut form_data = HashMap::new();
93    form_data.insert("name".to_string(), "Blockless".to_string());
94    form_data.insert("type".to_string(), "distributed computing".to_string());
95    match client
96        .post("https://httpbin.org/post")
97        .form(form_data)
98        .send()
99    {
100        Ok(response) => {
101            println!("Form POST Status: {}", response.status());
102            if let Ok(json_data) = response.json::<serde_json::Value>() {
103                if let Some(form) = json_data.get("form") {
104                    println!("Form data received: {}", form);
105                }
106            }
107        }
108        Err(e) => println!("Form POST Error: {}", e),
109    }
110
111    println!("\n6. Multipart form with file upload:");
112    let multipart_fields = vec![
113        MultipartField::text("description", "SDK test file"),
114        MultipartField::file(
115            "upload",
116            b"Hello from Blockless SDK v2!".to_vec(),
117            "hello.txt",
118            Some("text/plain".to_string()),
119        ),
120    ];
121    match client
122        .post("https://httpbin.org/post")
123        .multipart(multipart_fields)
124        .send()
125    {
126        Ok(response) => {
127            println!("Multipart POST Status: {}", response.status());
128            if let Ok(json_data) = response.json::<serde_json::Value>() {
129                if let Some(files) = json_data.get("files") {
130                    println!("Files uploaded: {}", files);
131                }
132            }
133        }
134        Err(e) => println!("Multipart POST Error: {}", e),
135    }
136
137    println!("\n7. Binary data:");
138    let binary_data = vec![0x48, 0x65, 0x6c, 0x6c, 0x6f]; // "Hello" in bytes
139    match client
140        .post("https://httpbin.org/post")
141        .header("Content-Type", "application/octet-stream")
142        .body_bytes(binary_data)
143        .send()
144    {
145        Ok(response) => {
146            println!("Binary POST Status: {}", response.status());
147        }
148        Err(e) => println!("Binary POST Error: {}", e),
149    }
150
151    println!("\n8. Advanced request building:");
152    match client
153        .put("https://httpbin.org/put")
154        .header("X-Custom-Header", "custom-value")
155        .header("X-API-Version", "2.0")
156        .query("action", "update")
157        .query("id", "12345")
158        .timeout(5000)
159        .body("Updated data")
160        .send()
161    {
162        Ok(response) => {
163            println!("PUT Status: {}", response.status());
164            if let Ok(json_data) = response.json::<serde_json::Value>() {
165                if let Some(headers) = json_data.get("headers") {
166                    println!("Custom headers received: {}", headers);
167                }
168            }
169        }
170        Err(e) => println!("PUT Error: {}", e),
171    }
172
173    println!("\nDemo completed 🚀");
174    Ok(())
175}
More examples
Hide additional examples
examples/ipfs_api.rs (line 22)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("IPFS RPC API Demo - HTTP v2 Client");
5    println!("=================================");
6    println!("Make sure your IPFS node is running on localhost:5001");
7    println!("Docker command: docker run --rm -it --name ipfs_host -p 4001:4001 -p 4001:4001/udp -p 8080:8080 -p 5001:5001 ipfs/kubo");
8    println!("Note: If you get CORS errors, configure CORS with:");
9    println!("  docker exec ipfs_host ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '[\"*\"]'");
10    println!("  docker exec ipfs_host ipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods '[\"GET\", \"POST\", \"PUT\", \"DELETE\", \"OPTIONS\"]'");
11    println!("  docker restart ipfs_host\n");
12
13    // Create HTTP client configured for IPFS RPC API
14    let client = HttpClient::builder()
15        .timeout(30000) // 30 seconds for file operations
16        .build();
17
18    let ipfs_api_base = "http://localhost:5001/api/v0";
19
20    // Example 1: Simple POST request - Get node version
21    println!("1. GET node version (POST with no body):");
22    match client.post(format!("{}/version", ipfs_api_base)).send() {
23        Ok(response) => {
24            println!("   Status: {}", response.status());
25            if response.is_success() {
26                if let Ok(version_info) = response.json::<serde_json::Value>() {
27                    println!(
28                        "   IPFS Version: {}",
29                        version_info
30                            .get("Version")
31                            .and_then(|v| v.as_str())
32                            .unwrap_or("unknown")
33                    );
34                    println!(
35                        "   Commit: {}",
36                        version_info
37                            .get("Commit")
38                            .and_then(|c| c.as_str())
39                            .unwrap_or("unknown")
40                    );
41                }
42            }
43        }
44        Err(e) => println!("   Error: {} (Is IPFS running?)", e),
45    }
46
47    // Example 2: POST with query parameters - Get node ID
48    println!("\n2. GET node ID (POST with query parameters):");
49    match client
50        .post(format!("{}/id", ipfs_api_base))
51        .query("format", "json")
52        .send()
53    {
54        Ok(response) => {
55            println!("   Status: {}", response.status());
56            if response.is_success() {
57                if let Ok(id_info) = response.json::<serde_json::Value>() {
58                    println!(
59                        "   Node ID: {}",
60                        id_info
61                            .get("ID")
62                            .and_then(|id| id.as_str())
63                            .unwrap_or("unknown")
64                    );
65                    if let Some(addresses) = id_info.get("Addresses") {
66                        if let Some(addr_array) = addresses.as_array() {
67                            if !addr_array.is_empty() {
68                                println!("   First Address: {}", addr_array[0]);
69                            }
70                        }
71                    }
72                }
73            }
74        }
75        Err(e) => println!("   Error: {}", e),
76    }
77
78    // Example 3: POST with multipart file upload - Add file to IPFS
79    println!("\n3. ADD file to IPFS (POST with multipart upload):");
80    let file_content = b"Hello from Blockless SDK HTTP v2 client!\nThis file was uploaded to IPFS using multipart form data.";
81    let multipart_fields = vec![MultipartField::file(
82        "file", // IPFS expects 'file' as the field name
83        file_content.to_vec(),
84        "hello-blockless.txt",
85        Some("text/plain".to_string()),
86    )];
87
88    match client
89        .post(format!("{}/add", ipfs_api_base))
90        .query("pin", "true") // Pin the file after adding
91        .multipart(multipart_fields)
92        .send()
93    {
94        Ok(response) => {
95            println!("   Status: {}", response.status());
96            if response.is_success() {
97                if let Ok(add_result) = response.json::<serde_json::Value>() {
98                    let hash = add_result
99                        .get("Hash")
100                        .and_then(|h| h.as_str())
101                        .unwrap_or("unknown");
102                    let name = add_result
103                        .get("Name")
104                        .and_then(|n| n.as_str())
105                        .unwrap_or("unknown");
106                    let size = add_result
107                        .get("Size")
108                        .and_then(|s| s.as_str())
109                        .unwrap_or("0");
110                    println!("   Added file: {}", name);
111                    println!("   IPFS Hash: {}", hash);
112                    println!("   Size: {} bytes", size);
113
114                    // Store hash for later examples
115                    if hash != "unknown" {
116                        demonstrate_file_operations(&client, ipfs_api_base, hash)?;
117                    }
118                }
119            }
120        }
121        Err(e) => println!("   Error: {}", e),
122    }
123
124    // Example 4: Repository stats (POST with query parameters)
125    println!("\n4. GET repository statistics (POST with boolean parameters):");
126    match client
127        .post(format!("{}/repo/stat", ipfs_api_base))
128        .query("human", "true")
129        .send()
130    {
131        Ok(response) => {
132            println!("   Status: {}", response.status());
133            if response.is_success() {
134                if let Ok(repo_stats) = response.json::<serde_json::Value>() {
135                    println!(
136                        "   Repo Size: {}",
137                        repo_stats
138                            .get("RepoSize")
139                            .unwrap_or(&serde_json::Value::Number(0.into()))
140                    );
141                    println!(
142                        "   Storage Max: {}",
143                        repo_stats
144                            .get("StorageMax")
145                            .unwrap_or(&serde_json::Value::Number(0.into()))
146                    );
147                    println!(
148                        "   Num Objects: {}",
149                        repo_stats
150                            .get("NumObjects")
151                            .unwrap_or(&serde_json::Value::Number(0.into()))
152                    );
153                }
154            }
155        }
156        Err(e) => println!("   Error: {}", e),
157    }
158
159    // Example 5: Pin operations - List pinned objects
160    println!("\n5. LIST pinned objects (POST with type filter):");
161    match client
162        .post(format!("{}/pin/ls", ipfs_api_base))
163        .query("type", "recursive")
164        .query("stream", "true")
165        .send()
166    {
167        Ok(response) => {
168            println!("   Status: {}", response.status());
169            if response.is_success() {
170                if let Ok(pin_list) = response.json::<serde_json::Value>() {
171                    if let Some(keys) = pin_list.get("Keys").and_then(|k| k.as_object()) {
172                        println!("   Pinned objects count: {}", keys.len());
173                        // Show first few pinned objects
174                        for (hash, info) in keys.iter().take(3) {
175                            if let Some(pin_type) = info.get("Type") {
176                                println!("   - {} ({})", hash, pin_type);
177                            }
178                        }
179                        if keys.len() > 3 {
180                            println!("   ... and {} more", keys.len() - 3);
181                        }
182                    }
183                }
184            }
185        }
186        Err(e) => println!("   Error: {}", e),
187    }
188
189    // Example 6: Module-level convenience function
190    println!("\n6. GET swarm peers (using module-level function):");
191    match post(format!("{}/swarm/peers", ipfs_api_base))
192        .query("verbose", "false")
193        .send()
194    {
195        Ok(response) => {
196            println!("   Status: {}", response.status());
197            if response.is_success() {
198                if let Ok(peers_info) = response.json::<serde_json::Value>() {
199                    if let Some(peers) = peers_info.get("Peers").and_then(|p| p.as_array()) {
200                        println!("   Connected peers: {}", peers.len());
201                        // Show first few peers
202                        for peer in peers.iter().take(2) {
203                            if let Some(peer_id) = peer.get("Peer") {
204                                if let Some(addr) = peer.get("Addr") {
205                                    println!(
206                                        "   - Peer: {}...{}",
207                                        &peer_id.as_str().unwrap_or("")[..8],
208                                        &peer_id.as_str().unwrap_or("")[peer_id
209                                            .as_str()
210                                            .unwrap_or("")
211                                            .len()
212                                            .saturating_sub(8)..]
213                                    );
214                                    println!("     Address: {}", addr);
215                                }
216                            }
217                        }
218                        if peers.len() > 2 {
219                            println!("   ... and {} more peers", peers.len() - 2);
220                        }
221                    }
222                }
223            }
224        }
225        Err(e) => println!("   Error: {}", e),
226    }
227
228    println!("\n✅ IPFS API Demo completed!");
229    println!("This example demonstrated:");
230    println!("  • POST requests with no body (version, id)");
231    println!("  • POST with query parameters (repo/stat, pin/ls)");
232    println!("  • POST with multipart file upload (add)");
233    println!("  • POST with binary responses (cat - in demonstrate_file_operations)");
234    println!("  • Module-level convenience functions (swarm/peers)");
235    println!("  • Different response types (JSON, binary)");
236
237    Ok(())
238}
239
240/// Demonstrates file operations with the uploaded file
241fn demonstrate_file_operations(
242    client: &HttpClient,
243    api_base: &str,
244    file_hash: &str,
245) -> Result<(), Box<dyn std::error::Error>> {
246    // Example: Get file content (binary response)
247    println!("\n   📄 GET file content (POST returning binary data):");
248    match client
249        .post(format!("{}/cat", api_base))
250        .query("arg", file_hash)
251        .send()
252    {
253        Ok(response) => {
254            println!("      Status: {}", response.status());
255            if response.is_success() {
256                match response.text() {
257                    Ok(content) => {
258                        println!(
259                            "      File content: {}",
260                            content.lines().next().unwrap_or("empty")
261                        );
262                        println!("      Content length: {} bytes", content.len());
263                    }
264                    Err(_) => {
265                        println!("      Binary content: {} bytes", response.bytes().len());
266                    }
267                }
268            }
269        }
270        Err(e) => println!("      Error: {}", e),
271    }
272
273    // Example: Pin the file explicitly (idempotent operation)
274    println!("\n   📌 PIN file (POST with path parameter):");
275    match client
276        .post(format!("{}/pin/add", api_base))
277        .query("arg", file_hash)
278        .query("recursive", "false")
279        .send()
280    {
281        Ok(response) => {
282            println!("      Status: {}", response.status());
283            if response.is_success() {
284                if let Ok(pin_result) = response.json::<serde_json::Value>() {
285                    if let Some(pins) = pin_result.get("Pins").and_then(|p| p.as_array()) {
286                        println!("      Pinned {} objects", pins.len());
287                        for pin in pins {
288                            println!("      - {}", pin.as_str().unwrap_or("unknown"));
289                        }
290                    }
291                }
292            }
293        }
294        Err(e) => println!("      Error: {}", e),
295    }
296
297    Ok(())
298}
Source

pub fn put<U: Into<String>>(&self, url: U) -> RequestBuilder

Examples found in repository?
examples/http_client.rs (line 153)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    println!("====================================");
6    println!("HTTP v2 Client Demo");
7    println!("====================================");
8
9    println!("\n1. GET request:");
10    match get("https://httpbin.org/get").send() {
11        Ok(response) => {
12            println!("GET Status: {}", response.status());
13            println!("GET Success: {}", response.is_success());
14        }
15        Err(e) => println!("GET Error: {}", e),
16    }
17
18    println!("\n2. POST with JSON:");
19    let json_data = serde_json::json!({
20        "name": "Blockless SDK",
21        "version": "2.0",
22        "api_style": "reqwest-like"
23    });
24    match post("https://httpbin.org/post").json(&json_data)?.send() {
25        Ok(response) => {
26            println!("POST JSON Status: {}", response.status());
27            if let Ok(response_json) = response.json::<serde_json::Value>() {
28                if let Some(received_json) = response_json.get("json") {
29                    println!("Received JSON: {}", received_json);
30                }
31            }
32        }
33        Err(e) => println!("POST JSON Error: {}", e),
34    }
35
36    println!("\n3. Client instance with default configuration:");
37    let mut default_headers = HashMap::new();
38    default_headers.insert("User-Agent".to_string(), "Blockless-SDK/2.0".to_string());
39    default_headers.insert("Accept".to_string(), "application/json".to_string());
40    let client = HttpClient::builder()
41        .default_headers(default_headers)
42        .timeout(10000)
43        .build();
44    match client
45        .get("https://httpbin.org/get")
46        .query("search", "blockless")
47        .query("limit", "10")
48        .query("format", "json")
49        .send()
50    {
51        Ok(response) => {
52            println!("Client GET Status: {}", response.status());
53            if let Ok(json_data) = response.json::<serde_json::Value>() {
54                if let Some(args) = json_data.get("args") {
55                    println!("Query params: {}", args);
56                }
57            }
58        }
59        Err(e) => println!("Client GET Error: {}", e),
60    }
61
62    println!("\n4. Authentication examples:");
63    match client
64        .get("https://httpbin.org/basic-auth/user/pass")
65        .basic_auth("user", "pass")
66        .send()
67    {
68        Ok(response) => {
69            println!("Basic auth status: {}", response.status());
70            if let Ok(json_data) = response.json::<serde_json::Value>() {
71                println!("Authenticated: {:?}", json_data.get("authenticated"));
72            }
73        }
74        Err(e) => println!("Basic auth error: {}", e),
75    }
76
77    match client
78        .get("https://httpbin.org/bearer")
79        .bearer_auth("test-token-12345")
80        .send()
81    {
82        Ok(response) => {
83            println!("Bearer auth status: {}", response.status());
84            if let Ok(json_data) = response.json::<serde_json::Value>() {
85                println!("Token received: {:?}", json_data.get("token"));
86            }
87        }
88        Err(e) => println!("Bearer auth error: {}", e),
89    }
90
91    println!("\n5. Different request body types:");
92    let mut form_data = HashMap::new();
93    form_data.insert("name".to_string(), "Blockless".to_string());
94    form_data.insert("type".to_string(), "distributed computing".to_string());
95    match client
96        .post("https://httpbin.org/post")
97        .form(form_data)
98        .send()
99    {
100        Ok(response) => {
101            println!("Form POST Status: {}", response.status());
102            if let Ok(json_data) = response.json::<serde_json::Value>() {
103                if let Some(form) = json_data.get("form") {
104                    println!("Form data received: {}", form);
105                }
106            }
107        }
108        Err(e) => println!("Form POST Error: {}", e),
109    }
110
111    println!("\n6. Multipart form with file upload:");
112    let multipart_fields = vec![
113        MultipartField::text("description", "SDK test file"),
114        MultipartField::file(
115            "upload",
116            b"Hello from Blockless SDK v2!".to_vec(),
117            "hello.txt",
118            Some("text/plain".to_string()),
119        ),
120    ];
121    match client
122        .post("https://httpbin.org/post")
123        .multipart(multipart_fields)
124        .send()
125    {
126        Ok(response) => {
127            println!("Multipart POST Status: {}", response.status());
128            if let Ok(json_data) = response.json::<serde_json::Value>() {
129                if let Some(files) = json_data.get("files") {
130                    println!("Files uploaded: {}", files);
131                }
132            }
133        }
134        Err(e) => println!("Multipart POST Error: {}", e),
135    }
136
137    println!("\n7. Binary data:");
138    let binary_data = vec![0x48, 0x65, 0x6c, 0x6c, 0x6f]; // "Hello" in bytes
139    match client
140        .post("https://httpbin.org/post")
141        .header("Content-Type", "application/octet-stream")
142        .body_bytes(binary_data)
143        .send()
144    {
145        Ok(response) => {
146            println!("Binary POST Status: {}", response.status());
147        }
148        Err(e) => println!("Binary POST Error: {}", e),
149    }
150
151    println!("\n8. Advanced request building:");
152    match client
153        .put("https://httpbin.org/put")
154        .header("X-Custom-Header", "custom-value")
155        .header("X-API-Version", "2.0")
156        .query("action", "update")
157        .query("id", "12345")
158        .timeout(5000)
159        .body("Updated data")
160        .send()
161    {
162        Ok(response) => {
163            println!("PUT Status: {}", response.status());
164            if let Ok(json_data) = response.json::<serde_json::Value>() {
165                if let Some(headers) = json_data.get("headers") {
166                    println!("Custom headers received: {}", headers);
167                }
168            }
169        }
170        Err(e) => println!("PUT Error: {}", e),
171    }
172
173    println!("\nDemo completed 🚀");
174    Ok(())
175}
Source

pub fn patch<U: Into<String>>(&self, url: U) -> RequestBuilder

Source

pub fn delete<U: Into<String>>(&self, url: U) -> RequestBuilder

Source

pub fn head<U: Into<String>>(&self, url: U) -> RequestBuilder

Source

pub fn request<U: Into<String>>(&self, method: &str, url: U) -> RequestBuilder

Trait Implementations§

Source§

impl Clone for HttpClient

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Default for HttpClient

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> ErasedDestructor for T
where T: 'static,