Skip to content

Instantly share code, notes, and snippets.

@TrueMemer
Created October 27, 2019 20:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TrueMemer/05dba5e9cf00a97cc1860b931467d899 to your computer and use it in GitHub Desktop.
Save TrueMemer/05dba5e9cf00a97cc1860b931467d899 to your computer and use it in GitHub Desktop.
Rust hyper web api
extern crate futures;
extern crate hyper;
extern crate pretty_env_logger;
#[macro_use] extern crate log;
extern crate serde;
extern crate serde_json;
extern crate serde_with;
extern crate usher;
use futures::{future, Future};
use hyper::{Body, Request, Server, StatusCode, Client};
use hyper::client::HttpConnector;
use hyper::service::service_fn;
use usher::capture::find_capture;
use serde::{Serialize, Deserialize};
use serde_with::skip_serializing_none;
type GenericError = Box<dyn std::error::Error + Send + Sync>;
type ResponseFuture = Box<dyn Future<Item = hyper::Response<Body>, Error = GenericError> + Send>;
type Handler = Box<dyn Fn(Request<Body>, Vec<(&str, (usize, usize))>, &Client<HttpConnector>) -> ResponseFuture + Send + Sync>;
#[skip_serializing_none]
#[derive(Serialize, Deserialize)]
struct Response<T> {
status: u16,
data: Option<T>,
error: Option<String>
}
impl<T> Response<T> {
fn new() -> Self {
Response { status: 200, data: None, error: None }
}
fn status(mut self, s: u16) -> Response<T> {
self.status = s;
self
}
fn data(mut self, d: T) -> Response<T> {
self.data = Some(d);
self
}
fn error(mut self, e: String) -> Response<T> {
self.error = Some(e);
self
}
}
type StringResponse = Response<String>;
impl StringResponse {
fn to_json_string(&self) -> String {
serde_json::to_string(self).unwrap()
}
fn to_body(&self) -> Body {
Body::from(self.to_json_string())
}
}
fn not_found_handler() -> ResponseFuture {
let resp: StringResponse =
Response::new()
.status(404)
.error(String::from("Not Found"));
let body = resp.to_body();
Box::new(future::ok(
hyper::Response::builder()
.status(StatusCode::from_u16(resp.status).unwrap())
.body(body)
.unwrap()
))
}
fn hello(req: Request<Body>, params: Vec<(&str, (usize, usize))>, _client: &Client<HttpConnector>) -> ResponseFuture {
let path = req.uri().path();
let name = find_capture(&path, &params, "name").unwrap();
let body = Body::from(String::from(format!("Hello, {}", name)));
let resp = hyper::Response::new(body);
Box::new(future::ok(resp))
}
fn main() {
pretty_env_logger::init();
hyper::rt::run(future::lazy(move || {
let addr: std::net::SocketAddr = ([127, 0, 0, 1], 3000).into();
use usher::http::HttpRouter;
use usher::prelude::{StaticParser, DynamicParser};
let mut router: HttpRouter<Handler> =
HttpRouter::new(vec![Box::new(DynamicParser), Box::new(StaticParser)]);
router.get("/:name", Box::new(hello));
let router = std::sync::Arc::new(router);
let http_client = Client::new();
let service = move || {
let client = http_client.clone();
let router = router.clone();
service_fn(move |req: Request<Body>| {
let method = req.method();
let path = req.uri().path();
match router.handler(method, path) {
Some((handler, captures)) => handler(req, captures, &client),
None => not_found_handler()
}
})
};
let server = Server::bind(&addr)
.serve(service)
.map_err(|e| eprintln!("error {}", e));
info!("Listening on {}...", addr);
server
}));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment