#hyper #binding #http #retrofit #http-api #api-bindings #api

已删除 hyper_api_service

受Retrofit启发的Rust实现

0.2.2 2021年8月3日
0.2.1 2021年8月3日
0.1.8 2021年8月2日
0.1.3 2021年7月29日

#181 in #http-api

每月24次下载

MIT 协议

51KB
1.5K SLoC

hyperAPIService

tag Crates.io Travis CI Build Status docs

license stars forks

受Retrofit启发的Rust实现。

为什么

我喜欢Retrofit(Java)和WebServiceAPI风格的编码。

但是,在Rust中实现它们比较困难,并且很少有库能够实现它们的部分功能。

因此,我实现了hyperAPIService。希望你会喜欢它:)

功能

  • 类似Retrofit的WebService Restful API API
    • 引擎
      • Hyper 特性: for_hyper
      • <待续.../ ...
    • 通用
      • 拦截请求:InterceptorFunc(结构体)/ Interceptor(特质)
      • 共享连接超时:set_timeout_millisecond()
      • 共享默认头:set_default_header()
      • 共享客户端:set_client()
    • 请求
      • 将结构体序列化为hyper HTTPBody:BodySerializer(特质)
    • 响应
      • 将hyper HTTPBody反序列化为结构体:BodyDeserializer(特质)
  • 可选
    • SerdeJsonSerializer/SerdeJsonDeserializer 特性: for_serde
    • MultipartSerializer 特性: multipart

注意

  • 如果您想绕过
    • 序列化,可以使用 DummyBypassSerializer
    • 反序列化,可以使用 DummyBypassDeserializer

依赖项

[features]
default = [
  "for_hyper", "multipart", "for_serde"
]
for_hyper = [ "hyper", "tokio" ]
multipart = [ "formdata", "multer", "mime" ]
for_serde = [ "serde", "serde_json" ]
pure = []

[dependencies]

# Required
bytes = "^1.0.0"
http = "^0.2.4"
futures="^0.3.0"
url="^2.2.0"

# for_hyper
hyper = { version = "^0.14.0", optional = true, features = ["client", "http1", "http2", "stream", "tcp",] }
tokio = { version = "^1.8.0", optional = true,features = ["time", "macros",] }

# multipart
formdata = { version = "^0.13.0", optional = true }
multer = { version = "^2.0.0", optional = true }
mime = { version = "^0.3.0", optional = true }

# for_serde
serde = { version = "^1.0", features = ["derive"], optional = true }
serde_json = { version = "^1.0", optional = true }

使用

设置:基础URL/超时/头,拦截/序列化器/反序列化器

示例


use std::sync::Arc;

use http::method::Method;
use hyper::HeaderMap;

use hyper_api_service::bind_hyper;
use hyper_api_service::path_param;
use hyper_api_service::simple_api;
use hyper_api_service::simple_api::{
    DEFAULT_SERDE_JSON_DESERIALIZER, DEFAULT_SERDE_JSON_SERIALIZER,
};

use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
struct Product {
    name: String,
    age: String,
}
impl Default for Product {
    fn default() -> Self {
        return Product {
            name: "".to_string(),
            age: "".to_string(),
        };
    }
}

let json_serializer = Arc::new(DEFAULT_SERDE_JSON_SERIALIZER);
let json_deserializer = Arc::new(DEFAULT_SERDE_JSON_DESERIALIZER);
let return_type_marker = &Product::default();

let common_api = bind_hyper::CommonAPI::new_for_hyper();
let mut base_service_setter = common_api.as_base_service_setter();
let base_service_shared = common_api.as_base_service_shared();

// Setup base_url
base_service_setter.set_base_url(url::Url::parse("http://localhost:3000").ok().unwrap());
// Setup timeout_millisecond
base_service_setter.set_timeout_millisecond(10 * 1000);

// Add common headers for Authentication or other usages
let mut header_map = match base_service_setter.get_default_header() {
    Some(header) => header,
    None => HeaderMap::new(),
};
header_map = bind_hyper::add_header_authentication_bearer(header_map, "MY_TOKEN")
    .ok()
    .unwrap();
base_service_setter.set_default_header(Some(header_map));

// Add interceptor for observing Requests before connections
base_service_setter.add_interceptor_fn(|req| {
    println!("REQ_CONTENT: {:?}", req);
    Ok(())
});

GET/POST

示例


// GET
let api_get_product = base_service_shared.make_api_no_body(
    base_service_shared.clone(),
    Method::GET,
    "/products/{id}",
    json_deserializer.clone(),
    return_type_marker,
);

// NOTE: You can use the HashMap<String, String> directly
// or path_param!["key1" => "val1", "key2" => "val2"])

// let path_param = [("id".into(), "3".into())]
//     .iter()
//     .cloned()
//     .collect::<simple_api::PathParam>();
let resp = api_get_product.call(Some(path_param!["id" => "3"])).await;
let model = resp.ok().unwrap(); // The deserialized model Product is here.

// POST

let api_post_product = base_service_shared.make_api_has_body(
    base_service_shared.clone(),
    Method::POST,
    "/products/{id}",
    "application/json",
    json_serializer.clone(),
    json_deserializer.clone(),
    return_type_marker,
);

let sent_body = Product {
    name: "Alien ".to_string(),
    age: "5 month".to_string(),
};
let resp = api_post_product
    .call(Some(path_param!["id" => "5"]), sent_body)
    .await;
let model = resp.ok().unwrap();

多部分

示例


// Multipart

use formdata::FormData;

let form_data_origin = FormData {
    fields: vec![
        ("name".to_owned(), "Baxter".to_owned()),
        ("age".to_owned(), "1 month".to_owned()),
    ],
    files: vec![],
};

// POST make_api_multipart
let api_post_multipart = base_service_shared.make_api_multipart(
    base_service_shared.clone(),
    Method::POST,
    "/form",
    json_deserializer.clone(),
    return_type_marker,
);

let resp = api_post_multipart
    .call(Some(simple_api::PathParam::new()), form_data_origin)
    .await;
let model = resp.ok().unwrap();

依赖项

~2–15MB
~217K SLoC