Created
August 22, 2018 08:18
-
-
Save djc/7555a2f23db7613e6637aaa256c4e972 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern crate diesel; | |
extern crate dotenv; | |
extern crate futures; | |
extern crate hyper; | |
extern crate juniper; | |
extern crate r2d2; | |
extern crate r2d2_diesel; | |
extern crate serde; | |
extern crate serde_json; | |
extern crate trackpay; | |
extern crate url; | |
use diesel::sqlite::SqliteConnection as Connection; | |
use futures::future; | |
use hyper::rt::{Future, Stream}; | |
use hyper::service::service_fn; | |
use hyper::{Body, Method, Request, Response, Server, StatusCode}; | |
use juniper::graphiql::graphiql_source; | |
use juniper::http; | |
use juniper::{InputValue, RootNode}; | |
use r2d2_diesel::ConnectionManager; | |
use std::env; | |
use url::Url; | |
use trackpay::{graphql, Context, Pool}; | |
fn main() { | |
dotenv::dotenv().ok(); | |
let db_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); | |
let conn_mgr = ConnectionManager::<Connection>::new(db_url); | |
let pool = r2d2::Pool::builder() | |
.build(conn_mgr) | |
.expect("Failed to create pool"); | |
let new_svc = move || { | |
let pool = pool.clone(); | |
service_fn(move |req| respond(pool.clone(), req)) | |
}; | |
let addr = ([127, 0, 0, 1], 3000).into(); | |
let server = Server::bind(&addr) | |
.serve(new_svc) | |
.map_err(|e| eprintln!("server error: {}", e)); | |
hyper::rt::run(server); | |
} | |
fn respond(pool: Pool, req: Request<Body>) -> BoxFut { | |
println!("request: {:?} {:?}", req.uri().path(), req.method()); | |
match (req.uri().path(), req.method()) { | |
("/", &Method::GET) => Box::new(future::ok( | |
Response::builder() | |
.header("Content-Type", "text/html; charset=utf-8") | |
.body(Body::from(graphiql_source("/graphql"))) | |
.unwrap(), | |
)), | |
("/graphql", &Method::GET) => { | |
let url = Url::parse(&format!("{}", req.uri())).unwrap(); | |
let (mut query, mut op, mut vars) = (None, None, None); | |
for (name, val) in url.query_pairs() { | |
if name == "query" { | |
query = Some(val.to_string()); | |
} else if name == "operationName" { | |
op = Some(val.to_string()); | |
} else if name == "variables" { | |
vars = Some(val.to_string()); | |
} | |
} | |
let vars = vars | |
.as_ref() | |
.map(|v| serde_json::from_str::<InputValue>(v).unwrap()); | |
Box::new(future::ok(gql_response( | |
&pool, | |
http::GraphQLRequest::new(query.unwrap(), op, vars), | |
))) | |
} | |
("/graphql", &Method::POST) => Box::new(req.into_body().concat2().map(move |chunk| { | |
gql_response( | |
&pool, | |
serde_json::from_slice::<http::GraphQLRequest>(&chunk).unwrap(), | |
) | |
})), | |
("/", _) | ("/graphql", _) => { | |
Box::new(future::ok(error_response(StatusCode::METHOD_NOT_ALLOWED))) | |
} | |
(_, _) => Box::new(future::ok(error_response(StatusCode::NOT_FOUND))), | |
} | |
} | |
fn gql_response(pool: &Pool, req: http::GraphQLRequest) -> Response<Body> { | |
Response::builder() | |
.header("Content-Type", "application/json") | |
.body(Body::from( | |
serde_json::to_vec(&req.execute( | |
&RootNode::new(graphql::Query, graphql::Mutation), | |
&Context { | |
connection: pool.get().unwrap(), | |
}, | |
)).unwrap(), | |
)) | |
.unwrap() | |
} | |
fn error_response(status: StatusCode) -> Response<Body> { | |
Response::builder() | |
.status(status) | |
.header("Content-Type", "text/plain; charset=utf-8") | |
.body(Body::from(status.canonical_reason().unwrap())) | |
.unwrap() | |
} | |
type BoxFut = Box<Future<Item = Response<Body>, Error = hyper::Error> + Send>; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment