echo_http is a type-safe HTTP client library built with Rust, based on Axios, for the typescript devs that just can't let go
- Type-safe HTTP requests and responses
- Async support with
reqwest - Generic response deserialization
- An async runtime (e.g., tokio).
serdefor data serialization/deserialization.- Optional:
reqwestif you need advanced features not provided byecho_httpdirectly.
[dependencies]
echo_http = "0.1"
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
# reqwest = { version = "0.12", features = ["json"] }just use echo_http::echo;
- This is a static default instance. No need to configure anything, just bring into scope and go!
- works with all supported methods: get, post, put and delete
use echo_http::echo;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let res = echo.get<Vec<Post>>("https://jsonplaceholder.typicode.com/posts").await?;
println!("{}", res.data);
Ok(())
}- The
Headersstruct offers a user-friendly way to manage request headers without working directly withreqwest::HeaderMap.
use echo_http::{Headers, Echo, RequestConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut headers = Headers::new();
headers.insert("Content-Type: application/json");
headers.insert("Authorization: Bearer token");
let mut echo_config = RequestConfig::default();
echo_config.headers = Some(headers);
{........}
}#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut headers = Headers::new();
headers.insert_many(vec![
"Content-Type: application/json",
"Authorization: Bearer token",
]);
let mut echo_config = RequestConfig::default();
echo_config.headers = Some(headers);
{........}
}- if the response type is unclear, use
get_unknownto retreive aserde_json::Value - *Only supports GET requests at this time.
use echo_http::echo;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// hmmm this api has no documentation, i wonder what the data type is...
let idk = echo.get_unknown("https://mysterious.internal.api/").await?;
println!("π {:#?}", idk)
Ok(())
}- instantiate a config and update it
use echo_http::Echo;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// your instance must be mutable if you intend to update your config
let mut echo = Echo::configure(None);
let mut headers = Headers::new();
headers.insert_many(vec![
"Content-Type: application/json",
"Authorization: Bearer token",
]);
echo.headers = Some(headers.clone());
let posts = echo
.get<Vec<Post>>("https://jsonplaceholder.typicode.com/posts")
.await?
.data // you can chain .data to get the Response.data directly. cool, right?
for post in posts {
println!("Post ID: {}, Title: {}", post.id, post.title);
}
}- or just create one with your preferences if you dont intend on updating it later
use echo_http::{Echo, RequestConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut config = RequestConfig::default();
config.base_url = Some("https://my_backend.api".to_string());
config.timeout = Some(5000);
let echo = Echo::configure(Some(config));
// base_url is already defined, we can just add an endpoint here
let users = echo.get<User>("/users/1")
....
}- post requets
#[derive(serde::Serialize, serde::Deserialize, Debug)]
struct Post {
user_id: u32,
id: u32,
title: String,
body: String,
}
#[tokio::main]
async fn main() -> Result<(), Err> {
let echo = Echo::configure(Some(/* set base_url */));
let new_post = Post {
user_id: 1,
id: 1,
title: "post title".to_string(),
body: "compelling post body".to_string(),
};
// since the base_url is already set, we can just add the endpoint here
let res = echo.post::<Post>("posts", Some(new_post)).await?;
println!("{:#?}", res);
Ok(())
}- put example
#[derive(serde::Serialize, serde::Deserialize, Debug)]
struct Post {
user_id: u32,
id: u32,
title: String,
body: String,
}
#[tokio::main]
async fn main() -> Result<(), Err> {
let echo = Echo::configure(Some(/* set base_url */));
let updated_post = Post {
user_id: 1,
id: 1,
title: "updated post title".to_string(),
body: "compelling post body with the classic reddit *edit:".to_string(),
};
// since the base_url is already set, we can just add the endpoint here
let res = echo.post::<Post>("posts", Some(updated_post)).await?;
println!("{:#?}", res);
Ok(())
}- delete example - does not take a type argument
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let echo = Echo::configure(None);
let res = echo.delete("https://jsonplaceholder.typicode.com/posts/1").await?;
println!("{:#?}", res);
Ok(())
}