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

plugin development documentation? #3712

Closed
seansfkelley opened this issue Mar 24, 2020 · 10 comments
Closed

plugin development documentation? #3712

seansfkelley opened this issue Mar 24, 2020 · 10 comments
Assignees
Labels
docs Documentation waiting-for-release Fixed/resolved, and waiting for the next stable release

Comments

@seansfkelley
Copy link

seansfkelley commented Mar 24, 2020

Is your feature request related to a problem? Please describe.

I'm trying to author a new plugin (python-operations) in my fork of this repo. However, while the docs talk about the basics of plugin development, I'm hung up on tooling issues that even before that. A selection of things:

  • How do I install the repo properly? I used some combination of yarn/lerna to get it into a valid state, and then I did something, and now my builds are failing and VS Code is complaining, unable to resolve @graphql-codegen/* dependencies.
  • What's a good development workflow for testing a new plugin on a real codebase? I matched versions with my project and tried to symlink in my new plugin, but it complained about having multiple versions of (I think) graphql (an error message which I greatly appreciate, but means I have some hacky workaround to test my very-much-still-in-development plugin on my project).
  • Are there common unit or integration tests that cover every GraphQL language feature that plugins should attempt to support? For instance, I don't use subscriptions and am not familiar with them, but if there were even one big integration test fixture that covers the syntax and I could compare what e.g. the typescript plugin does for it, I'm reasonably confident I could make a passable Python equivalent.
  • I'd like to reuse the BaseDocumentsVisitor to do python-operations, but there are a lot of moving parts. I'm trying to learn how SelectionSetToObject and BaseSelectionSetProcessor and OperationVariablesToObject and DeclarationBlock work simultaneously and it's pretty confusing. A document that explains what their role is and how they interact with each other would be awesome, because I think there's a lot in there I can reuse, but they also appear somewhat coupled to Flow/Typescript.

Describe the solution you'd like

More documentation! What's on the site now is a good start, but only covers the very basics and assumes you're working in your own repo, which I'm not (partly because I'm targeting Python, so I don't want to have to set up a node package when I already have graphql-code-generator available, and partly because I'm interested in eventually contributing this back to the mainline).

Describe alternatives you've considered

Trying random stuff only works for so long. I really can't figure out how I got my repo into this state, and why the nuclear option of deleting all node_modules and starting over isn't working.

Additional context

Similar to #951, but that one is quite old and appears to have been the impetus for writing the documentation that currently exists.

@GavinRay97
Copy link

I actually asked the same question in the Discord 15 minutes ago, hopefully get some good info.

@dotansimha dotansimha self-assigned this Apr 19, 2020
@dotansimha dotansimha added docs Documentation enhancement labels Apr 19, 2020
@dotansimha
Copy link
Owner

Thank you, I'm working on improving it now :)

@dotansimha
Copy link
Owner

dotansimha commented Apr 19, 2020

Done in: #3895 (https://github.com/dotansimha/graphql-code-generator/blob/fixes/website/docs/custom-codegen/contributing.md), this will be available in the website soon.

@dotansimha dotansimha added the waiting-for-release Fixed/resolved, and waiting for the next stable release label Apr 19, 2020
@dotansimha
Copy link
Owner

Done in 1.13.3

@seansfkelley
Copy link
Author

Thank you! I'll pick my Python work back up and take a look.

@Andrew-Talley
Copy link
Contributor

@seansfkelley Hey, are you still working on this? I was thinking about making the same sort of package you were, but it seems redundant and I wouldn't want to step on your toes if this is still under development. Or, if you want someone to help with it, I'd be more than happy to.

@seansfkelley
Copy link
Author

seansfkelley commented May 31, 2020

@Andrew-Talley unfortunately I haven't had enough time to give this the attention it needs. I would really really love to have this, but I've had to just work around the few cases I'd use it for with manually-defined types. Boo.

If you want to pick it up, that would be fantastic. I'd be happy to take a look over whatever you put together, if that helps. That said, you can find my changes at https://github.com/seansfkelley/graphql-code-generator/tree/python-support but be warned they're a hodgepodge of half-baked ideas and me trying to understand the types of things I'm asking about in this issue.

I did end up generating some promising types. The basic design I was going for was:

  • Uses Pydantic. Love this library.
  • The "global" type generator would only output scalars, enumerations and input types.
  • The "operations" type generator would define purpose-built types according to the operation in question (this is different than the Typescript generator, which generates all types in the global space, and then uses Pick/Partial/whatever to select subsets of them for operations).

This made code that, when used with the near-operations-file preset, looked like (from memory here -- sorry if this doesn't match with what it does exactly):

# Assuming a sibling file defines some query:
# query getStuff(input: MyInputType) {
#   fooBar { # of type FooBar!
#     baz # of type String
#   }
# }

from wherever.you.set.global.types.to import BaseModel

class GetStuff(BaseModel):
  class FooBar(BaseModel):
    baz: Optional[str]
  
  foo_bar: FooBar

A couple things to notice about this that I liked:

  • Though the selection set for any given type (e.g. FooBar) may vary in different queries, it always takes the same name when generated. This is because you get a nice behavior where the enclosing class acts as a namespace (like GetStuff.FooBar) which makes it abundantly clear both what type the selection set is on and that this class definition is only for this operation.
  • Pydantic has "alias generators" that make it super easy to translate between camelCase GraphQL and snake_case Python so it's idiomatic in all usages. (That's what the BaseModel import is doing here, along with a couple of other behaviors like disallowing extraneous fields and disallowing mutations.)

Hope that's helpful, and really look forward to any progress you make on this! Maybe the new C# generator can be a helpful guide for non-Javascript-family languages.

@Andrew-Talley
Copy link
Contributor

@seansfkelley Thank you for all of that, that'll be super helpful. I'm really hoping I'll be able to turn this into something close to as high-quality as the rest of the languages. And thank you for the offer to look it over, I may take you up on it.

@dotansimha
Copy link
Owner

@seansfkelley this is awesome! do you wish to create a WIP PR for that? this way we can help you wish developing this new plugin :)

@seansfkelley
Copy link
Author

Sure, if you think that would be helpful! I opened #4144, but as noted here and there, I won't have time to contribute it beyond reviewing/testing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs Documentation waiting-for-release Fixed/resolved, and waiting for the next stable release
Projects
None yet
Development

No branches or pull requests

4 participants