Extract general HTTP/JSON functions from Iron integration
This commit is contained in:
parent
cac5dd17c3
commit
a7a6778b18
5 changed files with 237 additions and 271 deletions
64
src/graphiql.rs
Normal file
64
src/graphiql.rs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
pub fn graphiql_source(graphql_endpoint_url: &str) -> String {
|
||||||
|
let stylesheet_source = r#"
|
||||||
|
<style>
|
||||||
|
html, body, #app {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
"#;
|
||||||
|
let fetcher_source = r#"
|
||||||
|
<script>
|
||||||
|
function graphQLFetcher(params) {
|
||||||
|
return fetch(GRAPHQL_URL, {
|
||||||
|
method: 'post',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(params)
|
||||||
|
}).then(function (response) {
|
||||||
|
return response.text();
|
||||||
|
}).then(function (body) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(body);
|
||||||
|
} catch (error) {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ReactDOM.render(
|
||||||
|
React.createElement(GraphiQL, {
|
||||||
|
fetcher: graphQLFetcher,
|
||||||
|
}),
|
||||||
|
document.querySelector('#app'));
|
||||||
|
</script>
|
||||||
|
"#;
|
||||||
|
|
||||||
|
format!(r#"
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>GraphQL</title>
|
||||||
|
{stylesheet_source}
|
||||||
|
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/graphiql/0.8.1/graphiql.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/fetch/2.0.1/fetch.js"></script>
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react.js"></script>
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react-dom.js"></script>
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/graphiql/0.8.1/graphiql.js"></script>
|
||||||
|
<script>var GRAPHQL_URL = '{graphql_url}';</script>
|
||||||
|
{fetcher_source}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"#,
|
||||||
|
graphql_url = graphql_endpoint_url,
|
||||||
|
stylesheet_source = stylesheet_source,
|
||||||
|
fetcher_source = fetcher_source)
|
||||||
|
|
||||||
|
}
|
92
src/http.rs
Normal file
92
src/http.rs
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
use serde::ser;
|
||||||
|
use serde::ser::SerializeMap;
|
||||||
|
|
||||||
|
use ::{GraphQLError, Value, Variables, GraphQLType, RootNode};
|
||||||
|
use ast::InputValue;
|
||||||
|
use executor::ExecutionError;
|
||||||
|
|
||||||
|
/// The expected structure of the decoded JSON Document for either Post or Get requests.
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct GraphQLRequest {
|
||||||
|
query: String,
|
||||||
|
#[serde(rename = "operationName")]
|
||||||
|
operation_name: Option<String>,
|
||||||
|
variables: Option<InputValue>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GraphQLRequest {
|
||||||
|
fn operation_name(&self) -> Option<&str> {
|
||||||
|
self.operation_name.as_ref().map(|oper_name| &**oper_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(query: String, operation_name: Option<String>, variables: Option<InputValue>) -> GraphQLRequest {
|
||||||
|
GraphQLRequest {
|
||||||
|
query: query,
|
||||||
|
operation_name: operation_name,
|
||||||
|
variables: variables,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute<'a, CtxT, QueryT, MutationT>(
|
||||||
|
&'a self,
|
||||||
|
root_node: &RootNode<QueryT, MutationT>,
|
||||||
|
context: &CtxT,
|
||||||
|
)
|
||||||
|
-> GraphQLResponse<'a>
|
||||||
|
where QueryT: GraphQLType<Context=CtxT>,
|
||||||
|
MutationT: GraphQLType<Context=CtxT>,
|
||||||
|
{
|
||||||
|
GraphQLResponse(::execute(
|
||||||
|
&self.query,
|
||||||
|
self.operation_name(),
|
||||||
|
root_node,
|
||||||
|
&self.variables(),
|
||||||
|
context,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct GraphQLResponse<'a>(Result<(Value, Vec<ExecutionError>), GraphQLError<'a>>);
|
||||||
|
|
||||||
|
impl<'a> GraphQLResponse<'a> {
|
||||||
|
pub fn is_ok(&self) -> bool {
|
||||||
|
self.0.is_ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ser::Serialize for GraphQLResponse<'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()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,17 +7,14 @@ use iron::method;
|
||||||
use urlencoded::{UrlEncodedQuery, UrlDecodingError};
|
use urlencoded::{UrlEncodedQuery, UrlDecodingError};
|
||||||
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::io::Error as IoError;
|
|
||||||
use std::io::ErrorKind;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::boxed::Box;
|
|
||||||
|
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use serde_json::error::Error as SerdeError;
|
use serde_json::error::Error as SerdeError;
|
||||||
|
|
||||||
use ::{InputValue, GraphQLType, RootNode, execute};
|
use ::{InputValue, GraphQLType, RootNode};
|
||||||
use super::serde::{WrappedGraphQLResult, GraphQLQuery};
|
use ::http;
|
||||||
|
|
||||||
/// Handler that executes GraphQL queries in the given schema
|
/// Handler that executes GraphQL queries in the given schema
|
||||||
///
|
///
|
||||||
|
@ -45,45 +42,29 @@ pub struct GraphiQLHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Get queries are allowed to repeat the same key more than once.
|
fn get_single_value<T>(mut values: Vec<T>) -> IronResult<T> {
|
||||||
fn check_for_repeat_keys(params: &Vec<String>) -> Result<(), IronError> {
|
if values.len() == 1 {
|
||||||
if params.len() > 1 {
|
Ok(values.remove(0))
|
||||||
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 {
|
else {
|
||||||
Ok(())
|
Err(GraphQLIronError::InvalidData("Duplicate URL query parameter").into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_url_param(param: Option<Vec<String>>) -> Result<Option<String>, IronError> {
|
fn parse_url_param(params: Option<Vec<String>>) -> IronResult<Option<String>> {
|
||||||
if let Some(values) = param {
|
if let Some(values) = params {
|
||||||
check_for_repeat_keys(&values)?;
|
get_single_value(values).map(Some)
|
||||||
Ok(Some(values[0].to_owned()))
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_variable_param(param: Option<Vec<String>>) -> Result<Option<InputValue>, IronError> {
|
fn parse_variable_param(params: Option<Vec<String>>) -> IronResult<Option<InputValue>> {
|
||||||
if let Some(values) = param {
|
if let Some(values) = params {
|
||||||
check_for_repeat_keys(&values)?;
|
Ok(serde_json::from_str::<InputValue>(get_single_value(values)?.as_ref())
|
||||||
match serde_json::from_str::<InputValue>(values[0].as_ref()) {
|
.map(Some)
|
||||||
Ok(input_values) => {
|
.map_err(GraphQLIronError::Serde)?)
|
||||||
Ok(Some(input_values))
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
Err(IronError::new(
|
|
||||||
Box::new(GraphQlIronError::Serde(err)),
|
|
||||||
(status::BadRequest, "No JSON object was decoded.")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
@ -112,62 +93,36 @@ impl<'a, CtxFactory, Query, Mutation, CtxT>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn handle_get(&self, req: &mut Request) -> IronResult<GraphQLQuery> {
|
fn handle_get(&self, req: &mut Request) -> IronResult<http::GraphQLRequest> {
|
||||||
match req.get_mut::<UrlEncodedQuery>() {
|
let url_query_string = req.get_mut::<UrlEncodedQuery>()
|
||||||
Ok(ref mut query_string) => {
|
.map_err(|e| GraphQLIronError::Url(e))?;
|
||||||
let input_query = parse_url_param(query_string.remove("query").to_owned())?;
|
|
||||||
if let Some(query) = input_query {
|
let input_query = parse_url_param(url_query_string.remove("query"))?
|
||||||
let operation_name =
|
.ok_or_else(|| GraphQLIronError::InvalidData("No query provided"))?;
|
||||||
parse_url_param(query_string.remove("operationName"))?;
|
let operation_name = parse_url_param(url_query_string.remove("operationName"))?;
|
||||||
let input_variables =
|
let variables = parse_variable_param(url_query_string.remove("variables"))?;
|
||||||
parse_variable_param(query_string.remove("variables"))?;
|
|
||||||
Ok(GraphQLQuery::new(query,operation_name,input_variables))
|
Ok(http::GraphQLRequest::new(input_query, operation_name, 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.")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
Err(IronError::new(
|
|
||||||
Box::new(GraphQlIronError::Url(err)),
|
|
||||||
(status::BadRequest, "No JSON object was decoded.")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_post(&self, req: &mut Request) -> IronResult<GraphQLQuery> {
|
fn handle_post(&self, req: &mut Request) -> IronResult<http::GraphQLRequest> {
|
||||||
let mut request_payload = String::new();
|
let mut request_payload = String::new();
|
||||||
itry!(req.body.read_to_string(&mut request_payload));
|
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(
|
Ok(serde_json::from_str::<http::GraphQLRequest>(request_payload.as_str())
|
||||||
Box::new(GraphQlIronError::Serde(err)),
|
.map_err(|err| GraphQLIronError::Serde(err))?)
|
||||||
(status::BadRequest, "No JSON object was decoded."))
|
|
||||||
});
|
|
||||||
graphql_query
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn respond(&self, req: &mut Request, graphql: GraphQLQuery) -> IronResult<Response> {
|
fn execute(&self, context: &CtxT, request: http::GraphQLRequest) -> IronResult<Response> {
|
||||||
let context = (self.context_factory)(req);
|
let response = request.execute(
|
||||||
let variables = graphql.variables();
|
&self.root_node,
|
||||||
let result = execute(graphql.query(),
|
context,
|
||||||
graphql.operation_name(),
|
);
|
||||||
&self.root_node,
|
let content_type = "application/json".parse::<Mime>().unwrap();
|
||||||
&variables,
|
let json = serde_json::to_string_pretty(&response).unwrap();
|
||||||
&context);
|
let status = if response.is_ok() { status::Ok } else { status::BadRequest };
|
||||||
let content_type = "application/json".parse::<Mime>().unwrap();
|
Ok(Response::with((content_type, status, json)))
|
||||||
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 {
|
impl GraphiQLHandler {
|
||||||
|
@ -191,17 +146,15 @@ impl<'a, CtxFactory, Query, Mutation, CtxT>
|
||||||
Mutation: GraphQLType<Context=CtxT> + Send + Sync + 'static, 'a: 'static,
|
Mutation: GraphQLType<Context=CtxT> + Send + Sync + 'static, 'a: 'static,
|
||||||
{
|
{
|
||||||
fn handle(&self, mut req: &mut Request) -> IronResult<Response> {
|
fn handle(&self, mut req: &mut Request) -> IronResult<Response> {
|
||||||
match req.method {
|
let context = (self.context_factory)(req);
|
||||||
method::Get => {
|
|
||||||
let graphql_query = self.handle_get(&mut req)?;
|
let graphql_request = match req.method {
|
||||||
self.respond(&mut req, graphql_query)
|
method::Get => self.handle_get(&mut req)?,
|
||||||
}
|
method::Post => self.handle_post(&mut req)?,
|
||||||
method::Post => {
|
_ => return Ok(Response::with((status::MethodNotAllowed)))
|
||||||
let graphql_query = self.handle_post(&mut req)?;
|
};
|
||||||
self.respond(&mut req, graphql_query)
|
|
||||||
},
|
self.execute(&context, graphql_request)
|
||||||
_ => Ok(Response::with((status::MethodNotAllowed)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,121 +162,54 @@ impl Handler for GraphiQLHandler {
|
||||||
fn handle(&self, _: &mut Request) -> IronResult<Response> {
|
fn handle(&self, _: &mut Request) -> IronResult<Response> {
|
||||||
let content_type = "text/html".parse::<Mime>().unwrap();
|
let content_type = "text/html".parse::<Mime>().unwrap();
|
||||||
|
|
||||||
let stylesheet_source = r#"
|
Ok(Response::with((
|
||||||
<style>
|
content_type,
|
||||||
html, body, #app {
|
status::Ok,
|
||||||
height: 100%;
|
::graphiql::graphiql_source(&self.graphql_url),
|
||||||
margin: 0;
|
)))
|
||||||
overflow: hidden;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
"#;
|
|
||||||
let fetcher_source = r#"
|
|
||||||
<script>
|
|
||||||
function graphQLFetcher(params) {
|
|
||||||
return fetch(GRAPHQL_URL, {
|
|
||||||
method: 'post',
|
|
||||||
headers: {
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify(params)
|
|
||||||
}).then(function (response) {
|
|
||||||
return response.text();
|
|
||||||
}).then(function (body) {
|
|
||||||
try {
|
|
||||||
return JSON.parse(body);
|
|
||||||
} catch (error) {
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
ReactDOM.render(
|
|
||||||
React.createElement(GraphiQL, {
|
|
||||||
fetcher: graphQLFetcher,
|
|
||||||
}),
|
|
||||||
document.querySelector('#app'));
|
|
||||||
</script>
|
|
||||||
"#;
|
|
||||||
|
|
||||||
let source = format!(r#"
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>GraphQL</title>
|
|
||||||
{stylesheet_source}
|
|
||||||
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/graphiql/0.8.1/graphiql.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="app"></div>
|
|
||||||
|
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/fetch/2.0.1/fetch.js"></script>
|
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react.js"></script>
|
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react-dom.js"></script>
|
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/graphiql/0.8.1/graphiql.js"></script>
|
|
||||||
<script>var GRAPHQL_URL = '{graphql_url}';</script>
|
|
||||||
{fetcher_source}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
"#,
|
|
||||||
graphql_url = self.graphql_url,
|
|
||||||
stylesheet_source = stylesheet_source,
|
|
||||||
fetcher_source = fetcher_source);
|
|
||||||
|
|
||||||
Ok(Response::with((content_type, status::Ok, source)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A general error allowing the developer to see the underlying issue.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum GraphQlIronError {
|
enum GraphQLIronError {
|
||||||
///Captures any errors that were caused by Serde.
|
|
||||||
Serde(SerdeError),
|
Serde(SerdeError),
|
||||||
/// Captures any error related the IO.
|
Url(UrlDecodingError),
|
||||||
IO(IoError),
|
InvalidData(&'static str),
|
||||||
/// Captures any error related to Url Decoding,
|
|
||||||
Url(UrlDecodingError)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for GraphQlIronError {
|
impl fmt::Display for GraphQLIronError {
|
||||||
fn fmt(&self, mut f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, mut f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
GraphQlIronError::Serde(ref err) => fmt::Display::fmt(err, &mut f),
|
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),
|
||||||
GraphQlIronError::Url(ref err) => fmt::Display::fmt(err, &mut f),
|
GraphQLIronError::InvalidData(ref err) => fmt::Display::fmt(err, &mut f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for GraphQlIronError {
|
impl Error for GraphQLIronError {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
match *self {
|
match *self {
|
||||||
GraphQlIronError::Serde(ref err) => {
|
GraphQLIronError::Serde(ref err) => err.description(),
|
||||||
err.description()
|
GraphQLIronError::Url(ref err) => err.description(),
|
||||||
},
|
GraphQLIronError::InvalidData(ref err) => err,
|
||||||
GraphQlIronError::IO(ref err) => {
|
|
||||||
err.description()
|
|
||||||
}
|
|
||||||
GraphQlIronError::Url(ref err) => {
|
|
||||||
err.description()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cause(&self) -> Option<&Error> {
|
fn cause(&self) -> Option<&Error> {
|
||||||
match *self {
|
match *self {
|
||||||
GraphQlIronError::Serde(ref err) => {
|
GraphQLIronError::Serde(ref err) => Some(err),
|
||||||
err.cause()
|
GraphQLIronError::Url(ref err) => Some(err),
|
||||||
}
|
GraphQLIronError::InvalidData(_) => None,
|
||||||
GraphQlIronError::IO(ref err) => {
|
}
|
||||||
err.cause()
|
}
|
||||||
}
|
}
|
||||||
GraphQlIronError::Url(ref err) => {
|
|
||||||
err.cause()
|
impl From<GraphQLIronError> for IronError {
|
||||||
}
|
fn from(err: GraphQLIronError) -> IronError {
|
||||||
}
|
let message = format!("{}", err);
|
||||||
}
|
IronError::new(err, (status::BadRequest, message))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use serde::ser::SerializeMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use ::{GraphQLError, Value, Variables};
|
use ::{GraphQLError, Value};
|
||||||
use ast::InputValue;
|
use ast::InputValue;
|
||||||
use executor::ExecutionError;
|
use executor::ExecutionError;
|
||||||
use parser::{ParseError, Spanning, SourcePosition};
|
use parser::{ParseError, Spanning, SourcePosition};
|
||||||
|
@ -223,81 +223,3 @@ impl ser::Serialize for Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The expected structure of the decoded JSON Document for either Post or Get requests.
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub struct GraphQLQuery {
|
|
||||||
query: String,
|
|
||||||
#[serde(rename = "operationName")]
|
|
||||||
operation_name: Option<String>,
|
|
||||||
variables: Option<InputValue>
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct WrappedGraphQLResult<'a>(Result<(Value, Vec<ExecutionError>), GraphQLError<'a>>);
|
|
||||||
|
|
||||||
impl<'a> WrappedGraphQLResult<'a> {
|
|
||||||
pub fn new(result: Result<(Value, Vec<ExecutionError>),
|
|
||||||
GraphQLError<'a>>
|
|
||||||
) -> WrappedGraphQLResult<'a> {
|
|
||||||
WrappedGraphQLResult(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -203,6 +203,8 @@ mod schema;
|
||||||
mod validation;
|
mod validation;
|
||||||
mod executor;
|
mod executor;
|
||||||
mod integrations;
|
mod integrations;
|
||||||
|
pub mod graphiql;
|
||||||
|
pub mod http;
|
||||||
#[macro_use] mod result_ext;
|
#[macro_use] mod result_ext;
|
||||||
|
|
||||||
#[cfg(all(test, not(feature="expose-test-schema")))] mod tests;
|
#[cfg(all(test, not(feature="expose-test-schema")))] mod tests;
|
||||||
|
|
Loading…
Reference in a new issue