Crate feignhttp[−][src]
FeignHttp
FeignHttp is a declarative HTTP client. Based on rust macros.
Features
- Easy to use
- Asynchronous request
- Configurable timeout settings
- Supports form, plain text and JSON
- Selectable HTTP backends (reqwest or isahc)
Usage
FeignHttp mark macros on asynchronous functions, you need a runtime for support async/await. You can use async-std or tokio.
async-std:
[dependencies]
async-std = { version = "1", features = ["attributes", "tokio1"] }
The feature tokio1
is need when use reqwest as the HTTP backend.
tokio:
[dependencies]
tokio = { version = "1", features = ["full"] }
Add feignhttp in your Cargo.toml
and use default feature:
feignhttp = { version = "0.3" }
Then add the following code:
use feignhttp::get; #[get("https://api.github.com")] async fn github() -> feignhttp::Result<String> {} #[async_std::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let r = github().await?; println!("result: {}", r); Ok(()) }
The get
attribute macro specifies get request, feignhttp::Result<String>
specifies the return result.
It will send get request to https://api.github.com
and receive a plain text body.
Using non-default HTTP backend:
feignhttp = { version = "0.3", default-features = false, features = ["isahc-client"] }
The default-features = false
option disable default reqwest.
Making a POST request
For a post request, you should use the post
attribute macro to specify request method and use a body
attribute to specify
a request body.
use feignhttp::post; #[post(url = "https://httpbin.org/anything")] async fn post_data(#[body] text: String) -> feignhttp::Result<String> {}
The #[body]
mark a request body. Function parameter text
is a String type, it will put in the request body as plain text.
String and &str will be put as plain text into the request body.
Paths
Using path
to specify path value:
use feignhttp::get; #[get("https://api.github.com/repos/{owner}/{repo}")] async fn repository( #[path] owner: &str, #[path] repo: String, ) -> feignhttp::Result<String> {} #[async_std::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let r = repository("dxx", "feignhttp".to_string()).await?; println!("repository result: {}", r); Ok(()) }
dxx
will replace {owner}
and feignhttp
will replace {repo}
, the url to be send will be
https://api.github.com/repos/dxx/feignhttp
. You can specify a path name like #[path("owner")]
.
Query Parameters
Using query
to specify query parameter:
use feignhttp::get; #[get("https://api.github.com/repos/{owner}/{repo}/contributors")] async fn contributors( #[path("owner")] user: &str, #[path] repo: &str, #[query] page: u32, ) -> feignhttp::Result<String> {} #[async_std::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let r = contributors ( "dxx", "feignhttp", 1, ).await?; println!("contributors result: {}", r); Ok(()) }
The page
parameter will as query parameter in the url. An url which will be send is https://api.github.com/repos/dxx/feignhttp?page=1
.
Note: A function parameter without query
attribute will as a query parameter by default.
Headers
Using header
to specify request header:
use feignhttp::get; #[get("https://api.github.com/repos/{owner}/{repo}/commits")] async fn commits( #[header] accept: &str, #[path] owner: &str, #[path] repo: &str, #[query] page: u32, #[query] per_page: u32, ) -> feignhttp::Result<String> {} #[async_std::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let r = commits( "application/vnd.github.v3+json", "dxx", "feignhttp", 1, 5, ) .await?; println!("commits result: {}", r); Ok(()) }
A header accept:application/vnd.github.v3+json
will be send.
Form
Using form
to specify form parameter:
use feignhttp::post; #[post(url = "https://httpbin.org/anything")] async fn post_user( #[form] id: i32, #[form] name: &str, ) -> feignhttp::Result<String> {} #[async_std::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let r = post_user(1, "jack").await?; println!("{}", r); Ok(()) }
See here for more examples.
URL constant
We can use constant to maintain all urls of request:
use feignhttp::get; const GITHUB_URL: &str = "https://api.github.com"; #[get(GITHUB_URL, path = "/repos/{owner}/{repo}/languages")] async fn languages( #[path] owner: &str, #[path] repo: &str, ) -> feignhttp::Result<String> {}
Url constant must be the first metadata in get attribute macro. You also can specify metadata key:
use feignhttp::get; const GITHUB_URL: &str = "https://api.github.com"; #[get(url = GITHUB_URL, path = "/repos/{owner}/{repo}/languages")] async fn languages( #[path] owner: &str, #[path] repo: &str, ) -> feignhttp::Result<String> {}
JSON
Serde is a framework for serializing and deserializing Rust data structures. When use json, you should add serde in Cargo.toml
:
[dependencies]
serde = { version = "1", features = ["derive"] }
Here is an example of getting json:
use feignhttp::get; use serde::Deserialize; // Deserialize: Specifies deserialization #[derive(Debug, Deserialize)] struct IssueItem { pub id: u32, pub number: u32, pub title: String, pub url: String, pub repository_url: String, pub state: String, pub body: Option<String>, } const GITHUB_URL: &str = "https://api.github.com"; #[get(url = GITHUB_URL, path = "/repos/{owner}/{repo}/issues")] async fn issues( #[path] owner: &str, #[path] repo: &str, page: u32, per_page: u32, ) -> feignhttp::Result<Vec<IssueItem>> {} #[async_std::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let r = issues("octocat", "hello-world", 1, 2).await?; println!("issues: {:#?}", r); Ok(()) }
This issues function return Vec<IssueItem>
, it is deserialized according to the content of the response.
Send a json request:
use feignhttp::post; use serde::Serialize; #[derive(Debug, Serialize)] struct User { id: i32, name: String, } #[post(url = "https://httpbin.org/anything")] async fn post_user(#[body] user: User) -> feignhttp::Result<String> {} #[async_std::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let user = User { id: 1, name: "jack".to_string(), }; let r = post_user(user).await?; println!("{}", r); Ok(()) }
See here for a complete example.
Using structure
Structure is a good way to manage requests. Define a structure and then define a large number of request methods:
use feignhttp::feign; const GITHUB_URL: &str = "https://api.github.com"; struct Github; #[feign(url = GITHUB_URL)] impl Github { #[get] async fn home() -> feignhttp::Result<String> {} #[get("/repos/{owner}/{repo}")] async fn repository( #[path] owner: &str, #[path] repo: &str, ) -> feignhttp::Result<String> {} // ... // Structure method still send request #[get(path = "/repos/{owner}/{repo}/languages")] async fn languages( &self, #[path] owner: &str, #[path] repo: &str, ) -> feignhttp::Result<String> {} }
See here for a complete example.
Timeout configuration
If you need to configure the timeout, use connect_timeout
and timeout
to specify connect timeout and read timeout.
Connect timeout:
use feignhttp::get; #[get(url = "http://xxx.com", connect_timeout = 3000)] async fn connect_timeout() -> feignhttp::Result<String> {}
Read timeout:
use feignhttp::get; #[get(url = "https://httpbin.org/delay/5", timeout = 3000)] async fn timeout() -> feignhttp::Result<String> {}
Optional Features
The following features are available. The default features are reqwest-client
.
- reqwest-client (default): use
reqwest
as the HTTP backend. - isahc-client: use
isahc
as the HTTP backend.
Structs
Error | The errors that may occur when processing a request. |
HttpClient | An HTTP client to make requests. |
HttpConfig | Configuration of an HTTP request. |
RequestWrapper | A wrapper of HTTP request. |
ResponseWrapper | A wrapper of HTTP response. |
Enums
ErrorKind |
Traits
HttpRequest | A trait of request. |
HttpResponse | A trait of response. |
Type Definitions
Result | A |
Attribute Macros
delete | |
feign | |
get | |
post | |
put |