Initial work on Rocket integration

This commit is contained in:
Magnus Hallin 2017-06-14 15:50:27 +02:00
parent a7a6778b18
commit e82534aced
5 changed files with 129 additions and 2 deletions

View file

@ -22,19 +22,28 @@ path = "benches/bench.rs"
name = "server"
required-features = ["iron-handlers", "expose-test-schema"]
[[example]]
name = "rocket-server"
required-features = ["rocket-handlers", "expose-test-schema"]
[features]
nightly = []
iron-handlers = ["iron", "serde_json", "urlencoded"]
rocket-handlers = ["rocket", "rocket_codegen", "serde_json"]
expose-test-schema = []
[dependencies]
serde = { version = "^1.0.8" }
serde_derive = {version="^1.0.8" }
iron = { version = "^0.5.1", optional = true }
serde_json = { version = "^1.0.2", optional = true }
iron = { version = "^0.5.1", optional = true }
urlencoded = { version = "^0.5.0", optional = true }
rocket = { version = "^0.2.8", optional = true }
rocket_codegen = { version = "^0.2.8", optional = true }
[dev-dependencies]
iron = "^0.5.1"
router = "^0.5.0"

37
examples/rocket-server.rs Normal file
View file

@ -0,0 +1,37 @@
#![feature(plugin)]
#![plugin(rocket_codegen)]
extern crate rocket;
extern crate juniper;
use rocket::response::content;
use rocket::State;
use juniper::tests::model::Database;
use juniper::{EmptyMutation, RootNode};
use juniper::rocket_handlers;
type Schema = RootNode<'static, Database, EmptyMutation<Database>>;
#[get("/")]
fn graphiql() -> content::HTML<String> {
rocket_handlers::graphiql_source("/graphql")
}
#[post("/graphql", data="<request>")]
fn post_graphql_handler(
context: State<Database>,
request: rocket_handlers::GraphQLRequest,
schema: State<Schema>
) -> rocket_handlers::GraphQLResponse {
request.execute(&schema, &context)
}
fn main() {
rocket::ignite()
.manage(Database::new())
.manage(Schema::new(Database::new(), EmptyMutation::<Database>::new()))
.mount("/", routes![graphiql, post_graphql_handler])
.launch();
}

View file

@ -1,2 +1,3 @@
#[cfg(feature="iron-handlers")] pub mod iron_handlers;
#[cfg(feature="rocket-handlers")] pub mod rocket_handlers;
pub mod serde;

View file

@ -0,0 +1,74 @@
use std::io::{Cursor, Read};
use serde_json;
use rocket::Request;
use rocket::data::{FromData, Outcome};
use rocket::response::{Responder, Response, content};
use rocket::http::{ContentType, Status};
use rocket::Data;
use rocket::Outcome::{Forward, Failure, Success};
use ::http;
use types::base::GraphQLType;
use schema::model::RootNode;
pub struct GraphQLResponse(Status, String);
pub struct GraphQLRequest(http::GraphQLRequest);
pub fn graphiql_source(graphql_endpoint_url: &str) -> content::HTML<String> {
content::HTML(::graphiql::graphiql_source(graphql_endpoint_url))
}
impl GraphQLRequest {
pub fn execute<CtxT, QueryT, MutationT>(
&self,
root_node: &RootNode<QueryT, MutationT>,
context: &CtxT,
)
-> GraphQLResponse
where QueryT: GraphQLType<Context=CtxT>,
MutationT: GraphQLType<Context=CtxT>,
{
let response = self.0.execute(root_node, context);
let status = if response.is_ok() { Status::Ok } else { Status::BadRequest };
let json = serde_json::to_string_pretty(&response).unwrap();
GraphQLResponse(status, json)
}
}
impl FromData for GraphQLRequest {
type Error = String;
fn from_data(request: &Request, data: Data) -> Outcome<Self, String> {
if !request.content_type().map_or(false, |ct| ct.is_json()) {
return Forward(data);
}
let mut body = String::new();
if let Err(e) = data.open().read_to_string(&mut body) {
return Failure((Status::InternalServerError, format!("{:?}", e)));
}
match serde_json::from_str(&body) {
Ok(value) => Success(GraphQLRequest(value)),
Err(failure) => return Failure(
(Status::BadRequest, format!("{}", failure)),
),
}
}
}
impl<'r> Responder<'r> for GraphQLResponse {
fn respond(self) -> Result<Response<'r>, Status> {
let GraphQLResponse(status, body) = self;
Ok(Response::build()
.header(ContentType::new("application", "json"))
.status(status)
.sized_body(Cursor::new(body))
.finalize())
}
}

View file

@ -185,6 +185,11 @@ built-in [GraphiQL][6] handler included.
#![cfg_attr(feature="nightly", feature(test))]
#![warn(missing_docs)]
#![cfg_attr(feature="rocket-handlers", feature(plugin))]
#![cfg_attr(feature="rocket-handlers", plugin(rocket_codegen))]
#[cfg(feature="rocket-handlers")] extern crate rocket;
#[cfg(feature="nightly")] extern crate test;
#[cfg(feature="iron-handlers")] #[macro_use(itry)] extern crate iron;
#[cfg(feature="iron-handlers")] extern crate urlencoded;
@ -192,7 +197,7 @@ built-in [GraphiQL][6] handler included.
extern crate serde;
#[macro_use] extern crate serde_derive;
#[cfg(feature="iron-handlers")] extern crate serde_json;
#[cfg(any(feature="iron-handlers", feature="rocket-handlers"))] extern crate serde_json;
#[macro_use] mod macros;
mod ast;
@ -232,6 +237,7 @@ pub use result_ext::ResultExt;
pub use schema::meta;
#[cfg(feature="iron-handlers")] pub use integrations::iron_handlers;
#[cfg(feature="rocket-handlers")] pub use integrations::rocket_handlers;
/// An error that prevented query execution
#[derive(Debug, PartialEq)]