Skip to content

gqlgenc v1#281

Draft
sonatard wants to merge 258 commits intov3from
v3dev
Draft

gqlgenc v1#281
sonatard wants to merge 258 commits intov3from
v3dev

Conversation

@sonatard
Copy link
Copy Markdown
Member

@sonatard sonatard commented Apr 22, 2025

gqlgenc v1 is rewriting based on gqlgenc v0.0.2. If there are any missing features, please let me know.

Schedule

  • Release 1.0.0-alpha release aligned with json/v2 release date

GraphQL Client

Gennerate Client and Query Go code

  • Separate gqlgenc config and gqlgen config
gqlgenc:
  clientgen:
    filename: ./gen/client.go
  query:
    - "./queries/*.graphql"

gqlgen:
  model:
    filename: ./gen/models_gen.go
  schema:
    - testdata/cfg/glob/**/*.graphql
  • Separate querygen and clientgen
gqlgenc:
  query:
    - ./query/*.graphql
  querygen:
    filename: ./domain/query_gen.go
  clientgen:
    filename: ./query/client_gen.go
  export_query_type: true
  • Separate gotype generator and operation generator
  • Make the Go types corresponding to FragmentSpread and InlineFragment non-optional to reduce the code generated for Getter functions.
  • gqlgen distinguishes whether the received input is undefined or null.
  • gqlgenc distinguishes whether the input sent, using the type generated by gqlgen's model_gen, is undefined or null.
  • Enable gqlgen to return undefined in responses. From Go 1.24, using omitempty + IsZero method.
  • Improved the consistency between GraphQL queries and Go types.
    1. Go Code Fragments are always generated as independent types and used.
    2. Go Code Fragments are embedded.
    3. Go Code Fragments are exported type
    4. Go Code Fragments are always non-optional.
    5. Go Code Inline Fragments do not generate independent types.
    6. Go Code InlineFragments are anonymous type
    7. Go Code Inline Fragments are always non-optional.
    8. Go Code Query type is unexported type(option)
    9. Go Code field is optional or not depends on the GraphQL schema.

Sample

query UserOperation {
  user {
    ... on User {
      ...UserFragment1
    }
    ...UserFragment1
  }
}

fragment UserFragment1 on User {
  name
}
// v1
type userOperation_User struct {
	User struct {
		UserFragment1
	} "graphql:\"... on User\""
	UserFragment1
}

type UserFragment1 struct {
	Name string "json:\"name,omitempty,omitzero\" graphql:\"name\""
}
// v0.32.0
type UserOperation struct {
	User UserOperation_User "json:\"user\" graphql:\"user\""
}

type UserOperation_User struct {
	User UserOperation_User_User "graphql:\"... on User\""
	Name string                  "json:\"name\" graphql:\"name\""
}

type UserOperation_User_User struct {
	Name string "json:\"name\" graphql:\"name\""
}

Refactoring

  • Fix multiple panic panic: multiple fields with the same name #282
  • goimports after clientgen
  • Reduce generation code and template line
  • Remove urfave
  • Table Driven Test remove testify
  • Refactor config
  • test with gqlgen
  • wrap error
  • GitHub Actions
  • document to english
  • golangci-lint v2
  • .golangci.yml
  • Name or Alias test
  • Input Omittable test
  • typename union
  • remove graphql tag
  • nested fragment test
  • graphqljson use json v2 package
  • default onlyUsedModel
  • omitzero default is false
  • remove omitempty
  • support query response @gofield type
  • inlineFragment Pointer
  • README.md
  • How To read gqlgenc 1. template.tmpl
  • comments
  • test reference by example

Not supported

  • struct_fields_always_pointers config
  • omitempty
  • Omittable in Query Response

Squense

sequenceDiagram
    actor User
    participant Main as main.go
    participant Run as run.go
    participant Config as config
    participant Client as client
    participant Introspection as introspection
    participant QueryParser as queryparser
    participant CodeGen as codegen
    participant ModelGen as modelgen
    participant QueryGen as querygen
    participant ClientGen as clientgen

    User->>Main: Execute gqlgenc command
    Main->>Run: run()

    Note over Run,Config: Configuration Loading (TestLoadConfig)
    Run->>Config: FindConfigFile(".gqlgenc.yml")
    Config-->>Run: config file path

    Run->>Config: LoadConfig(cfgFile)
    Note right of Config: [TestLoadConfig]<br/>Read config file<br/>Parse YAML with env expansion

    alt Config validation error
        Config->>Config: Check schema/endpoint
        Note right of Config: Error if both specified<br/>Error if neither specified
        Config-->>Run: Error
    else Config validation success
        Config->>Config: Validate model config
        Config->>Config: Set schema filenames (glob)
        Config->>Config: Set default gqlgen fields
        Note right of Config: Directives, Exec, Resolver,<br/>Federation configs
        Config-->>Run: Config
    end

    Note over Run,Introspection: Schema Loading & Initialization (TestLoadSchema)
    Run->>Config: LoadSchema(ctx)

    alt Local Schema
        Config->>Config: GQLGenConfig.LoadSchema()
        Note right of Config: [TestLoadSchema]<br/>Load from local files
        Config-->>Config: GraphQL AST
    else Remote Schema (Endpoint)
        Config->>Client: Use endpoint.Client or http.DefaultClient
        Client-->>Config: HTTP Client
        Config->>Introspection: introspectionSchema(ctx, client, URL, headers)
        Introspection->>Client: Post(introspectionQuery)

        alt HTTP Error
            Client-->>Introspection: Error (500, 404, etc)
            Introspection-->>Config: Error
            Config-->>Run: Error
        else Success
            Client-->>Introspection: Schema Response
            Introspection->>Introspection: Parse introspection response

            alt Invalid Schema
                Introspection->>Introspection: Validate schema
                Introspection-->>Config: Validation Error
                Config-->>Run: Error
            else Valid Schema
                alt Query type is null
                    Introspection->>Introspection: Initialize default Query type
                end
                Introspection-->>Config: GraphQL AST
                Config->>Config: Set GQLGenConfig.Schema
            end
        end
    end

    Config->>Config: Delete existing generated files
    Note right of Config: Unlink model, query,<br/>client gen files
    Config->>Config: Initialize Models & StructTag
    Note right of Config: Set default Models map<br/>Set default StructTag="json"
    Config->>Config: GQLGenConfig.Init()
    Config->>Config: Sort Schema.Implements
    Note right of Config: [TestLoadSchema]<br/>Sort interface implementations<br/>for deterministic output
    Config-->>Run: Initialized Config

    Note over Run,QueryParser: Query File Parsing (TestLoadQuery)
    Run->>Config: GQLGencConfig.LoadQuery(schema)
    Config->>QueryParser: LoadQuerySources(query files)

    alt Query file not found or syntax error
        QueryParser-->>Config: Error
        Config-->>Run: Error
    else Query files loaded
        QueryParser-->>Config: Query Sources
        Config->>QueryParser: QueryDocument(schema, sources)
        Note right of QueryParser: [TestLoadQuery]<br/>Parse & validate<br/>GraphQL queries

        alt Query validation error
            QueryParser-->>Config: Error (unknown field, etc)
            Config-->>Run: Error
        else Valid queries
            QueryParser-->>Config: Query Document
            Config->>QueryParser: OperationQueryDocuments()
            Note right of QueryParser: [TestLoadQuery]<br/>Split by operation<br/>(query/mutation/subscription)
            QueryParser-->>Config: Operation Documents
            Config->>Config: Set QueryDocument & OperationQueryDocuments
            Config-->>Run: Success
        end
    end

    Note over Run,ClientGen: Code Generation
    Run->>Run: plugins.GenerateCode(cfg)

    Note over Run,ModelGen: Model Generation (gqlgen based)
    Run->>ModelGen: New(cfg, operationDocs)
    Run->>ModelGen: MutateConfig()
    ModelGen->>ModelGen: Generate models/enums/scalars
    Note right of ModelGen: Generate Go types<br/>for GraphQL types
    ModelGen-->>Run: models_gen.go

    Note over Run,CodeGen: Go Type Analysis
    Run->>CodeGen: CreateOperations(queryDoc, opDocs)
    Note right of CodeGen: Create operation structs<br/>with args & variables
    CodeGen-->>Run: Operations
    Run->>CodeGen: CreateGoTypes(operations)
    Note right of CodeGen: Convert GraphQL types<br/>to Go types
    CodeGen-->>Run: Go Types

    Note over Run,QueryGen: Query Code Generation
    Run->>QueryGen: New(cfg, operations, goTypes)
    Run->>QueryGen: MutateConfig()
    QueryGen->>QueryGen: RenderTemplate(template.tmpl)
    Note right of QueryGen: Generate response types<br/>& unmarshal code
    QueryGen-->>Run: query code with types

    Note over Run,ClientGen: Client Code Generation
    Run->>ClientGen: New(cfg, operations)
    Run->>ClientGen: MutateConfig()
    ClientGen->>ClientGen: RenderTemplate(template.tmpl)
    Note right of ClientGen: Generate client methods<br/>for each operation
    ClientGen-->>Run: client.go with methods

    Run-->>Main: Success
    Main-->>User: Generated code files
Loading

@sonatard sonatard mentioned this pull request Apr 22, 2025
@sonatard sonatard changed the base branch from master to v3 April 22, 2025 15:35
@sonatard sonatard force-pushed the v3dev branch 3 times, most recently from 759d2e7 to 821cc20 Compare April 23, 2025 00:33
@sonatard sonatard force-pushed the v3dev branch 2 times, most recently from 1c45783 to 7c96479 Compare April 23, 2025 23:54
@sonatard sonatard force-pushed the v3dev branch 2 times, most recently from 6821f68 to 3749703 Compare April 24, 2025 01:24
@sonatard sonatard changed the title gqlgenc v3 gqlgenc v1 Oct 16, 2025
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.

1 participant