juniper/juniper_rocket/src/lib.rs

542 lines
17 KiB
Rust
Raw Normal View History

/*!
# juniper_rocket
This repository contains the [Rocket][Rocket] web server integration for
[Juniper][Juniper], a [GraphQL][GraphQL] implementation for Rust.
## Documentation
For documentation, including guides and examples, check out [Juniper][Juniper].
A basic usage example can also be found in the [Api documentation][documentation].
## Examples
Check [examples/rocket_server.rs][example] for example code of a working Rocket
server with GraphQL handlers.
## Links
* [Juniper][Juniper]
* [Api Reference][documentation]
* [Rocket][Rocket]
## License
This project is under the BSD-2 license.
Check the LICENSE file for details.
[Rocket]: https://rocket.rs
[Juniper]: https://github.com/graphql-rust/juniper
[GraphQL]: http://graphql.org
[documentation]: https://docs.rs/juniper_rocket
[example]: https://github.com/graphql-rust/juniper_rocket/blob/master/examples/rocket_server.rs
*/
#![doc(html_root_url = "https://docs.rs/juniper_rocket/0.2.0")]
2019-08-21 10:22:16 +01:00
#![feature(decl_macro, proc_macro_hygiene)]
2020-01-29 02:50:28 -05:00
use std::io::{Cursor, Read};
use juniper::{
http::{self, GraphQLBatchRequest},
DefaultScalarValue, FieldError, GraphQLType, InputValue, RootNode, ScalarValue,
};
use rocket::{
data::{FromDataSimple, Outcome as FromDataOutcome},
http::{ContentType, RawStr, Status},
request::{FormItems, FromForm, FromFormValue},
response::{content, Responder, Response},
Data,
Outcome::{Forward, Success},
Request,
};
/// Simple wrapper around an incoming GraphQL request
///
/// See the `http` module for more information. This type can be constructed
/// automatically from both GET and POST routes by implementing the `FromForm`
/// and `FromData` traits.
#[derive(Debug, PartialEq)]
Introduce an abstraction for scalar values (#251) Introduce an abstraction for scalar values Before this change, possible scalar values were hard coded to be representable by one of the following types: `i32`, `f64`, `String` or `bool`. This restricts the types of custom scalar values that can be defined. For example, it was not possible to define a scalar value that represents an `i64` without mapping it to a string (which would be inefficient). One solution to fix the example above would simply be to change the internal representation to allow it to represent an `i64`, but this would only fix the problem for one type (until someone wants to support `i128` for example). Also this would make juniper not follow the GraphQL standard closely. This commit takes another approach, by making the exact "internal" representation of scalar values swappable (in such a way that a downstream crate could provide its own representation tailored to their needs). This allows juniper to provide a default type that only contains the types described in the standard whereas other crates could define custom scalars for their needs. To accomplish this we need to change several things in the current implementation: * Add some traits that abstract the behavior of such a scalar value representation * Change `Value` and `InputValue` to have a scalar variant (with a generic type) instead of hard coded variants for the standard types. This implies adding a generic parameter to both enums that needs to be added in the whole crate. * Change the parser to allow deciding between different types of scalar values. The problem is basically that the original parser implementation had no way to know whether a parsed integer number is a `i32` or a `i64` (for example). To fix this we added some knowledge of the existing schema to the parser. * Fix some macros and derives to follow the new behavior. This commit also contains an unrelated change about the way `juniper_codegen` resolves items from `juniper`. The `_internal` flag is removed and the resolution is replaced by a macro. The scalar parsing strategy is as follows: * Pass optional type information all the way down in the parser. If a field/type/… does note exist, just do not pass down the type information. * The lexer now distinguishes between several fundamental scalar types (`String`, `Float`, `Int`). It does not try to actually parse those values, instead it just annotates them that this is a floating point number, an integer number, or a string value, etc. * If type information exists while parsing a scalar value, try the following: 1. Try parsing the value using that type information. 2. If that fails try parsing the value using the inferred type information from the lexer. * If no type information exists, try parsing the scalar value using the inferred type from the lexer, All macros support the introduced scalar value abstraction. It is now possible to specify if a certain implementation should be based on a specific scalar value representation or be generic about the exact representation. All macros now default to the `DefaultScalarValue` type provided by `juniper` if no scalar value representation is specified. This is done with usability and backwards compatibility in mind. Finally, we allow specifying the scalar value representations via an attribute (`#[graphql(scalar = "Type")]`). A default generic implementation is provided.
2018-10-23 03:40:14 +00:00
pub struct GraphQLRequest<S = DefaultScalarValue>(GraphQLBatchRequest<S>)
where
S: ScalarValue;
/// Simple wrapper around the result of executing a GraphQL query
pub struct GraphQLResponse(pub Status, pub String);
/// Generate an HTML page containing GraphiQL
pub fn graphiql_source(
graphql_endpoint_url: &str,
subscriptions_endpoint: Option<&str>,
) -> content::Html<String> {
content::Html(juniper::http::graphiql::graphiql_source(
graphql_endpoint_url,
subscriptions_endpoint,
))
}
/// Generate an HTML page containing GraphQL Playground
2020-03-20 17:11:06 +01:00
pub fn playground_source(
graphql_endpoint_url: &str,
subscriptions_endpoint: Option<&str>,
) -> content::Html<String> {
content::Html(juniper::http::playground::playground_source(
graphql_endpoint_url,
2020-03-20 17:11:06 +01:00
subscriptions_endpoint,
))
}
Introduce an abstraction for scalar values (#251) Introduce an abstraction for scalar values Before this change, possible scalar values were hard coded to be representable by one of the following types: `i32`, `f64`, `String` or `bool`. This restricts the types of custom scalar values that can be defined. For example, it was not possible to define a scalar value that represents an `i64` without mapping it to a string (which would be inefficient). One solution to fix the example above would simply be to change the internal representation to allow it to represent an `i64`, but this would only fix the problem for one type (until someone wants to support `i128` for example). Also this would make juniper not follow the GraphQL standard closely. This commit takes another approach, by making the exact "internal" representation of scalar values swappable (in such a way that a downstream crate could provide its own representation tailored to their needs). This allows juniper to provide a default type that only contains the types described in the standard whereas other crates could define custom scalars for their needs. To accomplish this we need to change several things in the current implementation: * Add some traits that abstract the behavior of such a scalar value representation * Change `Value` and `InputValue` to have a scalar variant (with a generic type) instead of hard coded variants for the standard types. This implies adding a generic parameter to both enums that needs to be added in the whole crate. * Change the parser to allow deciding between different types of scalar values. The problem is basically that the original parser implementation had no way to know whether a parsed integer number is a `i32` or a `i64` (for example). To fix this we added some knowledge of the existing schema to the parser. * Fix some macros and derives to follow the new behavior. This commit also contains an unrelated change about the way `juniper_codegen` resolves items from `juniper`. The `_internal` flag is removed and the resolution is replaced by a macro. The scalar parsing strategy is as follows: * Pass optional type information all the way down in the parser. If a field/type/… does note exist, just do not pass down the type information. * The lexer now distinguishes between several fundamental scalar types (`String`, `Float`, `Int`). It does not try to actually parse those values, instead it just annotates them that this is a floating point number, an integer number, or a string value, etc. * If type information exists while parsing a scalar value, try the following: 1. Try parsing the value using that type information. 2. If that fails try parsing the value using the inferred type information from the lexer. * If no type information exists, try parsing the scalar value using the inferred type from the lexer, All macros support the introduced scalar value abstraction. It is now possible to specify if a certain implementation should be based on a specific scalar value representation or be generic about the exact representation. All macros now default to the `DefaultScalarValue` type provided by `juniper` if no scalar value representation is specified. This is done with usability and backwards compatibility in mind. Finally, we allow specifying the scalar value representations via an attribute (`#[graphql(scalar = "Type")]`). A default generic implementation is provided.
2018-10-23 03:40:14 +00:00
impl<S> GraphQLRequest<S>
where
S: ScalarValue,
Introduce an abstraction for scalar values (#251) Introduce an abstraction for scalar values Before this change, possible scalar values were hard coded to be representable by one of the following types: `i32`, `f64`, `String` or `bool`. This restricts the types of custom scalar values that can be defined. For example, it was not possible to define a scalar value that represents an `i64` without mapping it to a string (which would be inefficient). One solution to fix the example above would simply be to change the internal representation to allow it to represent an `i64`, but this would only fix the problem for one type (until someone wants to support `i128` for example). Also this would make juniper not follow the GraphQL standard closely. This commit takes another approach, by making the exact "internal" representation of scalar values swappable (in such a way that a downstream crate could provide its own representation tailored to their needs). This allows juniper to provide a default type that only contains the types described in the standard whereas other crates could define custom scalars for their needs. To accomplish this we need to change several things in the current implementation: * Add some traits that abstract the behavior of such a scalar value representation * Change `Value` and `InputValue` to have a scalar variant (with a generic type) instead of hard coded variants for the standard types. This implies adding a generic parameter to both enums that needs to be added in the whole crate. * Change the parser to allow deciding between different types of scalar values. The problem is basically that the original parser implementation had no way to know whether a parsed integer number is a `i32` or a `i64` (for example). To fix this we added some knowledge of the existing schema to the parser. * Fix some macros and derives to follow the new behavior. This commit also contains an unrelated change about the way `juniper_codegen` resolves items from `juniper`. The `_internal` flag is removed and the resolution is replaced by a macro. The scalar parsing strategy is as follows: * Pass optional type information all the way down in the parser. If a field/type/… does note exist, just do not pass down the type information. * The lexer now distinguishes between several fundamental scalar types (`String`, `Float`, `Int`). It does not try to actually parse those values, instead it just annotates them that this is a floating point number, an integer number, or a string value, etc. * If type information exists while parsing a scalar value, try the following: 1. Try parsing the value using that type information. 2. If that fails try parsing the value using the inferred type information from the lexer. * If no type information exists, try parsing the scalar value using the inferred type from the lexer, All macros support the introduced scalar value abstraction. It is now possible to specify if a certain implementation should be based on a specific scalar value representation or be generic about the exact representation. All macros now default to the `DefaultScalarValue` type provided by `juniper` if no scalar value representation is specified. This is done with usability and backwards compatibility in mind. Finally, we allow specifying the scalar value representations via an attribute (`#[graphql(scalar = "Type")]`). A default generic implementation is provided.
2018-10-23 03:40:14 +00:00
{
/// Execute an incoming GraphQL query
pub fn execute_sync<CtxT, QueryT, MutationT, SubscriptionT>(
&self,
root_node: &RootNode<QueryT, MutationT, SubscriptionT, S>,
context: &CtxT,
) -> GraphQLResponse
where
Introduce an abstraction for scalar values (#251) Introduce an abstraction for scalar values Before this change, possible scalar values were hard coded to be representable by one of the following types: `i32`, `f64`, `String` or `bool`. This restricts the types of custom scalar values that can be defined. For example, it was not possible to define a scalar value that represents an `i64` without mapping it to a string (which would be inefficient). One solution to fix the example above would simply be to change the internal representation to allow it to represent an `i64`, but this would only fix the problem for one type (until someone wants to support `i128` for example). Also this would make juniper not follow the GraphQL standard closely. This commit takes another approach, by making the exact "internal" representation of scalar values swappable (in such a way that a downstream crate could provide its own representation tailored to their needs). This allows juniper to provide a default type that only contains the types described in the standard whereas other crates could define custom scalars for their needs. To accomplish this we need to change several things in the current implementation: * Add some traits that abstract the behavior of such a scalar value representation * Change `Value` and `InputValue` to have a scalar variant (with a generic type) instead of hard coded variants for the standard types. This implies adding a generic parameter to both enums that needs to be added in the whole crate. * Change the parser to allow deciding between different types of scalar values. The problem is basically that the original parser implementation had no way to know whether a parsed integer number is a `i32` or a `i64` (for example). To fix this we added some knowledge of the existing schema to the parser. * Fix some macros and derives to follow the new behavior. This commit also contains an unrelated change about the way `juniper_codegen` resolves items from `juniper`. The `_internal` flag is removed and the resolution is replaced by a macro. The scalar parsing strategy is as follows: * Pass optional type information all the way down in the parser. If a field/type/… does note exist, just do not pass down the type information. * The lexer now distinguishes between several fundamental scalar types (`String`, `Float`, `Int`). It does not try to actually parse those values, instead it just annotates them that this is a floating point number, an integer number, or a string value, etc. * If type information exists while parsing a scalar value, try the following: 1. Try parsing the value using that type information. 2. If that fails try parsing the value using the inferred type information from the lexer. * If no type information exists, try parsing the scalar value using the inferred type from the lexer, All macros support the introduced scalar value abstraction. It is now possible to specify if a certain implementation should be based on a specific scalar value representation or be generic about the exact representation. All macros now default to the `DefaultScalarValue` type provided by `juniper` if no scalar value representation is specified. This is done with usability and backwards compatibility in mind. Finally, we allow specifying the scalar value representations via an attribute (`#[graphql(scalar = "Type")]`). A default generic implementation is provided.
2018-10-23 03:40:14 +00:00
QueryT: GraphQLType<S, Context = CtxT>,
MutationT: GraphQLType<S, Context = CtxT>,
SubscriptionT: GraphQLType<S, Context = CtxT>,
{
let response = self.0.execute_sync(root_node, context);
let status = if response.is_ok() {
Status::Ok
} else {
Status::BadRequest
};
let json = serde_json::to_string(&response).unwrap();
GraphQLResponse(status, json)
}
/// Returns the operation names associated with this request.
///
/// For batch requests there will be multiple names.
pub fn operation_names(&self) -> Vec<Option<&str>> {
self.0.operation_names()
}
}
impl GraphQLResponse {
/// Constructs an error response outside of the normal execution flow
///
/// # Examples
///
/// ```
/// # #![feature(decl_macro, proc_macro_hygiene)]
/// #
/// # use rocket::http::Cookies;
/// # use rocket::request::Form;
/// # use rocket::response::content;
/// # use rocket::State;
/// #
Make interfaces great again! (#682) * Bootstrap * Upd * Bootstrap macro * Revert stuff * Correct PoC to compile * Bootstrap #[graphql_interface] expansion * Bootstrap #[graphql_interface] meta parsing * Bootstrap #[graphql_interface] very basic code generation [skip ci] * Upd trait code generation and fix keywords usage [skip ci] * Expand trait impls [skip ci] * Tune up objects [skip ci] * Finally! Complies at least... [skip ci] * Parse meta for fields and its arguments [skip ci] - also, refactor and bikeshed new macros code * Impl filling fields meta and bootstrap field resolution [skip ci] * Poking with fields resolution [skip ci] * Solve Rust's teen async HRTB problems [skip ci] * Start parsing trait methods [skip ci] * Finish parsing fields from trait methods [skip ci] * Autodetect trait asyncness and allow to specify it [skip ci] * Allow to autogenerate trait object alias via attribute * Support generics in trait definition and asyncify them correctly * Temporary disable explicit async * Cover arguments and custom names/descriptions in tests * Re-enable tests with explicit async and fix the codegen to satisfy it * Check implementers are registered in schema and vice versa * Check argument camelCases * Test argument defaults, and allow Into coercions for them * Re-enable markers * Re-enable markers and relax Sized requirement on IsInputType/IsOutputType marker traits * Revert 'juniper_actix' fmt * Fix missing marks for object * Fix subscriptions marks * Deduce result type correctly via traits * Final fixes * Fmt * Restore marks checking * Support custom ScalarValue * Cover deprecations with tests * Impl dowcasting via methods * Impl dowcasting via external functions * Support custom context, vol. 1 * Support custom context, vol. 2 * Cover fallible field with test * Impl explicit generic ScalarValue, vol.1 * Impl explicit generic ScalarValue, vol.2 * Allow passing executor into methods * Generating enum, vol.1 * Generating enum, vol.2 * Generating enum, vol.3 * Generating enum, vol.3 * Generating enum, vol.4 * Generating enum, vol.5 * Generating enum, vol.6 * Generating enum, vol.7 * Generating enum, vol.8 * Refactor juniper stuff * Fix juniper tests, vol.1 * Fix juniper tests, vol.2 * Polish 'juniper' crate changes, vol.1 * Polish 'juniper' crate changes, vol.2 * Remove redundant stuf * Polishing 'juniper_codegen', vol.1 * Polishing 'juniper_codegen', vol.2 * Polishing 'juniper_codegen', vol.3 * Polishing 'juniper_codegen', vol.4 * Polishing 'juniper_codegen', vol.5 * Polishing 'juniper_codegen', vol.6 * Polishing 'juniper_codegen', vol.7 * Polishing 'juniper_codegen', vol.8 * Polishing 'juniper_codegen', vol.9 * Fix other crates tests and make Clippy happier * Fix examples * Add codegen failure tests, vol. 1 * Add codegen failure tests, vol. 2 * Add codegen failure tests, vol.3 * Fix codegen failure tests accordingly to latest nightly Rust * Fix codegen when interface has no implementers * Fix warnings in book tests * Describing new interfaces in Book, vol.1 Co-authored-by: Christian Legnitto <LegNeato@users.noreply.github.com>
2020-10-06 10:21:01 +03:00
/// # use juniper::tests::fixtures::starwars::schema::{Database, Query};
/// # use juniper::{EmptyMutation, EmptySubscription, FieldError, RootNode, Value};
/// #
/// # type Schema = RootNode<'static, Query, EmptyMutation<Database>, EmptySubscription<Database>>;
/// #
/// #[rocket::get("/graphql?<request..>")]
/// fn get_graphql_handler(
/// mut cookies: Cookies,
/// context: State<Database>,
/// request: Form<juniper_rocket::GraphQLRequest>,
/// schema: State<Schema>,
/// ) -> juniper_rocket::GraphQLResponse {
/// if cookies.get("user_id").is_none() {
/// let err = FieldError::new("User is not logged in", Value::null());
/// return juniper_rocket::GraphQLResponse::error(err);
/// }
///
/// request.execute_sync(&schema, &context)
/// }
/// ```
pub fn error(error: FieldError) -> Self {
let response = http::GraphQLResponse::error(error);
let json = serde_json::to_string(&response).unwrap();
GraphQLResponse(Status::BadRequest, json)
}
/// Constructs a custom response outside of the normal execution flow
///
/// This is intended for highly customized integrations and should only
/// be used as a last resort. For normal juniper use, use the response
/// from GraphQLRequest::execute_sync(..).
pub fn custom(status: Status, response: serde_json::Value) -> Self {
let json = serde_json::to_string(&response).unwrap();
GraphQLResponse(status, json)
}
}
Introduce an abstraction for scalar values (#251) Introduce an abstraction for scalar values Before this change, possible scalar values were hard coded to be representable by one of the following types: `i32`, `f64`, `String` or `bool`. This restricts the types of custom scalar values that can be defined. For example, it was not possible to define a scalar value that represents an `i64` without mapping it to a string (which would be inefficient). One solution to fix the example above would simply be to change the internal representation to allow it to represent an `i64`, but this would only fix the problem for one type (until someone wants to support `i128` for example). Also this would make juniper not follow the GraphQL standard closely. This commit takes another approach, by making the exact "internal" representation of scalar values swappable (in such a way that a downstream crate could provide its own representation tailored to their needs). This allows juniper to provide a default type that only contains the types described in the standard whereas other crates could define custom scalars for their needs. To accomplish this we need to change several things in the current implementation: * Add some traits that abstract the behavior of such a scalar value representation * Change `Value` and `InputValue` to have a scalar variant (with a generic type) instead of hard coded variants for the standard types. This implies adding a generic parameter to both enums that needs to be added in the whole crate. * Change the parser to allow deciding between different types of scalar values. The problem is basically that the original parser implementation had no way to know whether a parsed integer number is a `i32` or a `i64` (for example). To fix this we added some knowledge of the existing schema to the parser. * Fix some macros and derives to follow the new behavior. This commit also contains an unrelated change about the way `juniper_codegen` resolves items from `juniper`. The `_internal` flag is removed and the resolution is replaced by a macro. The scalar parsing strategy is as follows: * Pass optional type information all the way down in the parser. If a field/type/… does note exist, just do not pass down the type information. * The lexer now distinguishes between several fundamental scalar types (`String`, `Float`, `Int`). It does not try to actually parse those values, instead it just annotates them that this is a floating point number, an integer number, or a string value, etc. * If type information exists while parsing a scalar value, try the following: 1. Try parsing the value using that type information. 2. If that fails try parsing the value using the inferred type information from the lexer. * If no type information exists, try parsing the scalar value using the inferred type from the lexer, All macros support the introduced scalar value abstraction. It is now possible to specify if a certain implementation should be based on a specific scalar value representation or be generic about the exact representation. All macros now default to the `DefaultScalarValue` type provided by `juniper` if no scalar value representation is specified. This is done with usability and backwards compatibility in mind. Finally, we allow specifying the scalar value representations via an attribute (`#[graphql(scalar = "Type")]`). A default generic implementation is provided.
2018-10-23 03:40:14 +00:00
impl<'f, S> FromForm<'f> for GraphQLRequest<S>
where
S: ScalarValue,
Introduce an abstraction for scalar values (#251) Introduce an abstraction for scalar values Before this change, possible scalar values were hard coded to be representable by one of the following types: `i32`, `f64`, `String` or `bool`. This restricts the types of custom scalar values that can be defined. For example, it was not possible to define a scalar value that represents an `i64` without mapping it to a string (which would be inefficient). One solution to fix the example above would simply be to change the internal representation to allow it to represent an `i64`, but this would only fix the problem for one type (until someone wants to support `i128` for example). Also this would make juniper not follow the GraphQL standard closely. This commit takes another approach, by making the exact "internal" representation of scalar values swappable (in such a way that a downstream crate could provide its own representation tailored to their needs). This allows juniper to provide a default type that only contains the types described in the standard whereas other crates could define custom scalars for their needs. To accomplish this we need to change several things in the current implementation: * Add some traits that abstract the behavior of such a scalar value representation * Change `Value` and `InputValue` to have a scalar variant (with a generic type) instead of hard coded variants for the standard types. This implies adding a generic parameter to both enums that needs to be added in the whole crate. * Change the parser to allow deciding between different types of scalar values. The problem is basically that the original parser implementation had no way to know whether a parsed integer number is a `i32` or a `i64` (for example). To fix this we added some knowledge of the existing schema to the parser. * Fix some macros and derives to follow the new behavior. This commit also contains an unrelated change about the way `juniper_codegen` resolves items from `juniper`. The `_internal` flag is removed and the resolution is replaced by a macro. The scalar parsing strategy is as follows: * Pass optional type information all the way down in the parser. If a field/type/… does note exist, just do not pass down the type information. * The lexer now distinguishes between several fundamental scalar types (`String`, `Float`, `Int`). It does not try to actually parse those values, instead it just annotates them that this is a floating point number, an integer number, or a string value, etc. * If type information exists while parsing a scalar value, try the following: 1. Try parsing the value using that type information. 2. If that fails try parsing the value using the inferred type information from the lexer. * If no type information exists, try parsing the scalar value using the inferred type from the lexer, All macros support the introduced scalar value abstraction. It is now possible to specify if a certain implementation should be based on a specific scalar value representation or be generic about the exact representation. All macros now default to the `DefaultScalarValue` type provided by `juniper` if no scalar value representation is specified. This is done with usability and backwards compatibility in mind. Finally, we allow specifying the scalar value representations via an attribute (`#[graphql(scalar = "Type")]`). A default generic implementation is provided.
2018-10-23 03:40:14 +00:00
{
type Error = String;
fn from_form(form_items: &mut FormItems<'f>, strict: bool) -> Result<Self, String> {
let mut query = None;
let mut operation_name = None;
let mut variables = None;
for form_item in form_items {
let (key, value) = form_item.key_value();
// Note: we explicitly decode in the match arms to save work rather
// than decoding every form item blindly.
match key.as_str() {
"query" => {
if query.is_some() {
return Err("Query parameter must not occur more than once".to_owned());
} else {
match value.url_decode() {
Ok(v) => query = Some(v),
2020-01-29 02:45:17 -05:00
Err(e) => return Err(e.to_string()),
}
}
}
"operation_name" => {
if operation_name.is_some() {
2018-07-19 15:22:21 +02:00
return Err(
"Operation name parameter must not occur more than once".to_owned()
);
} else {
match value.url_decode() {
Ok(v) => operation_name = Some(v),
2020-01-29 02:45:17 -05:00
Err(e) => return Err(e.to_string()),
}
}
}
"variables" => {
if variables.is_some() {
2018-01-13 12:25:55 +01:00
return Err("Variables parameter must not occur more than once".to_owned());
} else {
let decoded;
match value.url_decode() {
Ok(v) => decoded = v,
2020-01-29 02:45:17 -05:00
Err(e) => return Err(e.to_string()),
}
Introduce an abstraction for scalar values (#251) Introduce an abstraction for scalar values Before this change, possible scalar values were hard coded to be representable by one of the following types: `i32`, `f64`, `String` or `bool`. This restricts the types of custom scalar values that can be defined. For example, it was not possible to define a scalar value that represents an `i64` without mapping it to a string (which would be inefficient). One solution to fix the example above would simply be to change the internal representation to allow it to represent an `i64`, but this would only fix the problem for one type (until someone wants to support `i128` for example). Also this would make juniper not follow the GraphQL standard closely. This commit takes another approach, by making the exact "internal" representation of scalar values swappable (in such a way that a downstream crate could provide its own representation tailored to their needs). This allows juniper to provide a default type that only contains the types described in the standard whereas other crates could define custom scalars for their needs. To accomplish this we need to change several things in the current implementation: * Add some traits that abstract the behavior of such a scalar value representation * Change `Value` and `InputValue` to have a scalar variant (with a generic type) instead of hard coded variants for the standard types. This implies adding a generic parameter to both enums that needs to be added in the whole crate. * Change the parser to allow deciding between different types of scalar values. The problem is basically that the original parser implementation had no way to know whether a parsed integer number is a `i32` or a `i64` (for example). To fix this we added some knowledge of the existing schema to the parser. * Fix some macros and derives to follow the new behavior. This commit also contains an unrelated change about the way `juniper_codegen` resolves items from `juniper`. The `_internal` flag is removed and the resolution is replaced by a macro. The scalar parsing strategy is as follows: * Pass optional type information all the way down in the parser. If a field/type/… does note exist, just do not pass down the type information. * The lexer now distinguishes between several fundamental scalar types (`String`, `Float`, `Int`). It does not try to actually parse those values, instead it just annotates them that this is a floating point number, an integer number, or a string value, etc. * If type information exists while parsing a scalar value, try the following: 1. Try parsing the value using that type information. 2. If that fails try parsing the value using the inferred type information from the lexer. * If no type information exists, try parsing the scalar value using the inferred type from the lexer, All macros support the introduced scalar value abstraction. It is now possible to specify if a certain implementation should be based on a specific scalar value representation or be generic about the exact representation. All macros now default to the `DefaultScalarValue` type provided by `juniper` if no scalar value representation is specified. This is done with usability and backwards compatibility in mind. Finally, we allow specifying the scalar value representations via an attribute (`#[graphql(scalar = "Type")]`). A default generic implementation is provided.
2018-10-23 03:40:14 +00:00
variables = Some(
serde_json::from_str::<InputValue<_>>(&decoded)
2020-01-29 02:45:17 -05:00
.map_err(|err| err.to_string())?,
Introduce an abstraction for scalar values (#251) Introduce an abstraction for scalar values Before this change, possible scalar values were hard coded to be representable by one of the following types: `i32`, `f64`, `String` or `bool`. This restricts the types of custom scalar values that can be defined. For example, it was not possible to define a scalar value that represents an `i64` without mapping it to a string (which would be inefficient). One solution to fix the example above would simply be to change the internal representation to allow it to represent an `i64`, but this would only fix the problem for one type (until someone wants to support `i128` for example). Also this would make juniper not follow the GraphQL standard closely. This commit takes another approach, by making the exact "internal" representation of scalar values swappable (in such a way that a downstream crate could provide its own representation tailored to their needs). This allows juniper to provide a default type that only contains the types described in the standard whereas other crates could define custom scalars for their needs. To accomplish this we need to change several things in the current implementation: * Add some traits that abstract the behavior of such a scalar value representation * Change `Value` and `InputValue` to have a scalar variant (with a generic type) instead of hard coded variants for the standard types. This implies adding a generic parameter to both enums that needs to be added in the whole crate. * Change the parser to allow deciding between different types of scalar values. The problem is basically that the original parser implementation had no way to know whether a parsed integer number is a `i32` or a `i64` (for example). To fix this we added some knowledge of the existing schema to the parser. * Fix some macros and derives to follow the new behavior. This commit also contains an unrelated change about the way `juniper_codegen` resolves items from `juniper`. The `_internal` flag is removed and the resolution is replaced by a macro. The scalar parsing strategy is as follows: * Pass optional type information all the way down in the parser. If a field/type/… does note exist, just do not pass down the type information. * The lexer now distinguishes between several fundamental scalar types (`String`, `Float`, `Int`). It does not try to actually parse those values, instead it just annotates them that this is a floating point number, an integer number, or a string value, etc. * If type information exists while parsing a scalar value, try the following: 1. Try parsing the value using that type information. 2. If that fails try parsing the value using the inferred type information from the lexer. * If no type information exists, try parsing the scalar value using the inferred type from the lexer, All macros support the introduced scalar value abstraction. It is now possible to specify if a certain implementation should be based on a specific scalar value representation or be generic about the exact representation. All macros now default to the `DefaultScalarValue` type provided by `juniper` if no scalar value representation is specified. This is done with usability and backwards compatibility in mind. Finally, we allow specifying the scalar value representations via an attribute (`#[graphql(scalar = "Type")]`). A default generic implementation is provided.
2018-10-23 03:40:14 +00:00
);
}
}
_ => {
if strict {
2020-03-13 23:02:43 -07:00
return Err(format!("Prohibited extra field '{}'", key));
}
}
}
}
if let Some(query) = query {
2018-07-19 15:22:21 +02:00
Ok(GraphQLRequest(GraphQLBatchRequest::Single(
http::GraphQLRequest::new(query, operation_name, variables),
)))
} else {
Err("Query parameter missing".to_owned())
}
}
}
impl<'v, S> FromFormValue<'v> for GraphQLRequest<S>
where
S: ScalarValue,
{
type Error = String;
fn from_form_value(form_value: &'v RawStr) -> Result<Self, Self::Error> {
let mut form_items = FormItems::from(form_value);
Self::from_form(&mut form_items, true)
}
}
impl<S> FromDataSimple for GraphQLRequest<S>
Introduce an abstraction for scalar values (#251) Introduce an abstraction for scalar values Before this change, possible scalar values were hard coded to be representable by one of the following types: `i32`, `f64`, `String` or `bool`. This restricts the types of custom scalar values that can be defined. For example, it was not possible to define a scalar value that represents an `i64` without mapping it to a string (which would be inefficient). One solution to fix the example above would simply be to change the internal representation to allow it to represent an `i64`, but this would only fix the problem for one type (until someone wants to support `i128` for example). Also this would make juniper not follow the GraphQL standard closely. This commit takes another approach, by making the exact "internal" representation of scalar values swappable (in such a way that a downstream crate could provide its own representation tailored to their needs). This allows juniper to provide a default type that only contains the types described in the standard whereas other crates could define custom scalars for their needs. To accomplish this we need to change several things in the current implementation: * Add some traits that abstract the behavior of such a scalar value representation * Change `Value` and `InputValue` to have a scalar variant (with a generic type) instead of hard coded variants for the standard types. This implies adding a generic parameter to both enums that needs to be added in the whole crate. * Change the parser to allow deciding between different types of scalar values. The problem is basically that the original parser implementation had no way to know whether a parsed integer number is a `i32` or a `i64` (for example). To fix this we added some knowledge of the existing schema to the parser. * Fix some macros and derives to follow the new behavior. This commit also contains an unrelated change about the way `juniper_codegen` resolves items from `juniper`. The `_internal` flag is removed and the resolution is replaced by a macro. The scalar parsing strategy is as follows: * Pass optional type information all the way down in the parser. If a field/type/… does note exist, just do not pass down the type information. * The lexer now distinguishes between several fundamental scalar types (`String`, `Float`, `Int`). It does not try to actually parse those values, instead it just annotates them that this is a floating point number, an integer number, or a string value, etc. * If type information exists while parsing a scalar value, try the following: 1. Try parsing the value using that type information. 2. If that fails try parsing the value using the inferred type information from the lexer. * If no type information exists, try parsing the scalar value using the inferred type from the lexer, All macros support the introduced scalar value abstraction. It is now possible to specify if a certain implementation should be based on a specific scalar value representation or be generic about the exact representation. All macros now default to the `DefaultScalarValue` type provided by `juniper` if no scalar value representation is specified. This is done with usability and backwards compatibility in mind. Finally, we allow specifying the scalar value representations via an attribute (`#[graphql(scalar = "Type")]`). A default generic implementation is provided.
2018-10-23 03:40:14 +00:00
where
S: ScalarValue,
Introduce an abstraction for scalar values (#251) Introduce an abstraction for scalar values Before this change, possible scalar values were hard coded to be representable by one of the following types: `i32`, `f64`, `String` or `bool`. This restricts the types of custom scalar values that can be defined. For example, it was not possible to define a scalar value that represents an `i64` without mapping it to a string (which would be inefficient). One solution to fix the example above would simply be to change the internal representation to allow it to represent an `i64`, but this would only fix the problem for one type (until someone wants to support `i128` for example). Also this would make juniper not follow the GraphQL standard closely. This commit takes another approach, by making the exact "internal" representation of scalar values swappable (in such a way that a downstream crate could provide its own representation tailored to their needs). This allows juniper to provide a default type that only contains the types described in the standard whereas other crates could define custom scalars for their needs. To accomplish this we need to change several things in the current implementation: * Add some traits that abstract the behavior of such a scalar value representation * Change `Value` and `InputValue` to have a scalar variant (with a generic type) instead of hard coded variants for the standard types. This implies adding a generic parameter to both enums that needs to be added in the whole crate. * Change the parser to allow deciding between different types of scalar values. The problem is basically that the original parser implementation had no way to know whether a parsed integer number is a `i32` or a `i64` (for example). To fix this we added some knowledge of the existing schema to the parser. * Fix some macros and derives to follow the new behavior. This commit also contains an unrelated change about the way `juniper_codegen` resolves items from `juniper`. The `_internal` flag is removed and the resolution is replaced by a macro. The scalar parsing strategy is as follows: * Pass optional type information all the way down in the parser. If a field/type/… does note exist, just do not pass down the type information. * The lexer now distinguishes between several fundamental scalar types (`String`, `Float`, `Int`). It does not try to actually parse those values, instead it just annotates them that this is a floating point number, an integer number, or a string value, etc. * If type information exists while parsing a scalar value, try the following: 1. Try parsing the value using that type information. 2. If that fails try parsing the value using the inferred type information from the lexer. * If no type information exists, try parsing the scalar value using the inferred type from the lexer, All macros support the introduced scalar value abstraction. It is now possible to specify if a certain implementation should be based on a specific scalar value representation or be generic about the exact representation. All macros now default to the `DefaultScalarValue` type provided by `juniper` if no scalar value representation is specified. This is done with usability and backwards compatibility in mind. Finally, we allow specifying the scalar value representations via an attribute (`#[graphql(scalar = "Type")]`). A default generic implementation is provided.
2018-10-23 03:40:14 +00:00
{
type Error = String;
fn from_data(req: &Request, data: Data) -> FromDataOutcome<Self, Self::Error> {
let content_type = req
.content_type()
.map(|ct| (ct.top().as_str(), ct.sub().as_str()));
let is_json = match content_type {
Some(("application", "json")) => true,
Some(("application", "graphql")) => false,
_ => return Forward(data),
};
let mut body = String::new();
data.open()
.read_to_string(&mut body)
.map_err(|e| (Status::InternalServerError, format!("{:?}", e)))?;
Success(GraphQLRequest(if is_json {
serde_json::from_str(&body).map_err(|e| (Status::BadRequest, format!("{}", e)))?
} else {
GraphQLBatchRequest::Single(http::GraphQLRequest::new(body, None, None))
}))
}
}
impl<'r> Responder<'r> for GraphQLResponse {
fn respond_to(self, _: &Request) -> 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())
}
}
#[cfg(test)]
mod fromform_tests {
use super::*;
use juniper::InputValue;
2018-01-13 12:25:55 +01:00
use rocket::request::{FormItems, FromForm};
2018-07-19 15:22:21 +02:00
use std::str;
fn check_error(input: &str, error: &str, strict: bool) {
let mut items = FormItems::from(input);
Introduce an abstraction for scalar values (#251) Introduce an abstraction for scalar values Before this change, possible scalar values were hard coded to be representable by one of the following types: `i32`, `f64`, `String` or `bool`. This restricts the types of custom scalar values that can be defined. For example, it was not possible to define a scalar value that represents an `i64` without mapping it to a string (which would be inefficient). One solution to fix the example above would simply be to change the internal representation to allow it to represent an `i64`, but this would only fix the problem for one type (until someone wants to support `i128` for example). Also this would make juniper not follow the GraphQL standard closely. This commit takes another approach, by making the exact "internal" representation of scalar values swappable (in such a way that a downstream crate could provide its own representation tailored to their needs). This allows juniper to provide a default type that only contains the types described in the standard whereas other crates could define custom scalars for their needs. To accomplish this we need to change several things in the current implementation: * Add some traits that abstract the behavior of such a scalar value representation * Change `Value` and `InputValue` to have a scalar variant (with a generic type) instead of hard coded variants for the standard types. This implies adding a generic parameter to both enums that needs to be added in the whole crate. * Change the parser to allow deciding between different types of scalar values. The problem is basically that the original parser implementation had no way to know whether a parsed integer number is a `i32` or a `i64` (for example). To fix this we added some knowledge of the existing schema to the parser. * Fix some macros and derives to follow the new behavior. This commit also contains an unrelated change about the way `juniper_codegen` resolves items from `juniper`. The `_internal` flag is removed and the resolution is replaced by a macro. The scalar parsing strategy is as follows: * Pass optional type information all the way down in the parser. If a field/type/… does note exist, just do not pass down the type information. * The lexer now distinguishes between several fundamental scalar types (`String`, `Float`, `Int`). It does not try to actually parse those values, instead it just annotates them that this is a floating point number, an integer number, or a string value, etc. * If type information exists while parsing a scalar value, try the following: 1. Try parsing the value using that type information. 2. If that fails try parsing the value using the inferred type information from the lexer. * If no type information exists, try parsing the scalar value using the inferred type from the lexer, All macros support the introduced scalar value abstraction. It is now possible to specify if a certain implementation should be based on a specific scalar value representation or be generic about the exact representation. All macros now default to the `DefaultScalarValue` type provided by `juniper` if no scalar value representation is specified. This is done with usability and backwards compatibility in mind. Finally, we allow specifying the scalar value representations via an attribute (`#[graphql(scalar = "Type")]`). A default generic implementation is provided.
2018-10-23 03:40:14 +00:00
let result: Result<GraphQLRequest, _> = GraphQLRequest::from_form(&mut items, strict);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), error);
}
#[test]
fn test_empty_form() {
check_error("", "Query parameter missing", false);
}
#[test]
fn test_no_query() {
2018-01-13 12:25:55 +01:00
check_error(
"operation_name=foo&variables={}",
"Query parameter missing",
false,
);
}
#[test]
fn test_strict() {
2018-01-13 12:25:55 +01:00
check_error("query=test&foo=bar", "Prohibited extra field \'foo\'", true);
}
#[test]
fn test_duplicate_query() {
check_error(
"query=foo&query=bar",
"Query parameter must not occur more than once",
false,
);
}
#[test]
fn test_duplicate_operation_name() {
check_error(
"query=test&operation_name=op1&operation_name=op2",
"Operation name parameter must not occur more than once",
false,
);
}
#[test]
fn test_duplicate_variables() {
check_error(
"query=test&variables={}&variables={}",
"Variables parameter must not occur more than once",
false,
);
}
#[test]
fn test_variables_invalid_json() {
2020-01-29 02:55:39 -05:00
check_error(
"query=test&variables=NOT_JSON",
"expected value at line 1 column 1",
false,
);
}
#[test]
fn test_variables_valid_json() {
let form_string = r#"query=test&variables={"foo":"bar"}"#;
let mut items = FormItems::from(form_string);
let result = GraphQLRequest::from_form(&mut items, false);
assert!(result.is_ok());
let variables = ::serde_json::from_str::<InputValue>(r#"{"foo":"bar"}"#).unwrap();
let expected = GraphQLRequest(GraphQLBatchRequest::Single(http::GraphQLRequest::new(
"test".to_string(),
None,
Some(variables),
)));
assert_eq!(result.unwrap(), expected);
}
#[test]
fn test_variables_encoded_json() {
let form_string = r#"query=test&variables={"foo": "x%20y%26%3F+z"}"#;
let mut items = FormItems::from(form_string);
let result = GraphQLRequest::from_form(&mut items, false);
assert!(result.is_ok());
let variables = ::serde_json::from_str::<InputValue>(r#"{"foo":"x y&? z"}"#).unwrap();
let expected = GraphQLRequest(GraphQLBatchRequest::Single(http::GraphQLRequest::new(
"test".to_string(),
None,
Some(variables),
)));
assert_eq!(result.unwrap(), expected);
}
#[test]
fn test_url_decode() {
let form_string = "query=%25foo%20bar+baz%26%3F&operation_name=test";
let mut items = FormItems::from(form_string);
Introduce an abstraction for scalar values (#251) Introduce an abstraction for scalar values Before this change, possible scalar values were hard coded to be representable by one of the following types: `i32`, `f64`, `String` or `bool`. This restricts the types of custom scalar values that can be defined. For example, it was not possible to define a scalar value that represents an `i64` without mapping it to a string (which would be inefficient). One solution to fix the example above would simply be to change the internal representation to allow it to represent an `i64`, but this would only fix the problem for one type (until someone wants to support `i128` for example). Also this would make juniper not follow the GraphQL standard closely. This commit takes another approach, by making the exact "internal" representation of scalar values swappable (in such a way that a downstream crate could provide its own representation tailored to their needs). This allows juniper to provide a default type that only contains the types described in the standard whereas other crates could define custom scalars for their needs. To accomplish this we need to change several things in the current implementation: * Add some traits that abstract the behavior of such a scalar value representation * Change `Value` and `InputValue` to have a scalar variant (with a generic type) instead of hard coded variants for the standard types. This implies adding a generic parameter to both enums that needs to be added in the whole crate. * Change the parser to allow deciding between different types of scalar values. The problem is basically that the original parser implementation had no way to know whether a parsed integer number is a `i32` or a `i64` (for example). To fix this we added some knowledge of the existing schema to the parser. * Fix some macros and derives to follow the new behavior. This commit also contains an unrelated change about the way `juniper_codegen` resolves items from `juniper`. The `_internal` flag is removed and the resolution is replaced by a macro. The scalar parsing strategy is as follows: * Pass optional type information all the way down in the parser. If a field/type/… does note exist, just do not pass down the type information. * The lexer now distinguishes between several fundamental scalar types (`String`, `Float`, `Int`). It does not try to actually parse those values, instead it just annotates them that this is a floating point number, an integer number, or a string value, etc. * If type information exists while parsing a scalar value, try the following: 1. Try parsing the value using that type information. 2. If that fails try parsing the value using the inferred type information from the lexer. * If no type information exists, try parsing the scalar value using the inferred type from the lexer, All macros support the introduced scalar value abstraction. It is now possible to specify if a certain implementation should be based on a specific scalar value representation or be generic about the exact representation. All macros now default to the `DefaultScalarValue` type provided by `juniper` if no scalar value representation is specified. This is done with usability and backwards compatibility in mind. Finally, we allow specifying the scalar value representations via an attribute (`#[graphql(scalar = "Type")]`). A default generic implementation is provided.
2018-10-23 03:40:14 +00:00
let result: Result<GraphQLRequest, _> = GraphQLRequest::from_form(&mut items, false);
assert!(result.is_ok());
let expected = GraphQLRequest(GraphQLBatchRequest::Single(http::GraphQLRequest::new(
"%foo bar baz&?".to_string(),
Some("test".to_string()),
None,
)));
assert_eq!(result.unwrap(), expected);
}
}
#[cfg(test)]
mod tests {
use juniper::{
http::tests as http_tests,
Make interfaces great again! (#682) * Bootstrap * Upd * Bootstrap macro * Revert stuff * Correct PoC to compile * Bootstrap #[graphql_interface] expansion * Bootstrap #[graphql_interface] meta parsing * Bootstrap #[graphql_interface] very basic code generation [skip ci] * Upd trait code generation and fix keywords usage [skip ci] * Expand trait impls [skip ci] * Tune up objects [skip ci] * Finally! Complies at least... [skip ci] * Parse meta for fields and its arguments [skip ci] - also, refactor and bikeshed new macros code * Impl filling fields meta and bootstrap field resolution [skip ci] * Poking with fields resolution [skip ci] * Solve Rust's teen async HRTB problems [skip ci] * Start parsing trait methods [skip ci] * Finish parsing fields from trait methods [skip ci] * Autodetect trait asyncness and allow to specify it [skip ci] * Allow to autogenerate trait object alias via attribute * Support generics in trait definition and asyncify them correctly * Temporary disable explicit async * Cover arguments and custom names/descriptions in tests * Re-enable tests with explicit async and fix the codegen to satisfy it * Check implementers are registered in schema and vice versa * Check argument camelCases * Test argument defaults, and allow Into coercions for them * Re-enable markers * Re-enable markers and relax Sized requirement on IsInputType/IsOutputType marker traits * Revert 'juniper_actix' fmt * Fix missing marks for object * Fix subscriptions marks * Deduce result type correctly via traits * Final fixes * Fmt * Restore marks checking * Support custom ScalarValue * Cover deprecations with tests * Impl dowcasting via methods * Impl dowcasting via external functions * Support custom context, vol. 1 * Support custom context, vol. 2 * Cover fallible field with test * Impl explicit generic ScalarValue, vol.1 * Impl explicit generic ScalarValue, vol.2 * Allow passing executor into methods * Generating enum, vol.1 * Generating enum, vol.2 * Generating enum, vol.3 * Generating enum, vol.3 * Generating enum, vol.4 * Generating enum, vol.5 * Generating enum, vol.6 * Generating enum, vol.7 * Generating enum, vol.8 * Refactor juniper stuff * Fix juniper tests, vol.1 * Fix juniper tests, vol.2 * Polish 'juniper' crate changes, vol.1 * Polish 'juniper' crate changes, vol.2 * Remove redundant stuf * Polishing 'juniper_codegen', vol.1 * Polishing 'juniper_codegen', vol.2 * Polishing 'juniper_codegen', vol.3 * Polishing 'juniper_codegen', vol.4 * Polishing 'juniper_codegen', vol.5 * Polishing 'juniper_codegen', vol.6 * Polishing 'juniper_codegen', vol.7 * Polishing 'juniper_codegen', vol.8 * Polishing 'juniper_codegen', vol.9 * Fix other crates tests and make Clippy happier * Fix examples * Add codegen failure tests, vol. 1 * Add codegen failure tests, vol. 2 * Add codegen failure tests, vol.3 * Fix codegen failure tests accordingly to latest nightly Rust * Fix codegen when interface has no implementers * Fix warnings in book tests * Describing new interfaces in Book, vol.1 Co-authored-by: Christian Legnitto <LegNeato@users.noreply.github.com>
2020-10-06 10:21:01 +03:00
tests::fixtures::starwars::schema::{Database, Query},
EmptyMutation, EmptySubscription, RootNode,
};
use rocket::{
self, get,
http::ContentType,
local::{Client, LocalRequest},
post,
request::Form,
routes, Rocket, State,
};
type Schema = RootNode<'static, Query, EmptyMutation<Database>, EmptySubscription<Database>>;
#[get("/?<request..>")]
fn get_graphql_handler(
context: State<Database>,
request: Form<super::GraphQLRequest>,
schema: State<Schema>,
) -> super::GraphQLResponse {
request.execute_sync(&schema, &context)
}
#[post("/", data = "<request>")]
fn post_graphql_handler(
context: State<Database>,
request: super::GraphQLRequest,
schema: State<Schema>,
) -> super::GraphQLResponse {
request.execute_sync(&schema, &context)
}
struct TestRocketIntegration {
client: Client,
}
impl http_tests::HttpIntegration for TestRocketIntegration {
fn get(&self, url: &str) -> http_tests::TestResponse {
let req = &self.client.get(url);
make_test_response(req)
}
fn post_json(&self, url: &str, body: &str) -> http_tests::TestResponse {
let req = &self.client.post(url).header(ContentType::JSON).body(body);
make_test_response(req)
}
fn post_graphql(&self, url: &str, body: &str) -> http_tests::TestResponse {
let req = &self
.client
.post(url)
.header(ContentType::new("application", "graphql"))
.body(body);
make_test_response(req)
}
}
#[test]
fn test_rocket_integration() {
let rocket = make_rocket();
let client = Client::new(rocket).expect("valid rocket");
let integration = TestRocketIntegration { client };
http_tests::run_http_test_suite(&integration);
}
#[test]
fn test_operation_names() {
#[post("/", data = "<request>")]
fn post_graphql_assert_operation_name_handler(
context: State<Database>,
request: super::GraphQLRequest,
schema: State<Schema>,
) -> super::GraphQLResponse {
assert_eq!(request.operation_names(), vec![Some("TestQuery")]);
request.execute_sync(&schema, &context)
}
let rocket = make_rocket_without_routes()
.mount("/", routes![post_graphql_assert_operation_name_handler]);
let client = Client::new(rocket).expect("valid rocket");
let req = client
.post("/")
.header(ContentType::JSON)
.body(r#"{"query": "query TestQuery {hero{name}}", "operationName": "TestQuery"}"#);
let resp = make_test_response(&req);
assert_eq!(resp.status_code, 200);
}
fn make_rocket() -> Rocket {
make_rocket_without_routes().mount("/", routes![post_graphql_handler, get_graphql_handler])
}
fn make_rocket_without_routes() -> Rocket {
rocket::ignite().manage(Database::new()).manage(Schema::new(
Query,
EmptyMutation::<Database>::new(),
EmptySubscription::<Database>::new(),
))
}
fn make_test_response(request: &LocalRequest) -> http_tests::TestResponse {
let mut response = request.clone().dispatch();
let status_code = response.status().code as i32;
let content_type = response
.content_type()
.expect("No content type header from handler")
.to_string();
let body = response
.body()
.expect("No body returned from GraphQL handler")
.into_string();
http_tests::TestResponse {
status_code,
body,
content_type,
}
}
}