Repository: graphql-rust/juniper (language: rust)

Issue:
Derive Clone, Serialize and Deserialize for GraphQLRequest and GraphQLResponse
For me I need to persist HTTP GraphQL requests and response which is why I need `Serialize` and `Deserialize` and then I need to pass them around cloning them. 

In order to do so for `GraphQLRequest` every field is already `Serialize`able and a simple `#[derive(Serialize)]`, it derives the other traits.

For `GraphQLResponse` in order to do `Deserialize`, a custom `Deserialize` implementation would have to be done. On top of that `Clone` seems impossible with the `GraphQLResponse` having borrowed content in the form of a lexer `Token<'a>` from a parse error.

Changing `Token` to owning the `Name` variant would make it possible to clone the response around.

Thats all. It should be relatively simple to implement.


Discussion / hints:
So, I was in the process of removing the borrowed content in `Token::Name` but it seems like the `ast`, `lexer` and `parser` are all dependent on that lifetime and the borrowed content. There might be another approach to it, however for now in order to clone, I will serialize then clone the string.

I do comparisions of `GraphQLResponses` so a serialized String would likely be used anyways.

I made a pr for the `GraphQLRequest`.
> In order to do so for `GraphQLRequest` every field is already `Serialize`able and a simple `#[derive(Serialize)]`, it derives the other traits.

This was done in https://github.com/graphql-rust/juniper/commit/6d345b6b98fd382c12de17954e3ae77827279014 (yeah, buy you 🙃).

> So, I was in the process of removing the borrowed content in `Token::Name` but it seems like the `ast`, `lexer` and `parser` are all dependent on that lifetime and the borrowed content. There might be another approach to it, however for now in order to clone, I will serialize then clone the string.

Actually, the lifetime was stripped from `GraphQLResponse` in #1081 already.

> For `GraphQLResponse` in order to do `Deserialize`, a custom `Deserialize` implementation would have to be done. On top of that `Clone` seems impossible with the `GraphQLResponse` having borrowed content in the form of a lexer `Token<'a>` from a parse error.

I'm not sure how much `Deserialize` has sense for `GraphQLResponse`, however, `Clone` and `PartialEq` seems to be something possible now, after #1081. Let's try it.



Fix patch:
diff --git a/juniper/CHANGELOG.md b/juniper/CHANGELOG.md
index 6a228e6b5..0962c04b3 100644
--- a/juniper/CHANGELOG.md
+++ b/juniper/CHANGELOG.md
@@ -71,6 +71,7 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
 - `LookAheadMethods::field_original_name()` and `LookAheadMethods::field_alias()` methods. ([#1199])
 - [`anyhow` crate] integration behind `anyhow` and `backtrace` [Cargo feature]s. ([#1215], [#988])
 - `RootNode::disable_introspection()` applying additional `validation::rules::disable_introspection`, and `RootNode::enable_introspection()` reverting it. ([#1227], [#456])
+- `Clone` and `PartialEq` implementations for `GraphQLResponse`. ([#1228], [#103])
 
 ### Changed
 
@@ -88,6 +89,7 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
 - Incorrect error when explicit `null` provided for `null`able list input parameter. ([#1086], [#1085])
 - Stack overflow on nested GraphQL fragments. ([CVE-2022-31173])
 
+[#103]: /../../issues/103
 [#113]: /../../issues/113
 [#456]: /../../issues/456
 [#503]: /../../issues/503
@@ -143,6 +145,7 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
 [#1215]: /../../pull/1215
 [#1221]: /../../pull/1221
 [#1227]: /../../pull/1227
+[#1228]: /../../pull/1228
 [ba1ed85b]: /../../commit/ba1ed85b3c3dd77fbae7baf6bc4e693321a94083
 [CVE-2022-31173]: /../../security/advisories/GHSA-4rx6-g5vg-5f3j
 
diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs
index 83f69446a..4150689ab 100644
--- a/juniper/src/executor/mod.rs
+++ b/juniper/src/executor/mod.rs
@@ -87,7 +87,7 @@ where
 ///
 /// All execution errors contain the source position in the query of the field
 /// that failed to resolve. It also contains the field stack.
-#[derive(Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct ExecutionError<S> {
     location: SourcePosition,
     path: Vec<String>,
diff --git a/juniper/src/http/mod.rs b/juniper/src/http/mod.rs
index b8b4cb002..38ef764f2 100644
--- a/juniper/src/http/mod.rs
+++ b/juniper/src/http/mod.rs
@@ -163,7 +163,7 @@ where
 /// This struct implements Serialize, so you can simply serialize this
 /// to JSON and send it over the wire. Use the `is_ok` method to determine
 /// whether to send a 200 or 400 HTTP status code.
-#[derive(Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct GraphQLResponse<S = DefaultScalarValue>(
     Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError>,
 );
diff --git a/juniper/src/lib.rs b/juniper/src/lib.rs
index 88825a28d..2882fb8e8 100644
--- a/juniper/src/lib.rs
+++ b/juniper/src/lib.rs
@@ -98,7 +98,7 @@ pub use crate::{
 
 /// An error that prevented query execution
 #[allow(missing_docs)]
-#[derive(Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq)]
 pub enum GraphQLError {
     ParseError(Spanning<ParseError>),
     ValidationError(Vec<RuleError>),
diff --git a/juniper/src/parser/lexer.rs b/juniper/src/parser/lexer.rs
index baefdf0bc..4eae6d6b1 100644
--- a/juniper/src/parser/lexer.rs
+++ b/juniper/src/parser/lexer.rs
@@ -51,7 +51,7 @@ pub enum Token<'a> {
 }
 
 /// Error when tokenizing the input source
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
 pub enum LexerError {
     /// An unknown character was found
     ///
diff --git a/juniper/src/parser/parser.rs b/juniper/src/parser/parser.rs
index d053ec42f..41922b850 100644
--- a/juniper/src/parser/parser.rs
+++ b/juniper/src/parser/parser.rs
@@ -5,7 +5,7 @@ use smartstring::alias::String;
 use crate::parser::{Lexer, LexerError, Spanning, Token};
 
 /// Error while parsing a GraphQL query
-#[derive(Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq)]
 pub enum ParseError {
     /// An unexpected token occurred in the source
     // TODO: Previously was `Token<'a>`.
diff --git a/juniper/src/validation/context.rs b/juniper/src/validation/context.rs
index d98c51422..f46af2f30 100644
--- a/juniper/src/validation/context.rs
+++ b/juniper/src/validation/context.rs
@@ -10,7 +10,7 @@ use crate::schema::{meta::MetaType, model::SchemaType};
 use crate::parser::SourcePosition;
 
 /// Query validation error
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
 pub struct RuleError {
     locations: Vec<SourcePosition>,
     message: String,


Test patch: