3 releases
0.1.2 | Jan 31, 2025 |
---|---|
0.1.1 | Jan 23, 2025 |
0.1.0 | Jan 22, 2025 |
#1437 in Network programming
369 downloads per month
28KB
406 lines
echo_http
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
Features
- Type-safe HTTP requests and responses
- Async support with
reqwest
- Generic response deserialization
Getting started
Requirements
- An async runtime (e.g., tokio).
serde
for data serialization/deserialization.- Optional:
reqwest
if you need advanced features not provided byecho_http
directly.
Installation
[dependencies]
echo_http = "0.1"
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
# reqwest = { version = "0.12", features = ["json"] }
Example Usage
In a hurry?
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(())
}
Managing Headers with the Headers
API
- The
Headers
struct offers a user-friendly way to manage request headers without working directly withreqwest::HeaderMap
.
Inserting headers:
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);
{........}
}
Inserting multiple 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);
{........}
}
Have no idea what data type youre expecting?
- if the response type is unclear, use
get_unknown
to 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(())
}
Do you require a little more control?
- 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(())
}
contributing: if you want to?
Dependencies
~4–16MB
~200K SLoC