Merge branch 'drop_rustc_serialization' of https://github.com/TheServerAsterisk/juniper into TheServerAsterisk-drop_rustc_serialization
# Conflicts: # examples/server.rs
This commit is contained in:
commit
7041efeda9
8 changed files with 344 additions and 212 deletions
|
@ -7,8 +7,8 @@ rust:
|
|||
- nightly
|
||||
|
||||
# The two most recent stable releases before "stable"
|
||||
- 1.13.0
|
||||
- 1.14.0
|
||||
- 1.15.0
|
||||
- 1.16.0
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
|
|
|
@ -20,15 +20,18 @@ name = "server"
|
|||
required-features = ["iron-handlers", "expose-test-schema"]
|
||||
|
||||
[features]
|
||||
default = ["rustc-serialize"]
|
||||
default = ["serde", "serde_json"]
|
||||
nightly = []
|
||||
iron-handlers = ["iron", "rustc-serialize"]
|
||||
iron-handlers = ["iron", "default", "serde_derive", "urlencoded"]
|
||||
expose-test-schema = []
|
||||
|
||||
[dependencies]
|
||||
rustc-serialize = { version = "^0.3.19", optional = true }
|
||||
iron = { version = "^0.5.1", optional = true }
|
||||
serde = { version = "^0.9.1", optional = true }
|
||||
serde_json = {version ="^0.9.1", optional = true }
|
||||
serde_derive = {version="^0.9.1", optional = true }
|
||||
urlencoded = {version="0.5", optional=true}
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
iron = "^0.5.1"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
extern crate iron;
|
||||
extern crate mount;
|
||||
extern crate logger;
|
||||
extern crate rustc_serialize;
|
||||
extern crate serde;
|
||||
extern crate juniper;
|
||||
|
||||
use std::env;
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
//! Optional handlers for the Iron framework. Requires the `iron-handlers` feature enabled.
|
||||
|
||||
use iron::prelude::*;
|
||||
use iron::middleware::Handler;
|
||||
use iron::mime::Mime;
|
||||
use iron::status;
|
||||
use iron::method;
|
||||
use iron::url::Url;
|
||||
use urlencoded::{UrlEncodedQuery, UrlDecodingError};
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::Read;
|
||||
use std::io::Error as IoError;
|
||||
use std::io::ErrorKind;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::boxed::Box;
|
||||
|
||||
use rustc_serialize::json::{ToJson, Json};
|
||||
use serde_json;
|
||||
use serde_json::error::Error as SerdeError;
|
||||
|
||||
use ::{InputValue, GraphQLType, RootNode, Variables, execute};
|
||||
use ::{InputValue, GraphQLType, RootNode, execute};
|
||||
use super::serde::{WrappedGraphQLResult, GraphQlQuery};
|
||||
|
||||
/// Handler that executes GraphQL queries in the given schema
|
||||
///
|
||||
|
@ -38,6 +44,53 @@ pub struct GraphiQLHandler {
|
|||
graphql_url: String,
|
||||
}
|
||||
|
||||
|
||||
/// Get queries are allowed to repeat the same key more than once.
|
||||
fn check_for_repeat_keys(params: &Vec<String>) -> Result<(), IronError> {
|
||||
if params.len() > 1 {
|
||||
let error = IronError::new(
|
||||
Box::new(GraphQlIronError::IO(IoError::new(ErrorKind::InvalidData,
|
||||
"Was able parse a query string \
|
||||
but a duplicate uri key was \
|
||||
found."))),
|
||||
(status::BadRequest, "Duplicate uri key was found."));
|
||||
Err(error)
|
||||
}
|
||||
else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_url_param(param: Option<Vec<String>>) -> Result<Option<String>, IronError> {
|
||||
if let Some(values) = param {
|
||||
check_for_repeat_keys(&values)?;
|
||||
Ok(Some(values[0].to_owned()))
|
||||
}
|
||||
else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_variable_param(param: Option<Vec<String>>) -> Result<Option<InputValue>, IronError> {
|
||||
if let Some(values) = param {
|
||||
check_for_repeat_keys(&values)?;
|
||||
match serde_json::from_str::<InputValue>(values[0].as_ref()) {
|
||||
Ok(input_values) => {
|
||||
Ok(Some(input_values))
|
||||
}
|
||||
Err(err) => {
|
||||
Err(IronError::new(
|
||||
Box::new(GraphQlIronError::Serde(err)),
|
||||
(status::BadRequest, "No JSON object was decoded.")))
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a, CtxFactory, Query, Mutation, CtxT>
|
||||
GraphQLHandler<'a, CtxFactory, Query, Mutation, CtxT>
|
||||
where CtxFactory: Fn(&mut Request) -> CtxT + Send + Sync + 'static,
|
||||
|
@ -59,81 +112,62 @@ impl<'a, CtxFactory, Query, Mutation, CtxT>
|
|||
}
|
||||
|
||||
|
||||
fn handle_get(&self, req: &mut Request) -> IronResult<Response> {
|
||||
let url: Url = req.url.clone().into();
|
||||
|
||||
let mut query = None;
|
||||
let variables = Variables::new();
|
||||
|
||||
for (k, v) in url.query_pairs() {
|
||||
if k == "query" {
|
||||
query = Some(v.into_owned());
|
||||
}
|
||||
}
|
||||
|
||||
let query = iexpect!(query);
|
||||
|
||||
self.execute(req, &query, &variables)
|
||||
}
|
||||
|
||||
fn handle_post(&self, req: &mut Request) -> IronResult<Response> {
|
||||
let json_data = itry!(Json::from_reader(&mut req.body));
|
||||
|
||||
let json_obj = match json_data {
|
||||
Json::Object(o) => o,
|
||||
_ => return Ok(Response::with((status::BadRequest, "No JSON object was decoded"))),
|
||||
};
|
||||
|
||||
let mut query = None;
|
||||
let mut variables = Variables::new();
|
||||
|
||||
for (k, v) in json_obj {
|
||||
if k == "query" {
|
||||
query = v.as_string().map(|s| s.to_owned());
|
||||
}
|
||||
else if k == "variables" {
|
||||
variables = InputValue::from_json(v).to_object_value()
|
||||
.map(|o| o.into_iter().map(|(k, v)| (k.to_owned(), v.clone())).collect())
|
||||
.unwrap_or_default();
|
||||
}
|
||||
}
|
||||
|
||||
let query = iexpect!(query);
|
||||
|
||||
self.execute(req, &query, &variables)
|
||||
}
|
||||
|
||||
fn execute(&self, req: &mut Request, query: &str, variables: &Variables) -> IronResult<Response> {
|
||||
let context = (self.context_factory)(req);
|
||||
let result = execute(query, None, &self.root_node, variables, &context);
|
||||
|
||||
let content_type = "application/json".parse::<Mime>().unwrap();
|
||||
let mut map = BTreeMap::new();
|
||||
|
||||
match result {
|
||||
Ok((result, errors)) => {
|
||||
map.insert("data".to_owned(), result.to_json());
|
||||
|
||||
if !errors.is_empty() {
|
||||
map.insert("errors".to_owned(), errors.to_json());
|
||||
fn handle_get(&self, req: &mut Request) -> IronResult<GraphQlQuery> {
|
||||
match req.get_mut::<UrlEncodedQuery>() {
|
||||
Ok(ref mut query_string) => {
|
||||
let input_query = parse_url_param(query_string.remove("query").to_owned())?;
|
||||
if let Some(query) = input_query {
|
||||
let operation_name =
|
||||
parse_url_param(query_string.remove("operationName"))?;
|
||||
let input_variables =
|
||||
parse_variable_param(query_string.remove("variables"))?;
|
||||
Ok(GraphQlQuery::new(query,operation_name,input_variables))
|
||||
} else {
|
||||
Err(IronError::new(
|
||||
Box::new(GraphQlIronError::IO(IoError::new(ErrorKind::InvalidData,
|
||||
"No query key was found in \
|
||||
the Get request."))),
|
||||
(status::BadRequest, "No query was provided.")))
|
||||
}
|
||||
|
||||
let data = Json::Object(map);
|
||||
let json = data.pretty();
|
||||
|
||||
Ok(Response::with((content_type, status::Ok, json.to_string())))
|
||||
}
|
||||
|
||||
Err(err) => {
|
||||
map.insert("errors".to_owned(), err.to_json());
|
||||
|
||||
let data = Json::Object(map);
|
||||
let json = data.pretty();
|
||||
|
||||
Ok(Response::with((content_type, status::BadRequest, json.to_string())))
|
||||
Err(IronError::new(
|
||||
Box::new(GraphQlIronError::Url(err)),
|
||||
(status::BadRequest, "No JSON object was decoded.")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_post(&self, req: &mut Request) -> IronResult<GraphQlQuery> {
|
||||
let mut request_payload = String::new();
|
||||
itry!(req.body.read_to_string(&mut request_payload));
|
||||
let graphql_query = serde_json::from_str::<GraphQlQuery>(request_payload.as_str()).map_err(|err|{
|
||||
IronError::new(
|
||||
Box::new(GraphQlIronError::Serde(err)),
|
||||
(status::BadRequest, "No JSON object was decoded."))
|
||||
});
|
||||
graphql_query
|
||||
}
|
||||
|
||||
fn respond(&self, req: &mut Request, graphql: GraphQlQuery) -> IronResult<Response> {
|
||||
let context = (self.context_factory)(req);
|
||||
let variables = graphql.variables();
|
||||
let result = execute(graphql.query(),
|
||||
graphql.operation_name(),
|
||||
&self.root_node,
|
||||
&variables,
|
||||
&context);
|
||||
let content_type = "application/json".parse::<Mime>().unwrap();
|
||||
if result.is_ok() {
|
||||
let response = WrappedGraphQLResult::new(result);
|
||||
let json = serde_json::to_string_pretty(&response).unwrap();
|
||||
Ok(Response::with((content_type, status::Ok, json)))
|
||||
} else {
|
||||
let response = WrappedGraphQLResult::new(result);
|
||||
let json = serde_json::to_string_pretty(&response).unwrap();
|
||||
Ok(Response::with((content_type, status::BadRequest, json)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GraphiQLHandler {
|
||||
|
@ -156,10 +190,16 @@ impl<'a, CtxFactory, Query, Mutation, CtxT>
|
|||
Query: GraphQLType<Context=CtxT> + Send + Sync + 'static,
|
||||
Mutation: GraphQLType<Context=CtxT> + Send + Sync + 'static, 'a: 'static,
|
||||
{
|
||||
fn handle(&self, req: &mut Request) -> IronResult<Response> {
|
||||
fn handle(&self, mut req: &mut Request) -> IronResult<Response> {
|
||||
match req.method {
|
||||
method::Get => self.handle_get(req),
|
||||
method::Post => self.handle_post(req),
|
||||
method::Get => {
|
||||
let graphql_query = self.handle_get(&mut req)?;
|
||||
self.respond(&mut req, graphql_query)
|
||||
}
|
||||
method::Post => {
|
||||
let graphql_query = self.handle_post(&mut req)?;
|
||||
self.respond(&mut req, graphql_query)
|
||||
},
|
||||
_ => Ok(Response::with((status::MethodNotAllowed)))
|
||||
}
|
||||
}
|
||||
|
@ -179,7 +219,6 @@ impl Handler for GraphiQLHandler {
|
|||
}
|
||||
</style>
|
||||
"#;
|
||||
|
||||
let fetcher_source = r#"
|
||||
<script>
|
||||
function graphQLFetcher(params) {
|
||||
|
@ -236,11 +275,62 @@ impl Handler for GraphiQLHandler {
|
|||
}
|
||||
}
|
||||
|
||||
/// A general error allowing the developer to see the underlying issue.
|
||||
#[derive(Debug)]
|
||||
pub enum GraphQlIronError {
|
||||
///Captures any errors that were caused by Serde.
|
||||
Serde(SerdeError),
|
||||
/// Captures any error related the IO.
|
||||
IO(IoError),
|
||||
/// Captures any error related to Url Decoding,
|
||||
Url(UrlDecodingError)
|
||||
}
|
||||
|
||||
impl fmt::Display for GraphQlIronError {
|
||||
fn fmt(&self, mut f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
GraphQlIronError::Serde(ref err) => fmt::Display::fmt(err, &mut f),
|
||||
GraphQlIronError::IO(ref err) => fmt::Display::fmt(err, &mut f),
|
||||
GraphQlIronError::Url(ref err) => fmt::Display::fmt(err, &mut f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for GraphQlIronError {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
GraphQlIronError::Serde(ref err) => {
|
||||
err.description()
|
||||
},
|
||||
GraphQlIronError::IO(ref err) => {
|
||||
err.description()
|
||||
}
|
||||
GraphQlIronError::Url(ref err) => {
|
||||
err.description()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&Error> {
|
||||
match *self {
|
||||
GraphQlIronError::Serde(ref err) => {
|
||||
err.cause()
|
||||
}
|
||||
GraphQlIronError::IO(ref err) => {
|
||||
err.cause()
|
||||
}
|
||||
GraphQlIronError::Url(ref err) => {
|
||||
err.cause()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rustc_serialize::json::Json;
|
||||
|
||||
use serde_json::Value as Json;
|
||||
use serde_json;
|
||||
use iron::prelude::*;
|
||||
use iron::status;
|
||||
use iron::headers;
|
||||
|
@ -267,7 +357,7 @@ mod tests {
|
|||
fn unwrap_json_response(resp: Response) -> Json {
|
||||
let result = response::extract_body_to_string(resp);
|
||||
|
||||
Json::from_str(&result).expect("Could not parse JSON object")
|
||||
serde_json::from_str::<Json>(&result).expect("Could not parse JSON object")
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -286,10 +376,77 @@ mod tests {
|
|||
|
||||
assert_eq!(
|
||||
json,
|
||||
Json::from_str(r#"{"data": {"hero": {"name": "R2-D2"}}}"#)
|
||||
serde_json::from_str::<Json>(r#"{"data": {"hero": {"name": "R2-D2"}}}"#)
|
||||
.expect("Invalid JSON constant in test"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encoded_get() {
|
||||
let response = request::get(
|
||||
"http://localhost:3000/?query=query%20{%20%20%20human(id:%20\"1000\")%20{%20%20%20%20%20id,%20%20%20%20%20name,%20%20%20%20%20appearsIn,%20%20%20%20%20homePlanet%20%20%20}%20}",
|
||||
Headers::new(),
|
||||
&make_handler())
|
||||
.expect("Unexpected IronError");
|
||||
|
||||
assert_eq!(response.status, Some(status::Ok));
|
||||
assert_eq!(response.headers.get::<headers::ContentType>(),
|
||||
Some(&headers::ContentType::json()));
|
||||
|
||||
let json = unwrap_json_response(response);
|
||||
|
||||
assert_eq!(
|
||||
json,
|
||||
serde_json::from_str::<Json>(r#"{
|
||||
"data": {
|
||||
"human": {
|
||||
"appearsIn": [
|
||||
"NEW_HOPE",
|
||||
"EMPIRE",
|
||||
"JEDI"
|
||||
],
|
||||
"homePlanet": "Tatooine",
|
||||
"name": "Luke Skywalker",
|
||||
"id": "1000"
|
||||
}
|
||||
}
|
||||
}"#)
|
||||
.expect("Invalid JSON constant in test"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_with_variables() {
|
||||
let response = request::get(
|
||||
"http://localhost:3000/?query=query($id:%20String!)%20{%20%20%20human(id:%20$id)%20{%20%20%20%20%20id,%20%20%20%20%20name,%20%20%20%20%20appearsIn,%20%20%20%20%20homePlanet%20%20%20}%20}&variables={%20%20%20\"id\":%20%20\"1000\"%20}",
|
||||
Headers::new(),
|
||||
&make_handler())
|
||||
.expect("Unexpected IronError");
|
||||
|
||||
assert_eq!(response.status, Some(status::Ok));
|
||||
assert_eq!(response.headers.get::<headers::ContentType>(),
|
||||
Some(&headers::ContentType::json()));
|
||||
|
||||
let json = unwrap_json_response(response);
|
||||
|
||||
assert_eq!(
|
||||
json,
|
||||
serde_json::from_str::<Json>(r#"{
|
||||
"data": {
|
||||
"human": {
|
||||
"appearsIn": [
|
||||
"NEW_HOPE",
|
||||
"EMPIRE",
|
||||
"JEDI"
|
||||
],
|
||||
"homePlanet": "Tatooine",
|
||||
"name": "Luke Skywalker",
|
||||
"id": "1000"
|
||||
}
|
||||
}
|
||||
}"#)
|
||||
.expect("Invalid JSON constant in test"));
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_simple_post() {
|
||||
let response = request::post(
|
||||
|
@ -307,7 +464,7 @@ mod tests {
|
|||
|
||||
assert_eq!(
|
||||
json,
|
||||
Json::from_str(r#"{"data": {"hero": {"name": "R2-D2"}}}"#)
|
||||
serde_json::from_str::<Json>(r#"{"data": {"hero": {"name": "R2-D2"}}}"#)
|
||||
.expect("Invalid JSON constant in test"));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
#[cfg(feature="iron-handlers")] pub mod iron_handlers;
|
||||
#[cfg(feature="rustc-serialize")] pub mod rustc_serialize;
|
||||
#[cfg(feature="serde")] pub mod serde;
|
||||
pub mod serde;
|
||||
|
|
|
@ -1,114 +0,0 @@
|
|||
use rustc_serialize::json::{ToJson, Json};
|
||||
|
||||
use ::{GraphQLError, Value};
|
||||
use ast::InputValue;
|
||||
use executor::ExecutionError;
|
||||
use parser::{ParseError, Spanning, SourcePosition};
|
||||
use validation::RuleError;
|
||||
|
||||
fn parse_error_to_json(err: &Spanning<ParseError>) -> Json {
|
||||
Json::Array(vec![
|
||||
Json::Object(vec![
|
||||
("message".to_owned(), format!("{}", err.item).to_json()),
|
||||
("locations".to_owned(), vec![
|
||||
Json::Object(vec![
|
||||
("line".to_owned(), (err.start.line() + 1).to_json()),
|
||||
("column".to_owned(), (err.start.column() + 1).to_json())
|
||||
].into_iter().collect()),
|
||||
].to_json()),
|
||||
].into_iter().collect()),
|
||||
])
|
||||
}
|
||||
|
||||
impl ToJson for ExecutionError {
|
||||
fn to_json(&self) -> Json {
|
||||
Json::Object(vec![
|
||||
("message".to_owned(), self.message().to_json()),
|
||||
("locations".to_owned(), vec![self.location().clone()].to_json()),
|
||||
("path".to_owned(), self.path().to_json()),
|
||||
].into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToJson for GraphQLError<'a> {
|
||||
fn to_json(&self) -> Json {
|
||||
match *self {
|
||||
GraphQLError::ParseError(ref err) => parse_error_to_json(err),
|
||||
GraphQLError::ValidationError(ref errs) => errs.to_json(),
|
||||
GraphQLError::MultipleOperationsProvided => Json::String(
|
||||
"Must provide operation name if query contains multiple operations".to_owned()),
|
||||
GraphQLError::NoOperationProvided => Json::String(
|
||||
"Must provide an operation".to_owned()),
|
||||
GraphQLError::UnknownOperationName => Json::String(
|
||||
"Unknown operation".to_owned()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for InputValue {
|
||||
fn to_json(&self) -> Json {
|
||||
match *self {
|
||||
InputValue::Null | InputValue::Variable(_) => Json::Null,
|
||||
InputValue::Int(i) => Json::I64(i),
|
||||
InputValue::Float(f) => Json::F64(f),
|
||||
InputValue::String(ref s) | InputValue::Enum(ref s) => Json::String(s.clone()),
|
||||
InputValue::Boolean(b) => Json::Boolean(b),
|
||||
InputValue::List(ref l) => Json::Array(l.iter().map(|x| x.item.to_json()).collect()),
|
||||
InputValue::Object(ref o) => Json::Object(o.iter().map(|&(ref k, ref v)| (k.item.clone(), v.item.to_json())).collect()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InputValue {
|
||||
/// Convert a `Json` structure into an `InputValue`.
|
||||
///
|
||||
/// This consumes the JSON instance.
|
||||
///
|
||||
/// Notes:
|
||||
/// * No enums or variables will be produced by this method.
|
||||
/// * All lists and objects will be unlocated
|
||||
pub fn from_json(json: Json) -> InputValue {
|
||||
match json {
|
||||
Json::I64(i) => InputValue::int(i),
|
||||
Json::U64(u) => InputValue::float(u as f64),
|
||||
Json::F64(f) => InputValue::float(f),
|
||||
Json::String(s) => InputValue::string(s),
|
||||
Json::Boolean(b) => InputValue::boolean(b),
|
||||
Json::Array(a) => InputValue::list(a.into_iter().map(InputValue::from_json).collect()),
|
||||
Json::Object(o) => InputValue::object(o.into_iter().map(|(k, v)| (k, InputValue::from_json(v))).collect()),
|
||||
Json::Null => InputValue::null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for RuleError {
|
||||
fn to_json(&self) -> Json {
|
||||
Json::Object(vec![
|
||||
("message".to_owned(), self.message().to_json()),
|
||||
("locations".to_owned(), self.locations().to_json()),
|
||||
].into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for SourcePosition {
|
||||
fn to_json(&self) -> Json {
|
||||
Json::Object(vec![
|
||||
("line".to_owned(), (self.line() + 1).to_json()),
|
||||
("column".to_owned(), (self.column() + 1).to_json()),
|
||||
].into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for Value {
|
||||
fn to_json(&self) -> Json {
|
||||
match *self {
|
||||
Value::Null => Json::Null,
|
||||
Value::Int(i) => Json::I64(i),
|
||||
Value::Float(f) => Json::F64(f),
|
||||
Value::String(ref s) => Json::String(s.clone()),
|
||||
Value::Boolean(b) => Json::Boolean(b),
|
||||
Value::List(ref l) => Json::Array(l.iter().map(|x| x.to_json()).collect()),
|
||||
Value::Object(ref o) => Json::Object(o.iter().map(|(k,v)| (k.clone(), v.to_json())).collect()),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,17 @@
|
|||
use serde::{de, ser};
|
||||
use serde::ser::SerializeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use ::{GraphQLError, Value};
|
||||
#[cfg(feature="iron-handlers")]
|
||||
use ::Variables;
|
||||
use ast::InputValue;
|
||||
use executor::ExecutionError;
|
||||
use parser::{ParseError, Spanning, SourcePosition};
|
||||
use validation::RuleError;
|
||||
|
||||
|
||||
impl ser::Serialize for ExecutionError {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: ser::Serializer,
|
||||
|
@ -213,3 +216,87 @@ impl ser::Serialize for Value {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The expected structure of the decoded JSON Document for either Post or Get requests.
|
||||
#[cfg(feature="iron-handlers")]
|
||||
#[derive(Deserialize)]
|
||||
pub struct GraphQlQuery {
|
||||
query: String,
|
||||
#[serde(rename = "operationName")]
|
||||
operation_name: Option<String>,
|
||||
variables: Option<InputValue>
|
||||
}
|
||||
|
||||
#[cfg(feature="iron-handlers")]
|
||||
impl GraphQlQuery {
|
||||
|
||||
pub fn new(query: String,
|
||||
operation_name: Option<String>,
|
||||
variables: Option<InputValue>
|
||||
) -> GraphQlQuery {
|
||||
GraphQlQuery {
|
||||
query: query,
|
||||
operation_name: operation_name,
|
||||
variables: variables
|
||||
}
|
||||
}
|
||||
|
||||
pub fn query(&self) -> &str {
|
||||
self.query.as_str()
|
||||
}
|
||||
|
||||
pub fn operation_name(&self) -> Option<&str> {
|
||||
self.operation_name.as_ref().map(|oper_name| &**oper_name)
|
||||
}
|
||||
|
||||
pub fn variables(&self) -> Variables {
|
||||
self.variables.as_ref().and_then(|iv| {
|
||||
iv.to_object_value().map(|o| {
|
||||
o.into_iter().map(|(k, v)| (k.to_owned(), v.clone())).collect()
|
||||
})
|
||||
}).unwrap_or_default()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#[cfg(feature="iron-handlers")]
|
||||
pub struct WrappedGraphQLResult<'a>(Result<(Value, Vec<ExecutionError>), GraphQLError<'a>>);
|
||||
|
||||
#[cfg(feature="iron-handlers")]
|
||||
impl<'a> WrappedGraphQLResult<'a> {
|
||||
pub fn new(result: Result<(Value, Vec<ExecutionError>),
|
||||
GraphQLError<'a>>
|
||||
) -> WrappedGraphQLResult<'a> {
|
||||
WrappedGraphQLResult(result)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="iron-handlers")]
|
||||
impl<'a> ser::Serialize for WrappedGraphQLResult<'a> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: ser::Serializer,
|
||||
{
|
||||
match self.0 {
|
||||
Ok((ref res, ref err)) => {
|
||||
let mut map = try!(serializer.serialize_map(None));
|
||||
|
||||
try!(map.serialize_key("data"));
|
||||
try!(map.serialize_value(res));
|
||||
|
||||
if !err.is_empty() {
|
||||
try!(map.serialize_key("errors"));
|
||||
try!(map.serialize_value(err));
|
||||
}
|
||||
|
||||
map.end()
|
||||
},
|
||||
Err(ref err) => {
|
||||
let mut map = try!(serializer.serialize_map(Some(1)));
|
||||
try!(map.serialize_key("errors"));
|
||||
try!(map.serialize_value(err));
|
||||
map.end()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
12
src/lib.rs
12
src/lib.rs
|
@ -14,7 +14,7 @@ schema, as well as an optional integration into the [Iron framework][2]. It
|
|||
tries to keep the number of dynamic operations to a minimum, and give you as the
|
||||
schema developer the control of the query execution path.
|
||||
|
||||
Juniper only depends on `rustc-serialize` by default, making it lightweight and
|
||||
Juniper only depends on `serde` and `serde_json` by default, making it lightweight and
|
||||
easy to drop into any project. Through the `iron-handlers` feature, it also
|
||||
depends on Iron.
|
||||
|
||||
|
@ -185,13 +185,13 @@ built-in [GraphiQL][6] handler included.
|
|||
|
||||
#![cfg_attr(feature="nightly", feature(test))]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
#[cfg(feature="rustc-serialize")] extern crate rustc_serialize;
|
||||
#[cfg(feature="serde")] extern crate serde;
|
||||
|
||||
#[cfg(feature="nightly")] extern crate test;
|
||||
#[cfg(feature="iron-handlers")] #[macro_use(itry, iexpect)] extern crate iron;
|
||||
#[cfg(feature="iron-handlers")] #[macro_use(itry)] extern crate iron;
|
||||
#[cfg(feature="iron-handlers")] extern crate urlencoded;
|
||||
#[cfg(test)] extern crate iron_test;
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
#[cfg(feature="iron-handlers")] #[macro_use] extern crate serde_derive;
|
||||
|
||||
#[macro_use] mod macros;
|
||||
mod ast;
|
||||
|
|
Loading…
Reference in a new issue