Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow using #[derive(GraphQLQuery)] without depending on serde #487

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

swlynch99
Copy link

This PR makes the serde derives emitted by #[derive(GraphQLQuery)] use a private re-export of the serde crate instead of relying on users of this crate having added serde to their Cargo.toml.

Serde allows you to add an annotation

#[serde(crate = "<path to crate>")]

for exactly this reason so most of this PR is just plumbing the correct path through the codegen crate to the correct annotation.

Details

  • There is a new #[doc(hidden)] mod _private declaration in the graphql_client crate. All re-exports (which is just serde) have been placed there.
  • I have added a new serde_path field to GraphQLCodegenOptions which defaults to ::serde. This means that the code generated by the CLI should remain effectively unchanged.
  • The rest is just applying #[serde(crate = ...)] annotations where appropriate.

Fixes #427

This PR makes the serde derives emitted by `#[derive(GraphQLQuery)]` use
a private re-export of the serde crate instead of relying on users of
this crate having added serde to their `Cargo.toml`.

Serde allows you to add an annotation

    #[serde(crate = "<path to crate>")]

for exactly this reason so most of this PR is just plumbing the correct
path through the codegen crate to the correct annotation.

Details
-------
- There is a new `#[doc(hidden)] mod _private` declaration in the
  `graphql_client` crate. All re-exports (which is just serde) have been
   placed there.
- I have added a new `serde_path` field to `GraphQLCodegenOptions` which
  defaults to `::serde`. This means that the code generated by the CLI
  should remain effectively unchanged.
- The rest is just applying `#[serde(crate = ...)]` annotations where
  appropriate.

Fixes graphql-rust#427
Copy link

@caspermeijn caspermeijn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not the maintainer. I had this same issue, so I want to help out with a review.

I think a re-export of serde is the way to go. That way the users of graphql_client don't have to be aware of that dependency.

Comment on lines +302 to +307
/// Hidden module for types used by the codegen crate.
#[doc(hidden)]
pub mod _private {
pub use ::serde;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am conflicted on whether I like how this re-export works.

  • First of all, I don't think you have to hide it. I think explicitly depending on serde 1 is not a problem. But I can't find best practices to back up that statement.
  • Does this re-export belong here, or in graphql_query_derive as that crate defines the macro that uses it, or in graphql_query_codegen as that crate produces the generated code?

Copy link
Author

@swlynch99 swlynch99 Jul 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A hidden module is a common pattern for private types used in macros (see serde, for an example). Adding a new public export is a bigger change than having it as a private module, regardless of whether publically exporting serde is an issue or not. I have not seen a crate publically re-export serde, though.

For the second point, this export needs to be in graphql_client. That is the only crate that we know will be available to users of the library. Beyond that, you can't have non-proc-macro exports from a proc-macro crate which rules out exporting it from graphql_query_derive.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the second point, this export needs to be in graphql_client. That is the only crate that we know will be available to users of the library. Beyond that, you can't have non-proc-macro exports from a proc-macro crate which rules out exporting it from graphql_query_derive.

I didn't know about that rule for proc-macro exports, then It makes total sense to do it in graphql_client.

@@ -68,6 +70,7 @@ impl GraphQLClientCodegenOptions {
extern_enums: Default::default(),
fragments_other_variant: Default::default(),
skip_serializing_none: Default::default(),
serde_path: syn::parse_quote!(::serde),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the generated code is already dependent on ::graphql_client, I don't think this has to be configurable. Do you have a usecase for having this configurable?

Copy link
Author

@swlynch99 swlynch99 Jul 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The graphql_client_codegen crate is used outside of the derive macro (see its reverse dependencies). Unilaterally changing the path used for serde imports would break users who are generating code for an older graphql_client version. Notably, it would change the output of the CLI.

It's been a while since I wrote the code here but I think that was the reason that I did it as an option here.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The graphql_client_codegen crate is used outside of the derive macro (see its reverse dependencies). Unilaterally changing the path used for serde imports would break users who are generating code for an older graphql_client version. Notably, it would change the output of the CLI.

You are right, this causes the least breaking change. The problem I see is that a config option is not good for discoverability. However, if you are using the codegen crate, then you are probably an advanced user. I think it makes sense to do it this way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

unresolved import serde use of undeclared crate or module serde
2 participants