├── integration
├── config.yaml
├── user.graphql
├── testomitempty.graphql
├── .babelrc
├── remote_api
│ └── user.go
├── codegen.yml
├── testomitempty
│ └── testmodel.go
├── models-go
│ ├── viewer.go
│ └── element.go
├── .graphqlconfig
├── readme.md
├── jest.config.js
├── gqlgen.yml
├── package.json
├── schema.graphql
└── schema-expected.graphql
├── codegen
├── config
│ └── testdata
│ │ ├── cfg
│ │ ├── outer
│ │ ├── subdir
│ │ │ ├── inner
│ │ │ └── gqlgen.yaml
│ │ ├── otherdir
│ │ │ └── .gitkeep
│ │ ├── gqlgen.yml
│ │ ├── malformedconfig.yml
│ │ ├── unknownkeys.yml
│ │ ├── glob
│ │ │ ├── foo
│ │ │ │ └── foo.graphql
│ │ │ └── bar
│ │ │ │ └── bar with spaces.graphql
│ │ ├── glob.yml
│ │ └── unwalkable.yml
│ │ ├── defaultconfig
│ │ └── schema.graphql
│ │ ├── example.go
│ │ └── autobinding
│ │ ├── chat
│ │ └── message.go
│ │ └── scalars
│ │ └── model
│ │ └── model.go
├── templates
│ ├── test.gotpl
│ ├── testdata
│ │ ├── a
│ │ │ └── bar
│ │ │ │ └── bar.go
│ │ ├── b
│ │ │ └── bar
│ │ │ │ └── bar.go
│ │ └── pkg_mismatch
│ │ │ └── turtles.go
│ └── test_.gotpl
├── testserver
│ ├── singlefile
│ │ ├── introspection
│ │ │ └── it.go
│ │ ├── loops.graphql
│ │ ├── ptr_to_slice.go
│ │ ├── recursive.go
│ │ ├── fields_order.go
│ │ ├── invalid-packagename
│ │ │ └── invalid-identifier.go
│ │ ├── variadic.graphql
│ │ ├── ptr_to_slice.graphql
│ │ ├── builtinscalar.graphql
│ │ ├── useptr.graphql
│ │ ├── typefallback.graphql
│ │ ├── otherpkg
│ │ │ └── model.go
│ │ ├── enum.graphql
│ │ ├── weird_type_cases.graphql
│ │ ├── slices.graphql
│ │ ├── mutation_with_custom_scalar.graphql
│ │ ├── scalar_context.graphql
│ │ ├── wrapped_type.go
│ │ ├── panics.graphql
│ │ ├── v-ok.graphql
│ │ ├── fields_order.graphql
│ │ ├── complexity.graphql
│ │ ├── v-ok.go
│ │ ├── useptr_test.go
│ │ ├── primitive_objects.graphql
│ │ ├── variadic.go
│ │ ├── scalar_default.graphql
│ │ ├── wrapped_type.graphql
│ │ ├── ptr_to_ptr_input.go
│ │ ├── maps.graphql
│ │ ├── defaults.graphql
│ │ ├── issue896.graphql
│ │ ├── ptr_to_ptr_input.graphql
│ │ ├── embedded.graphql
│ │ ├── nulls.graphql
│ │ ├── bytes.go
│ │ ├── thirdparty.go
│ │ ├── mutation_with_custom_scalar.go
│ │ ├── typefallback_test.go
│ │ ├── gqlgen.yml
│ │ ├── response_extension_test.go
│ │ ├── variadic_test.go
│ │ ├── scalar_default_test.go
│ │ ├── ptr_to_slice_test.go
│ │ ├── validtypes_test.go
│ │ ├── embedded.go
│ │ └── scalar_context.go
│ ├── followschema
│ │ ├── introspection
│ │ │ └── it.go
│ │ ├── loops.graphql
│ │ ├── ptr_to_slice.go
│ │ ├── recursive.go
│ │ ├── fields_order.go
│ │ ├── invalid-packagename
│ │ │ └── invalid-identifier.go
│ │ ├── variadic.graphql
│ │ ├── ptr_to_slice.graphql
│ │ ├── useptr.graphql
│ │ ├── builtinscalar.graphql
│ │ ├── otherpkg
│ │ │ └── model.go
│ │ ├── typefallback.graphql
│ │ ├── enum.graphql
│ │ ├── slices.graphql
│ │ ├── weird_type_cases.graphql
│ │ ├── mutation_with_custom_scalar.graphql
│ │ ├── scalar_context.graphql
│ │ ├── wrapped_type.go
│ │ ├── panics.graphql
│ │ ├── v-ok.graphql
│ │ ├── fields_order.graphql
│ │ ├── complexity.graphql
│ │ ├── v-ok.go
│ │ ├── primitive_objects.graphql
│ │ ├── useptr_test.go
│ │ ├── variadic.go
│ │ ├── scalar_default.graphql
│ │ ├── wrapped_type.graphql
│ │ ├── ptr_to_ptr_input.go
│ │ ├── maps.graphql
│ │ ├── defaults.graphql
│ │ ├── issue896.graphql
│ │ ├── nulls.graphql
│ │ ├── ptr_to_ptr_input.graphql
│ │ ├── embedded.graphql
│ │ ├── bytes.go
│ │ ├── thirdparty.go
│ │ ├── mutation_with_custom_scalar.go
│ │ ├── typefallback_test.go
│ │ ├── gqlgen.yml
│ │ ├── response_extension_test.go
│ │ ├── scalar_default_test.go
│ │ ├── ptr_to_slice_test.go
│ │ ├── validtypes_test.go
│ │ ├── embedded.go
│ │ └── scalar_context.go
│ └── empty.go
├── complexity.go
├── interface.gotpl
├── type.go
└── util.go
├── docs
├── content
│ ├── _introduction.md
│ └── introduction.md
├── static
│ ├── favicon.ico
│ ├── schema_layout.png
│ ├── request_anatomy.png
│ └── external-link-alt.svg
├── layouts
│ ├── 404.html
│ ├── partials
│ │ ├── version-switcher.html
│ │ └── version-banner.html
│ ├── _default
│ │ └── single.html
│ ├── sitemap.xml
│ └── index.html
├── readme.md
└── config.yml
├── api
├── testdata
│ ├── default
│ │ └── graph
│ │ │ ├── model
│ │ │ └── doc.go
│ │ │ └── schema.graphqls
│ └── federation2
│ │ └── graph
│ │ ├── model
│ │ └── doc.go
│ │ ├── schema.graphqls
│ │ └── federation.go
└── option.go
├── _examples
├── fileupload
│ ├── testfiles
│ │ ├── a.txt
│ │ ├── b.txt
│ │ └── c.txt
│ ├── .gqlgen.yml
│ ├── model
│ │ └── generated.go
│ └── schema.graphql
├── federation
│ ├── accounts
│ │ ├── graph
│ │ │ ├── model
│ │ │ │ ├── model.go
│ │ │ │ └── models_gen.go
│ │ │ ├── resolver.go
│ │ │ ├── schema.graphqls
│ │ │ ├── schema.resolvers.go
│ │ │ └── entity.resolvers.go
│ │ └── server.go
│ ├── products
│ │ ├── graph
│ │ │ ├── model
│ │ │ │ ├── model.go
│ │ │ │ └── models_gen.go
│ │ │ ├── resolver.go
│ │ │ ├── schema.graphqls
│ │ │ ├── products.go
│ │ │ └── schema.resolvers.go
│ │ └── server.go
│ ├── readme.md
│ ├── reviews
│ │ ├── graph
│ │ │ ├── resolver.go
│ │ │ ├── model
│ │ │ │ ├── models_gen.go
│ │ │ │ └── models.go
│ │ │ ├── schema.graphqls
│ │ │ ├── reviews.go
│ │ │ └── schema.resolvers.go
│ │ └── server.go
│ ├── jest.config.js
│ ├── start.sh
│ ├── package.json
│ └── gateway
│ │ └── index.js
├── scalars
│ ├── external
│ │ └── model.go
│ ├── model
│ │ └── generated.go
│ ├── server
│ │ └── server.go
│ ├── .gqlgen.yml
│ └── schema.graphql
├── embedding
│ ├── parent.graphqls
│ └── subdir
│ │ ├── subdir.graphqls
│ │ ├── schemadir
│ │ └── root.graphqls
│ │ ├── model.go
│ │ ├── gendir
│ │ ├── model.go
│ │ └── federation_gen.go
│ │ ├── cfgdir
│ │ ├── generate_in_subdir.yml
│ │ └── generate_in_gendir.yml
│ │ ├── federation_gen.go
│ │ └── resolvers.go
├── chat
│ ├── .gqlgen.yml
│ ├── models_gen.go
│ ├── .gitignore
│ ├── public
│ │ └── index.html
│ ├── schema.graphql
│ ├── tsconfig.json
│ ├── src
│ │ ├── App.js
│ │ └── graphql-sse.ts
│ ├── package.json
│ └── readme.md
├── selection
│ ├── .gqlgen.yml
│ ├── readme.md
│ ├── schema.graphql
│ └── server
│ │ └── server.go
├── type-system-extension
│ ├── schemas
│ │ ├── enum-extension.graphql
│ │ ├── union-extension.graphql
│ │ ├── object-extension.graphql
│ │ ├── scalar-extension.graphql
│ │ ├── input-object-extension.graphql
│ │ ├── interface-extension.graphql
│ │ ├── type-extension.graphql
│ │ ├── schema-extension.graphql
│ │ └── schema.graphql
│ ├── gqlgen.yml
│ ├── README.md
│ └── server
│ │ └── server.go
├── tools.go
├── dataloader
│ ├── .gqlgen.yml
│ ├── readme.md
│ ├── models_gen.go
│ ├── schema.graphql
│ └── server
│ │ └── server.go
├── todo
│ ├── readme.md
│ ├── gqlgen.yml
│ ├── models.go
│ ├── server
│ │ └── server.go
│ ├── schema.graphql
│ └── models_gen.go
├── config
│ ├── todo.graphql
│ ├── user.graphql
│ ├── schema.graphql
│ ├── model.go
│ ├── models_gen.go
│ ├── server
│ │ └── server.go
│ ├── .gqlgen.yml
│ ├── resolver.go
│ ├── user.resolvers.go
│ ├── todo.resolvers.go
│ └── schema.resolvers.go
├── readme.md
├── websocket-initfunc
│ └── server
│ │ ├── graph
│ │ ├── resolver.go
│ │ ├── model
│ │ │ └── models_gen.go
│ │ ├── schema.graphqls
│ │ └── schema.resolvers.go
│ │ ├── Makefile
│ │ ├── go.mod
│ │ └── readme.md
└── starwars
│ ├── readme.md
│ ├── .gqlgen.yml
│ ├── server
│ └── server.go
│ └── benchmarks_test.go
├── internal
├── code
│ ├── testdata
│ │ ├── a
│ │ │ └── a.go
│ │ ├── b
│ │ │ └── b.go
│ │ └── c
│ │ │ └── c.go
│ └── util_test.go
├── tools.go
├── imports
│ ├── testdata
│ │ ├── unused.go
│ │ └── unused.expected.go
│ └── prune_test.go
└── rewrite
│ ├── testdata
│ └── example.go
│ └── rewriter_test.go
├── .dockerignore
├── graphql
├── version.go
├── root.go
├── oneshot.go
├── any.go
├── context_path_test.go
├── context_root_field_test.go
├── handler
│ ├── transport
│ │ ├── headers.go
│ │ ├── websocket_close_reason.go
│ │ ├── util.go
│ │ ├── error.go
│ │ ├── options.go
│ │ └── reader.go
│ ├── extension
│ │ ├── introspection_test.go
│ │ └── introspection.go
│ └── lru
│ │ └── lru.go
├── bool_test.go
├── recovery.go
├── map.go
├── upload.go
├── time.go
├── bool.go
├── float_test.go
├── time_test.go
├── context_root_field.go
├── context_field_test.go
├── response.go
├── error.go
├── cache.go
├── float.go
└── jsonw_test.go
├── plugin
├── federation
│ ├── testdata
│ │ ├── entities
│ │ │ ├── nokey.graphql
│ │ │ └── nokey.yml
│ │ ├── interfaces
│ │ │ ├── key.graphqls
│ │ │ ├── key.yml
│ │ │ ├── extends.yml
│ │ │ └── extends.graphqls
│ │ ├── schema
│ │ │ ├── customquerytype.graphql
│ │ │ └── customquerytype.yml
│ │ ├── entityresolver
│ │ │ ├── resolver.go
│ │ │ ├── schema.resolvers.go
│ │ │ ├── generated
│ │ │ │ └── errors.go
│ │ │ └── gqlgen.yml
│ │ ├── allthethings
│ │ │ ├── gqlgen.yml
│ │ │ ├── model
│ │ │ │ └── federation.go
│ │ │ └── schema.graphql
│ │ └── federation2
│ │ │ ├── federation2.yml
│ │ │ └── federation2.graphql
│ ├── fedruntime
│ │ └── runtime.go
│ └── test_data
│ │ └── model
│ │ └── federation.go
├── resolvergen
│ └── testdata
│ │ ├── schema.graphql
│ │ ├── return_values
│ │ ├── schema.graphqls
│ │ ├── model.go
│ │ ├── gqlgen.yml
│ │ ├── resolvers.go
│ │ └── return_values_test.go
│ │ ├── invalid_model_path
│ │ └── gqlgen.yml
│ │ ├── filetemplate
│ │ ├── out
│ │ │ ├── resolver.go
│ │ │ └── model.go
│ │ └── gqlgen.yml
│ │ ├── followschema
│ │ ├── out
│ │ │ ├── resolver.go
│ │ │ └── model.go
│ │ └── gqlgen.yml
│ │ └── singlefile
│ │ ├── out
│ │ ├── model.go
│ │ └── resolver.go
│ │ └── gqlgen.yml
├── modelgen
│ ├── out
│ │ └── existing.go
│ ├── out_struct_pointers
│ │ └── existing.go
│ └── testdata
│ │ ├── gqlgen.yml
│ │ └── gqlgen_struct_field_pointers.yml
├── servergen
│ └── server.gotpl
└── plugin.go
├── .gitattributes
├── testdata
└── gomod-with-leading-comments.mod
├── .github
├── ISSUE_TEMPLATE.md
├── workflows
│ ├── check-fmt
│ ├── check-generate
│ ├── check-federation
│ ├── check-init
│ ├── check-coverage
│ ├── security.yml
│ ├── check-integration
│ └── test.yml
└── PULL_REQUEST_TEMPLATE.md
├── client
├── errors.go
└── readme.md
├── .gitignore
├── .editorconfig
├── .chglog
└── config.yml
├── init-templates
└── schema.graphqls
├── .golangci.yml
├── RELEASE-CHECKLIST.md
├── LICENSE
├── go.mod
└── bin
└── release
/integration/config.yaml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/codegen/config/testdata/cfg/outer:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/codegen/config/testdata/cfg/subdir/inner:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/codegen/config/testdata/cfg/otherdir/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/content/_introduction.md:
--------------------------------------------------------------------------------
1 | ../../README.md
--------------------------------------------------------------------------------
/codegen/config/testdata/defaultconfig/schema.graphql:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/api/testdata/default/graph/model/doc.go:
--------------------------------------------------------------------------------
1 | package model
2 |
--------------------------------------------------------------------------------
/codegen/config/testdata/cfg/gqlgen.yml:
--------------------------------------------------------------------------------
1 | schema: outer
2 |
--------------------------------------------------------------------------------
/codegen/config/testdata/cfg/malformedconfig.yml:
--------------------------------------------------------------------------------
1 | asdf
2 |
--------------------------------------------------------------------------------
/codegen/templates/test.gotpl:
--------------------------------------------------------------------------------
1 | this is my test package
2 |
--------------------------------------------------------------------------------
/codegen/templates/testdata/a/bar/bar.go:
--------------------------------------------------------------------------------
1 | package bar
2 |
--------------------------------------------------------------------------------
/codegen/templates/testdata/b/bar/bar.go:
--------------------------------------------------------------------------------
1 | package bar
2 |
--------------------------------------------------------------------------------
/_examples/fileupload/testfiles/a.txt:
--------------------------------------------------------------------------------
1 | Alpha file content
2 |
--------------------------------------------------------------------------------
/_examples/fileupload/testfiles/b.txt:
--------------------------------------------------------------------------------
1 | Bravo file content
2 |
--------------------------------------------------------------------------------
/_examples/fileupload/testfiles/c.txt:
--------------------------------------------------------------------------------
1 | Charlie file content
2 |
--------------------------------------------------------------------------------
/api/testdata/federation2/graph/model/doc.go:
--------------------------------------------------------------------------------
1 | package model
2 |
--------------------------------------------------------------------------------
/codegen/config/testdata/example.go:
--------------------------------------------------------------------------------
1 | package config_test_data
2 |
--------------------------------------------------------------------------------
/codegen/templates/test_.gotpl:
--------------------------------------------------------------------------------
1 | this will not be included
2 |
--------------------------------------------------------------------------------
/_examples/federation/accounts/graph/model/model.go:
--------------------------------------------------------------------------------
1 | package model
2 |
--------------------------------------------------------------------------------
/_examples/federation/products/graph/model/model.go:
--------------------------------------------------------------------------------
1 | package model
2 |
--------------------------------------------------------------------------------
/codegen/config/testdata/cfg/subdir/gqlgen.yaml:
--------------------------------------------------------------------------------
1 | schema: inner
2 |
--------------------------------------------------------------------------------
/internal/code/testdata/a/a.go:
--------------------------------------------------------------------------------
1 | package a
2 |
3 | var A = "A"
4 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | /**/node_modules
2 | /codegen/tests/gen
3 | /vendor
4 |
--------------------------------------------------------------------------------
/codegen/templates/testdata/pkg_mismatch/turtles.go:
--------------------------------------------------------------------------------
1 | package turtles
2 |
--------------------------------------------------------------------------------
/_examples/fileupload/.gqlgen.yml:
--------------------------------------------------------------------------------
1 | model:
2 | filename: model/generated.go
3 |
--------------------------------------------------------------------------------
/codegen/config/testdata/cfg/unknownkeys.yml:
--------------------------------------------------------------------------------
1 | schema: outer
2 | unknown: foo
3 |
--------------------------------------------------------------------------------
/graphql/version.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | const Version = "v0.17.27-dev"
4 |
--------------------------------------------------------------------------------
/_examples/scalars/external/model.go:
--------------------------------------------------------------------------------
1 | package external
2 |
3 | type ObjectID int
4 |
--------------------------------------------------------------------------------
/_examples/embedding/parent.graphqls:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | parentdir: String!
3 | }
4 |
--------------------------------------------------------------------------------
/_examples/embedding/subdir/subdir.graphqls:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | subdir: String!
3 | }
4 |
--------------------------------------------------------------------------------
/integration/user.graphql:
--------------------------------------------------------------------------------
1 | type User {
2 | name: String!
3 | likes: [String!]!
4 | }
5 |
--------------------------------------------------------------------------------
/_examples/embedding/subdir/schemadir/root.graphqls:
--------------------------------------------------------------------------------
1 | type Query {
2 | inSchemadir: String!
3 | }
4 |
--------------------------------------------------------------------------------
/docs/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/si3nloong/gqlgen/master/docs/static/favicon.ico
--------------------------------------------------------------------------------
/integration/testomitempty.graphql:
--------------------------------------------------------------------------------
1 | type RemoteModelWithOmitempty {
2 | newDesc: String
3 | }
4 |
--------------------------------------------------------------------------------
/integration/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [["@babel/env", {"exclude": ["transform-regenerator"]}]]
3 | }
4 |
--------------------------------------------------------------------------------
/docs/static/schema_layout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/si3nloong/gqlgen/master/docs/static/schema_layout.png
--------------------------------------------------------------------------------
/_examples/federation/readme.md:
--------------------------------------------------------------------------------
1 | ### Federation
2 |
3 | [Read the docs](https://gqlgen.com/recipes/federation/)
4 |
--------------------------------------------------------------------------------
/docs/static/request_anatomy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/si3nloong/gqlgen/master/docs/static/request_anatomy.png
--------------------------------------------------------------------------------
/_examples/chat/.gqlgen.yml:
--------------------------------------------------------------------------------
1 | models:
2 | Chatroom:
3 | model: github.com/99designs/gqlgen/_examples/chat.Chatroom
4 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/introspection/it.go:
--------------------------------------------------------------------------------
1 | package introspection
2 |
3 | type It struct {
4 | ID string
5 | }
6 |
--------------------------------------------------------------------------------
/_examples/embedding/subdir/model.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
2 |
3 | package subdir
4 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/introspection/it.go:
--------------------------------------------------------------------------------
1 | package introspection
2 |
3 | type It struct {
4 | ID string
5 | }
6 |
--------------------------------------------------------------------------------
/integration/remote_api/user.go:
--------------------------------------------------------------------------------
1 | package remote_api
2 |
3 | type User struct {
4 | Name string
5 | Likes []string
6 | }
7 |
--------------------------------------------------------------------------------
/_examples/embedding/subdir/gendir/model.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
2 |
3 | package gendir
4 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/loops.graphql:
--------------------------------------------------------------------------------
1 | type LoopA {
2 | b: LoopB!
3 | }
4 |
5 | type LoopB {
6 | a: LoopA!
7 | }
8 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/loops.graphql:
--------------------------------------------------------------------------------
1 | type LoopA {
2 | b: LoopB!
3 | }
4 |
5 | type LoopB {
6 | a: LoopA!
7 | }
8 |
--------------------------------------------------------------------------------
/graphql/root.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | type Query struct{}
4 |
5 | type Mutation struct{}
6 |
7 | type Subscription struct{}
8 |
--------------------------------------------------------------------------------
/_examples/selection/.gqlgen.yml:
--------------------------------------------------------------------------------
1 | schema: schema.graphql
2 | model:
3 | filename: models_gen.go
4 | exec:
5 | filename: generated.go
6 |
--------------------------------------------------------------------------------
/_examples/type-system-extension/schemas/enum-extension.graphql:
--------------------------------------------------------------------------------
1 | directive @enumLogging on ENUM
2 |
3 | extend enum State @enumLogging
4 |
--------------------------------------------------------------------------------
/internal/tools.go:
--------------------------------------------------------------------------------
1 | //go:build tools
2 | // +build tools
3 |
4 | package main
5 |
6 | import (
7 | _ "github.com/matryer/moq"
8 | )
9 |
--------------------------------------------------------------------------------
/_examples/type-system-extension/schemas/union-extension.graphql:
--------------------------------------------------------------------------------
1 | directive @unionLogging on UNION
2 |
3 | extend union Data @unionLogging
4 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/ptr_to_slice.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | type PtrToSliceContainer struct {
4 | PtrToSlice *[]string
5 | }
6 |
--------------------------------------------------------------------------------
/internal/code/testdata/b/b.go:
--------------------------------------------------------------------------------
1 | package b
2 |
3 | import "github.com/99designs/gqlgen/internal/code/testdata/a"
4 |
5 | var B = a.A + " B"
6 |
--------------------------------------------------------------------------------
/_examples/type-system-extension/schemas/object-extension.graphql:
--------------------------------------------------------------------------------
1 | directive @objectLogging on OBJECT
2 |
3 | extend type Todo @objectLogging
4 |
--------------------------------------------------------------------------------
/_examples/type-system-extension/schemas/scalar-extension.graphql:
--------------------------------------------------------------------------------
1 | directive @scalarLogging on SCALAR
2 |
3 | extend scalar ID @scalarLogging
4 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/ptr_to_slice.go:
--------------------------------------------------------------------------------
1 | package followschema
2 |
3 | type PtrToSliceContainer struct {
4 | PtrToSlice *[]string
5 | }
6 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/recursive.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | type RecursiveInputSlice struct {
4 | Self []RecursiveInputSlice
5 | }
6 |
--------------------------------------------------------------------------------
/plugin/federation/testdata/entities/nokey.graphql:
--------------------------------------------------------------------------------
1 | type Hello {
2 | name: String!
3 | }
4 |
5 | type Query {
6 | hello: Hello!
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/plugin/resolvergen/testdata/schema.graphql:
--------------------------------------------------------------------------------
1 | type Query {
2 | resolver: Resolver!
3 | }
4 |
5 | type Resolver {
6 | name: String!
7 | }
8 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/recursive.go:
--------------------------------------------------------------------------------
1 | package followschema
2 |
3 | type RecursiveInputSlice struct {
4 | Self []RecursiveInputSlice
5 | }
6 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | /codegen/templates/data.go linguist-generated
2 | /_examples/dataloader/*_gen.go linguist-generated
3 | generated.go linguist-generated
4 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/fields_order.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | type FieldsOrderInput struct {
4 | FirstField *string `json:"firstField"`
5 | }
6 |
--------------------------------------------------------------------------------
/docs/layouts/404.html:
--------------------------------------------------------------------------------
1 | {{ define "main" }}
2 |
Page not found
3 |
4 | I'm sorry, but the requested page wasn’t found on the server.
5 | {{ end }}
--------------------------------------------------------------------------------
/internal/code/testdata/c/c.go:
--------------------------------------------------------------------------------
1 | package c
2 |
3 | import (
4 | "github.com/99designs/gqlgen/internal/code/testdata/b"
5 | )
6 |
7 | var C = b.B + " C"
8 |
--------------------------------------------------------------------------------
/plugin/federation/testdata/interfaces/key.graphqls:
--------------------------------------------------------------------------------
1 | extend interface Hello @key(fields: "name") {
2 | name: String!
3 | secondary: String!
4 | }
5 |
--------------------------------------------------------------------------------
/_examples/type-system-extension/schemas/input-object-extension.graphql:
--------------------------------------------------------------------------------
1 | directive @inputLogging on INPUT_OBJECT
2 |
3 | extend input TodoInput @inputLogging
4 |
--------------------------------------------------------------------------------
/_examples/type-system-extension/schemas/interface-extension.graphql:
--------------------------------------------------------------------------------
1 | directive @interfaceLogging on INTERFACE
2 |
3 | extend interface Node @interfaceLogging
4 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/fields_order.go:
--------------------------------------------------------------------------------
1 | package followschema
2 |
3 | type FieldsOrderInput struct {
4 | FirstField *string `json:"firstField"`
5 | }
6 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/invalid-packagename/invalid-identifier.go:
--------------------------------------------------------------------------------
1 | package invalid_packagename
2 |
3 | type InvalidIdentifier struct {
4 | ID int
5 | }
6 |
--------------------------------------------------------------------------------
/docs/content/introduction.md:
--------------------------------------------------------------------------------
1 | ---
2 | linkTitle: Introduction
3 | title: Type-safe GraphQL for Go
4 | type: homepage
5 | date: 2018-03-17T13:06:47+11:00
6 | ---
7 |
--------------------------------------------------------------------------------
/integration/codegen.yml:
--------------------------------------------------------------------------------
1 | schema: http://localhost:8080/query
2 | overwrite: true
3 | generates:
4 | ./schema-fetched.graphql:
5 | plugins:
6 | - schema-ast
--------------------------------------------------------------------------------
/codegen/testserver/followschema/invalid-packagename/invalid-identifier.go:
--------------------------------------------------------------------------------
1 | package invalid_packagename
2 |
3 | type InvalidIdentifier struct {
4 | ID int
5 | }
6 |
--------------------------------------------------------------------------------
/codegen/testserver/empty.go:
--------------------------------------------------------------------------------
1 | package testserver
2 |
3 | // Empty file to silence go build error complaining that codegen/testserver/ has no non-test Go source files.
4 |
--------------------------------------------------------------------------------
/integration/testomitempty/testmodel.go:
--------------------------------------------------------------------------------
1 | package testomitempty
2 |
3 | type RemoteModelWithOmitempty struct {
4 | Description string `json:"newDesc,omitempty"`
5 | }
6 |
--------------------------------------------------------------------------------
/_examples/tools.go:
--------------------------------------------------------------------------------
1 | //go:build tools
2 | // +build tools
3 |
4 | package main
5 |
6 | import (
7 | _ "github.com/vektah/dataloaden"
8 | _ "golang.org/x/text"
9 | )
10 |
--------------------------------------------------------------------------------
/_examples/type-system-extension/schemas/type-extension.graphql:
--------------------------------------------------------------------------------
1 | directive @fieldLogging on FIELD_DEFINITION
2 |
3 | extend type Todo {
4 | verified: Boolean! @fieldLogging
5 | }
6 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/variadic.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | variadicModel: VariadicModel
3 | }
4 |
5 | type VariadicModel {
6 | value(rank: Int!): String
7 | }
8 |
--------------------------------------------------------------------------------
/integration/models-go/viewer.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import "github.com/99designs/gqlgen/integration/remote_api"
4 |
5 | type Viewer struct {
6 | User *remote_api.User
7 | }
8 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/variadic.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | variadicModel: VariadicModel
3 | }
4 |
5 | type VariadicModel {
6 | value(rank: Int!): String
7 | }
8 |
--------------------------------------------------------------------------------
/plugin/resolvergen/testdata/return_values/schema.graphqls:
--------------------------------------------------------------------------------
1 | type User {
2 | id: ID!
3 | name: String!
4 | }
5 |
6 | type Query {
7 | user: User!
8 | userPointer: User
9 | }
10 |
--------------------------------------------------------------------------------
/integration/models-go/element.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type Element struct {
4 | ID int
5 | }
6 |
7 | func (e *Element) Mismatched() []Element {
8 | return []Element{*e}
9 | }
10 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/ptr_to_slice.graphql:
--------------------------------------------------------------------------------
1 | type PtrToSliceContainer {
2 | ptrToSlice: [String!]
3 | }
4 |
5 | extend type Query {
6 | ptrToSliceContainer: PtrToSliceContainer!
7 | }
8 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/ptr_to_slice.graphql:
--------------------------------------------------------------------------------
1 | type PtrToSliceContainer {
2 | ptrToSlice: [String!]
3 | }
4 |
5 | extend type Query {
6 | ptrToSliceContainer: PtrToSliceContainer!
7 | }
8 |
--------------------------------------------------------------------------------
/plugin/resolvergen/testdata/invalid_model_path/gqlgen.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - "testdata/schema.graphql"
3 |
4 | models:
5 | Resolver:
6 | model: github.com/99designs/invalid/invalid/invalid/nope.Resolver
7 |
--------------------------------------------------------------------------------
/_examples/dataloader/.gqlgen.yml:
--------------------------------------------------------------------------------
1 | models:
2 | Order:
3 | model: github.com/99designs/gqlgen/_examples/dataloader.Order
4 | Customer:
5 | model: github.com/99designs/gqlgen/_examples/dataloader.Customer
6 |
--------------------------------------------------------------------------------
/codegen/config/testdata/cfg/glob/foo/foo.graphql:
--------------------------------------------------------------------------------
1 | type Todo {
2 | id: ID!
3 | text: String!
4 | done: Boolean!
5 | user: User!
6 | }
7 |
8 | type User {
9 | id: ID!
10 | name: String!
11 | }
12 |
--------------------------------------------------------------------------------
/plugin/federation/testdata/schema/customquerytype.graphql:
--------------------------------------------------------------------------------
1 | schema {
2 | query: CustomQuery
3 | }
4 |
5 | type Hello {
6 | name: String!
7 | }
8 |
9 | type CustomQuery {
10 | hello: Hello!
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/testdata/gomod-with-leading-comments.mod:
--------------------------------------------------------------------------------
1 | // main module of gqlgen
2 |
3 | // and another module to test stripping of comment lines
4 |
5 | module github.com/99designs/gqlgen // replace it for new project
6 |
7 | go 1.18
8 |
--------------------------------------------------------------------------------
/codegen/config/testdata/cfg/glob.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - testdata/cfg/glob/**/*.graphql
3 | exec:
4 | filename: generated.go
5 | model:
6 | filename: models_gen.go
7 | resolver:
8 | filename: resolver.go
9 | type: Resolver
10 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/useptr.graphql:
--------------------------------------------------------------------------------
1 | type A {
2 | id: ID!
3 | }
4 |
5 | type B {
6 | id: ID!
7 | }
8 |
9 | union TestUnion = A | B
10 |
11 | extend type Query {
12 | optionalUnion: TestUnion
13 | }
14 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/builtinscalar.graphql:
--------------------------------------------------------------------------------
1 |
2 | """
3 | Since gqlgen defines default implementation for a Map scalar, this tests that the builtin is _not_
4 | added to the TypeMap
5 | """
6 | type Map {
7 | id: ID!
8 | }
9 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/useptr.graphql:
--------------------------------------------------------------------------------
1 | type A {
2 | id: ID!
3 | }
4 |
5 | type B {
6 | id: ID!
7 | }
8 |
9 | union TestUnion = A | B
10 |
11 | extend type Query {
12 | optionalUnion: TestUnion
13 | }
14 |
--------------------------------------------------------------------------------
/codegen/config/testdata/cfg/unwalkable.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - not_walkable/**/*.graphql
3 | exec:
4 | filename: generated.go
5 | model:
6 | filename: models_gen.go
7 | resolver:
8 | filename: resolver.go
9 | type: Resolver
10 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/builtinscalar.graphql:
--------------------------------------------------------------------------------
1 |
2 | """
3 | Since gqlgen defines default implementation for a Map scalar, this tests that the builtin is _not_
4 | added to the TypeMap
5 | """
6 | type Map {
7 | id: ID!
8 | }
9 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/typefallback.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | fallback(arg: FallbackToStringEncoding!): FallbackToStringEncoding!
3 | }
4 |
5 | enum FallbackToStringEncoding {
6 | A
7 | B
8 | C
9 | }
10 |
--------------------------------------------------------------------------------
/plugin/federation/testdata/interfaces/key.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - "testdata/interfaces/key.graphqls"
3 | exec:
4 | filename: testdata/interfaces/generated/exec.go
5 | federation:
6 | filename: testdata/interfaces/generated/federation.go
7 |
--------------------------------------------------------------------------------
/plugin/resolvergen/testdata/return_values/model.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
2 |
3 | package return_values
4 |
5 | type User struct {
6 | ID string `json:"id"`
7 | Name string `json:"name"`
8 | }
9 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### What happened?
2 |
3 | ### What did you expect?
4 |
5 | ### Minimal graphql.schema and models to reproduce
6 |
7 | ### versions
8 | - `go run github.com/99designs/gqlgen version`?
9 | - `go version`?
10 |
--------------------------------------------------------------------------------
/_examples/todo/readme.md:
--------------------------------------------------------------------------------
1 | ### todo app
2 |
3 | This is the simplest example of a graphql server.
4 |
5 | to run this server
6 | ```bash
7 | go run ./server/server.go
8 | ```
9 |
10 | and open http://localhost:8081 in your browser
11 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/otherpkg/model.go:
--------------------------------------------------------------------------------
1 | package otherpkg
2 |
3 | type (
4 | Scalar string
5 | Map map[string]string
6 | Slice []string
7 | )
8 |
9 | type Struct struct {
10 | Name Scalar
11 | Desc *Scalar
12 | }
13 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/typefallback.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | fallback(arg: FallbackToStringEncoding!): FallbackToStringEncoding!
3 | }
4 |
5 | enum FallbackToStringEncoding {
6 | A
7 | B
8 | C
9 | }
10 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/otherpkg/model.go:
--------------------------------------------------------------------------------
1 | package otherpkg
2 |
3 | type (
4 | Scalar string
5 | Map map[string]string
6 | Slice []string
7 | )
8 |
9 | type Struct struct {
10 | Name Scalar
11 | Desc *Scalar
12 | }
13 |
--------------------------------------------------------------------------------
/plugin/federation/testdata/interfaces/extends.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - "testdata/interfaces/extends.graphqls"
3 | exec:
4 | filename: testdata/interfaces/generated/exec.go
5 | federation:
6 | filename: testdata/interfaces/generated/federation.go
7 |
--------------------------------------------------------------------------------
/_examples/federation/reviews/graph/resolver.go:
--------------------------------------------------------------------------------
1 | // This file will not be regenerated automatically.
2 | //
3 | // It serves as dependency injection for your app, add any dependencies you require here.
4 | package graph
5 |
6 | type Resolver struct{}
7 |
--------------------------------------------------------------------------------
/_examples/federation/accounts/graph/resolver.go:
--------------------------------------------------------------------------------
1 | // This file will not be regenerated automatically.
2 | //
3 | // It serves as dependency injection for your app, add any dependencies you require here.
4 | package graph
5 |
6 | type Resolver struct{}
7 |
--------------------------------------------------------------------------------
/_examples/federation/products/graph/resolver.go:
--------------------------------------------------------------------------------
1 | // This file will not be regenerated automatically.
2 | //
3 | // It serves as dependency injection for your app, add any dependencies you require here.
4 | package graph
5 |
6 | type Resolver struct{}
7 |
--------------------------------------------------------------------------------
/_examples/selection/readme.md:
--------------------------------------------------------------------------------
1 | ### selection app
2 |
3 | This is the simplest example of a graphql server.
4 |
5 | to run this server
6 | ```bash
7 | go run ./server/server.go
8 | ```
9 |
10 | and open http://localhost:8086 in your browser
11 |
--------------------------------------------------------------------------------
/_examples/config/todo.graphql:
--------------------------------------------------------------------------------
1 | type Todo {
2 | id: ID! @goField(forceResolver: true)
3 | databaseId: Int!
4 | text: String!
5 | done: Boolean!
6 | user: User!
7 | }
8 |
9 | input NewTodo {
10 | text: String!
11 | userId: String!
12 | }
13 |
--------------------------------------------------------------------------------
/codegen/config/testdata/cfg/glob/bar/bar with spaces.graphql:
--------------------------------------------------------------------------------
1 | type Query {
2 | todos: [Todo!]!
3 | }
4 |
5 | input NewTodo {
6 | text: String!
7 | userId: String!
8 | }
9 |
10 | type Mutation {
11 | createTodo(input: NewTodo!): Todo!
12 | }
13 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/enum.graphql:
--------------------------------------------------------------------------------
1 | enum EnumTest {
2 | OK
3 | NG
4 | }
5 |
6 | input InputWithEnumValue {
7 | enum: EnumTest!
8 | }
9 |
10 | extend type Query {
11 | enumInInput(input: InputWithEnumValue): EnumTest!
12 | }
13 |
--------------------------------------------------------------------------------
/_examples/readme.md:
--------------------------------------------------------------------------------
1 | ### examples
2 |
3 | - todo: A simple todo checklist. A good place to get the basics down
4 | - starwars: A starwars movie database. It has examples of advanced graphql features
5 | - dataloader: How to avoid n+1 database query problems
6 |
--------------------------------------------------------------------------------
/_examples/websocket-initfunc/server/graph/resolver.go:
--------------------------------------------------------------------------------
1 | package graph
2 |
3 | // This file will not be regenerated automatically.
4 | //
5 | // It serves as dependency injection for your app, add any dependencies you require here.
6 |
7 | type Resolver struct{}
8 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/enum.graphql:
--------------------------------------------------------------------------------
1 | enum EnumTest {
2 | OK
3 | NG
4 | }
5 |
6 | input InputWithEnumValue {
7 | enum: EnumTest!
8 | }
9 |
10 | extend type Query {
11 | enumInInput(input: InputWithEnumValue): EnumTest!
12 | }
13 |
--------------------------------------------------------------------------------
/codegen/complexity.go:
--------------------------------------------------------------------------------
1 | package codegen
2 |
3 | func (o *Object) UniqueFields() map[string][]*Field {
4 | m := map[string][]*Field{}
5 |
6 | for _, f := range o.Fields {
7 | m[f.GoFieldName] = append(m[f.GoFieldName], f)
8 | }
9 |
10 | return m
11 | }
12 |
--------------------------------------------------------------------------------
/plugin/resolvergen/testdata/return_values/gqlgen.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - schema.graphqls
3 |
4 | exec:
5 | filename: ignored.go
6 | model:
7 | filename: model.go
8 | resolver:
9 | filename: resolvers.go
10 |
11 | resolvers_always_return_pointers: false
12 |
--------------------------------------------------------------------------------
/plugin/federation/testdata/entityresolver/resolver.go:
--------------------------------------------------------------------------------
1 | package entityresolver
2 |
3 | // This file will not be regenerated automatically.
4 | //
5 | // It serves as dependency injection for your app, add any dependencies you require here.
6 |
7 | type Resolver struct{}
8 |
--------------------------------------------------------------------------------
/_examples/websocket-initfunc/server/graph/model/models_gen.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
2 |
3 | package model
4 |
5 | type Dummy struct {
6 | ID string `json:"id"`
7 | Text string `json:"text"`
8 | Done bool `json:"done"`
9 | }
10 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/weird_type_cases.graphql:
--------------------------------------------------------------------------------
1 | # regression test for https://github.com/99designs/gqlgen/issues/583
2 |
3 | type asdfIt { id: ID! }
4 | type iIt { id: ID! }
5 | type AIt { id: ID! }
6 | type XXIt { id: ID! }
7 | type AbIt { id: ID! }
8 | type XxIt { id: ID! }
9 |
--------------------------------------------------------------------------------
/plugin/federation/testdata/entityresolver/schema.resolvers.go:
--------------------------------------------------------------------------------
1 | package entityresolver
2 |
3 | // This file will be automatically regenerated based on the schema, any resolver implementations
4 | // will be copied through when generating and any unknown code will be moved to the end.
5 |
--------------------------------------------------------------------------------
/plugin/resolvergen/testdata/filetemplate/out/resolver.go:
--------------------------------------------------------------------------------
1 | package customresolver
2 |
3 | // This file will not be regenerated automatically.
4 | //
5 | // It serves as dependency injection for your app, add any dependencies you require here.
6 |
7 | type CustomResolverType struct{}
8 |
--------------------------------------------------------------------------------
/plugin/resolvergen/testdata/followschema/out/resolver.go:
--------------------------------------------------------------------------------
1 | package customresolver
2 |
3 | // This file will not be regenerated automatically.
4 | //
5 | // It serves as dependency injection for your app, add any dependencies you require here.
6 |
7 | type CustomResolverType struct{}
8 |
--------------------------------------------------------------------------------
/.github/workflows/check-fmt:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -euo pipefail
4 |
5 | go fmt ./...
6 | cd _examples && go fmt ./...
7 | if [[ $(git --no-pager diff) ]] ; then
8 | echo "you need to run "go fmt" and commit the changes"
9 | git --no-pager diff
10 | exit 1
11 | fi
12 |
--------------------------------------------------------------------------------
/_examples/todo/gqlgen.yml:
--------------------------------------------------------------------------------
1 | models:
2 | Todo:
3 | model: github.com/99designs/gqlgen/_examples/todo.Todo
4 | ID:
5 | model: # override the default id marshaller to use ints
6 | - github.com/99designs/gqlgen/graphql.IntID
7 | - github.com/99designs/gqlgen/graphql.ID
8 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/slices.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | slices: Slices
3 | scalarSlice: Bytes!
4 | }
5 |
6 | type Slices {
7 | test1: [String]
8 | test2: [String!]
9 | test3: [String]!
10 | test4: [String!]!
11 | }
12 |
13 | scalar Bytes
14 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/weird_type_cases.graphql:
--------------------------------------------------------------------------------
1 | # regression test for https://github.com/99designs/gqlgen/issues/583
2 |
3 | type asdfIt { id: ID! }
4 | type iIt { id: ID! }
5 | type AIt { id: ID! }
6 | type XXIt { id: ID! }
7 | type AbIt { id: ID! }
8 | type XxIt { id: ID! }
9 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/slices.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | slices: Slices
3 | scalarSlice: Bytes!
4 | }
5 |
6 | type Slices {
7 | test1: [String]
8 | test2: [String!]
9 | test3: [String]!
10 | test4: [String!]!
11 | }
12 |
13 | scalar Bytes
14 |
--------------------------------------------------------------------------------
/client/errors.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import "encoding/json"
4 |
5 | // RawJsonError is a json formatted error from a GraphQL server.
6 | type RawJsonError struct {
7 | json.RawMessage
8 | }
9 |
10 | func (r RawJsonError) Error() string {
11 | return string(r.RawMessage)
12 | }
13 |
--------------------------------------------------------------------------------
/_examples/dataloader/readme.md:
--------------------------------------------------------------------------------
1 | ### dataloader
2 |
3 | This example uses [dataloaden](https://github.com/vektah/dataloaden) to avoiding n+1 queries.
4 |
5 |
6 | There is also [nicksrandall/dataloader](https://github.com/nicksrandall/dataloader) if you wanted to avoid
7 | doing more codegeneration.
8 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/mutation_with_custom_scalar.graphql:
--------------------------------------------------------------------------------
1 | extend type Mutation {
2 | updateSomething(input: SpecialInput!): String!
3 | }
4 |
5 | scalar Email
6 |
7 | input SpecialInput {
8 | nesting: NestedInput!
9 | }
10 |
11 | input NestedInput {
12 | field: Email!
13 | }
14 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/scalar_context.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | infinity: Float!
3 | stringFromContextInterface: StringFromContextInterface!
4 | stringFromContextFunction: StringFromContextFunction!
5 | }
6 |
7 | scalar StringFromContextInterface
8 | scalar StringFromContextFunction
9 |
--------------------------------------------------------------------------------
/codegen/config/testdata/autobinding/chat/message.go:
--------------------------------------------------------------------------------
1 | package chat
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | type Message struct {
8 | ID string `json:"id"`
9 | Text string `json:"text"`
10 | CreatedBy string `json:"createdBy"`
11 | CreatedAt time.Time `json:"createdAt"`
12 | }
13 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/mutation_with_custom_scalar.graphql:
--------------------------------------------------------------------------------
1 | extend type Mutation {
2 | updateSomething(input: SpecialInput!): String!
3 | }
4 |
5 | scalar Email
6 |
7 | input SpecialInput {
8 | nesting: NestedInput!
9 | }
10 |
11 | input NestedInput {
12 | field: Email!
13 | }
14 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/scalar_context.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | infinity: Float!
3 | stringFromContextInterface: StringFromContextInterface!
4 | stringFromContextFunction: StringFromContextFunction!
5 | }
6 |
7 | scalar StringFromContextInterface
8 | scalar StringFromContextFunction
9 |
--------------------------------------------------------------------------------
/plugin/federation/testdata/interfaces/extends.graphqls:
--------------------------------------------------------------------------------
1 | interface Hello @extends {
2 | name: String!
3 | secondary: String!
4 | }
5 |
6 | extend type World implements Hello @key(fields: "name") {
7 | name: String! @external
8 | secondary: String!
9 |
10 | tertiary: String!
11 | }
12 |
--------------------------------------------------------------------------------
/.github/workflows/check-generate:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -euo pipefail
4 |
5 | go generate ./...
6 | cd _examples && go generate ./...
7 | if [[ $(git --no-pager diff) ]] ; then
8 | echo "you need to run "go generate ./..." and commit the changes"
9 | git --no-pager diff
10 | exit 1
11 | fi
12 |
--------------------------------------------------------------------------------
/graphql/oneshot.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import "context"
4 |
5 | func OneShot(resp *Response) ResponseHandler {
6 | var oneshot bool
7 |
8 | return func(context context.Context) *Response {
9 | if oneshot {
10 | return nil
11 | }
12 | oneshot = true
13 |
14 | return resp
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/_examples/type-system-extension/schemas/schema-extension.graphql:
--------------------------------------------------------------------------------
1 | extend schema {
2 | mutation: MyMutation
3 | }
4 |
5 | extend type MyQuery {
6 | todo(id: ID!): Todo
7 | }
8 |
9 | type MyMutation {
10 | createTodo(todo: TodoInput!): Todo!
11 | }
12 |
13 | input TodoInput {
14 | text: String!
15 | }
16 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/wrapped_type.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | import "github.com/99designs/gqlgen/codegen/testserver/singlefile/otherpkg"
4 |
5 | type (
6 | WrappedScalar = otherpkg.Scalar
7 | WrappedStruct otherpkg.Struct
8 | WrappedMap otherpkg.Map
9 | WrappedSlice otherpkg.Slice
10 | )
11 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/wrapped_type.go:
--------------------------------------------------------------------------------
1 | package followschema
2 |
3 | import "github.com/99designs/gqlgen/codegen/testserver/followschema/otherpkg"
4 |
5 | type (
6 | WrappedScalar = otherpkg.Scalar
7 | WrappedStruct otherpkg.Struct
8 | WrappedMap otherpkg.Map
9 | WrappedSlice otherpkg.Slice
10 | )
11 |
--------------------------------------------------------------------------------
/integration/.graphqlconfig:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "Project Name": {
4 | "schemaPath": "schema-fetched.graphql",
5 | "extensions": {
6 | "endpoints": {
7 | "dev": {
8 | "url": "${env:SERVER_URL}"
9 | }
10 | }
11 | }
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/_examples/config/user.graphql:
--------------------------------------------------------------------------------
1 | type User
2 | @goModel(model:"github.com/99designs/gqlgen/_examples/config.User") {
3 | id: ID!
4 | name: String! @goField(name:"FullName")
5 | role: role!
6 | }
7 |
8 | type role
9 | @goModel(model:"github.com/99designs/gqlgen/_examples/config.UserRole") {
10 | name: String!
11 | }
12 |
--------------------------------------------------------------------------------
/_examples/starwars/readme.md:
--------------------------------------------------------------------------------
1 | ### starwars example
2 |
3 | This server demonstrates a few advanced features of graphql:
4 | - connections
5 | - unions
6 | - interfaces
7 | - enums
8 |
9 | to run this server
10 | ```bash
11 | go run ./server/server.go
12 | ```
13 |
14 | and open http://localhost:8080 in your browser
15 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/panics.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | panics: Panics
3 | }
4 |
5 | type Panics {
6 | fieldScalarMarshal: [MarshalPanic!]!
7 | fieldFuncMarshal(u: [MarshalPanic!]!): [MarshalPanic!]!
8 | argUnmarshal(u: [MarshalPanic!]!): Boolean!
9 |
10 | }
11 |
12 | scalar MarshalPanic
13 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/panics.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | panics: Panics
3 | }
4 |
5 | type Panics {
6 | fieldScalarMarshal: [MarshalPanic!]!
7 | fieldFuncMarshal(u: [MarshalPanic!]!): [MarshalPanic!]!
8 | argUnmarshal(u: [MarshalPanic!]!): Boolean!
9 |
10 | }
11 |
12 | scalar MarshalPanic
13 |
--------------------------------------------------------------------------------
/plugin/federation/testdata/entities/nokey.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - "testdata/entities/nokey.graphql"
3 | exec:
4 | filename: testdata/entities/generated/exec.go
5 | federation:
6 | filename: testdata/entities/generated/federation.go
7 |
8 | autobind:
9 | - "github.com/99designs/gqlgen/plugin/federation/test_data/model"
10 |
--------------------------------------------------------------------------------
/_examples/federation/accounts/graph/schema.graphqls:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | me: User
3 | }
4 |
5 | type EmailHost @key(fields: "id") {
6 | id: String!
7 | name: String!
8 | }
9 |
10 | type User @key(fields: "id") {
11 | id: ID!
12 | host: EmailHost!
13 | email: String!
14 | username: String!
15 | }
16 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/v-ok.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | vOkCaseValue: VOkCaseValue
3 | vOkCaseNil: VOkCaseNil
4 | }
5 |
6 | type VOkCaseValue @goModel(model:"singlefile.VOkCaseValue") {
7 | value: String
8 | }
9 |
10 | type VOkCaseNil @goModel(model:"singlefile.VOkCaseNil") {
11 | value: String
12 | }
13 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/v-ok.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | vOkCaseValue: VOkCaseValue
3 | vOkCaseNil: VOkCaseNil
4 | }
5 |
6 | type VOkCaseValue @goModel(model:"followschema.VOkCaseValue") {
7 | value: String
8 | }
9 |
10 | type VOkCaseNil @goModel(model:"followschema.VOkCaseNil") {
11 | value: String
12 | }
13 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/fields_order.graphql:
--------------------------------------------------------------------------------
1 | type FieldsOrderPayload {
2 | firstFieldValue: String
3 | }
4 |
5 | input FieldsOrderInput {
6 | firstField: String
7 | overrideFirstField: String
8 | }
9 |
10 | extend type Mutation {
11 | overrideValueViaInput(input: FieldsOrderInput!): FieldsOrderPayload!
12 | }
13 |
--------------------------------------------------------------------------------
/plugin/federation/testdata/schema/customquerytype.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - "testdata/schema/customquerytype.graphql"
3 | exec:
4 | filename: testdata/schema/generated/exec.go
5 | federation:
6 | filename: testdata/schema/generated/federation.go
7 |
8 | autobind:
9 | - "github.com/99designs/gqlgen/plugin/federation/test_data/model"
10 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Describe your PR and link to any relevant issues.
2 |
3 | I have:
4 | - [ ] Added tests covering the bug / feature (see [testing](https://github.com/99designs/gqlgen/blob/master/TESTING.md))
5 | - [ ] Updated any relevant documentation (see [docs](https://github.com/99designs/gqlgen/tree/master/docs/content))
6 |
--------------------------------------------------------------------------------
/_examples/dataloader/models_gen.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
2 |
3 | package dataloader
4 |
5 | type Address struct {
6 | ID int `json:"id"`
7 | Street string `json:"street"`
8 | Country string `json:"country"`
9 | }
10 |
11 | type Item struct {
12 | Name string `json:"name"`
13 | }
14 |
--------------------------------------------------------------------------------
/_examples/todo/models.go:
--------------------------------------------------------------------------------
1 | package todo
2 |
3 | type Ownable interface {
4 | Owner() *User
5 | }
6 |
7 | type Todo struct {
8 | ID int
9 | Text string
10 | Done bool
11 | owner *User
12 | }
13 |
14 | func (t Todo) Owner() *User {
15 | return t.owner
16 | }
17 |
18 | type User struct {
19 | ID int
20 | Name string
21 | }
22 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/fields_order.graphql:
--------------------------------------------------------------------------------
1 | type FieldsOrderPayload {
2 | firstFieldValue: String
3 | }
4 |
5 | input FieldsOrderInput {
6 | firstField: String
7 | overrideFirstField: String
8 | }
9 |
10 | extend type Mutation {
11 | overrideValueViaInput(input: FieldsOrderInput!): FieldsOrderPayload!
12 | }
13 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/complexity.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | overlapping: OverlappingFields
3 | }
4 |
5 | type OverlappingFields {
6 | oneFoo: Int! @goField(name: "foo")
7 | twoFoo: Int! @goField(name: "foo")
8 | oldFoo: Int! @goField(name: "foo", forceResolver: true)
9 | newFoo: Int!
10 | new_foo: Int!
11 | }
12 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/complexity.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | overlapping: OverlappingFields
3 | }
4 |
5 | type OverlappingFields {
6 | oneFoo: Int! @goField(name: "foo")
7 | twoFoo: Int! @goField(name: "foo")
8 | oldFoo: Int! @goField(name: "foo", forceResolver: true)
9 | newFoo: Int!
10 | new_foo: Int!
11 | }
12 |
--------------------------------------------------------------------------------
/integration/readme.md:
--------------------------------------------------------------------------------
1 | # Integration tests
2 |
3 | These tests run a gqlgen server against the apollo client to test real world connectivity.
4 |
5 | First start the go server
6 | ```bash
7 | go run integration/server/server.go
8 | ```
9 |
10 | And in another terminal:
11 | ```bash
12 | cd integration
13 | npm ci
14 | npm run test
15 | ```
16 |
--------------------------------------------------------------------------------
/_examples/starwars/.gqlgen.yml:
--------------------------------------------------------------------------------
1 | exec:
2 | filename: generated/exec.go
3 | model:
4 | filename: models/generated.go
5 |
6 | autobind:
7 | - github.com/99designs/gqlgen/_examples/starwars/models
8 |
9 | models:
10 | ReviewInput:
11 | model: models.Review
12 | Starship:
13 | fields:
14 | length:
15 | resolver: true
16 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/v-ok.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | // VOkCaseValue model
4 | type VOkCaseValue struct{}
5 |
6 | func (v VOkCaseValue) Value() (string, bool) {
7 | return "hi", true
8 | }
9 |
10 | // VOkCaseNil model
11 | type VOkCaseNil struct{}
12 |
13 | func (v VOkCaseNil) Value() (string, bool) {
14 | return "", false
15 | }
16 |
--------------------------------------------------------------------------------
/plugin/resolvergen/testdata/filetemplate/out/model.go:
--------------------------------------------------------------------------------
1 | package customresolver
2 |
3 | import "context"
4 |
5 | type Resolver struct{}
6 |
7 | type QueryResolver interface {
8 | Resolver(ctx context.Context) (*Resolver, error)
9 | }
10 |
11 | type ResolverResolver interface {
12 | Name(ctx context.Context, obj *Resolver) (string, error)
13 | }
14 |
--------------------------------------------------------------------------------
/plugin/resolvergen/testdata/followschema/out/model.go:
--------------------------------------------------------------------------------
1 | package customresolver
2 |
3 | import "context"
4 |
5 | type Resolver struct{}
6 |
7 | type QueryResolver interface {
8 | Resolver(ctx context.Context) (*Resolver, error)
9 | }
10 |
11 | type ResolverResolver interface {
12 | Name(ctx context.Context, obj *Resolver) (string, error)
13 | }
14 |
--------------------------------------------------------------------------------
/plugin/resolvergen/testdata/singlefile/out/model.go:
--------------------------------------------------------------------------------
1 | package customresolver
2 |
3 | import "context"
4 |
5 | type Resolver struct{}
6 |
7 | type QueryResolver interface {
8 | Resolver(ctx context.Context) (*Resolver, error)
9 | }
10 |
11 | type ResolverResolver interface {
12 | Name(ctx context.Context, obj *Resolver) (string, error)
13 | }
14 |
--------------------------------------------------------------------------------
/_examples/embedding/subdir/cfgdir/generate_in_subdir.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - schemadir/*.graphqls
3 | - ../*.graphqls
4 | - '*.graphqls'
5 | exec:
6 | layout: follow-schema
7 | dir: .
8 | package: subdir
9 |
10 | federation:
11 | filename: federation_gen.go
12 | package: subdir
13 |
14 | model:
15 | filename: model.go
16 | package: subdir
--------------------------------------------------------------------------------
/_examples/scalars/model/generated.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
2 |
3 | package model
4 |
5 | import (
6 | "github.com/99designs/gqlgen/_examples/scalars/external"
7 | )
8 |
9 | type Address struct {
10 | ID external.ObjectID `json:"id"`
11 | Location *Point `json:"location,omitempty"`
12 | }
13 |
--------------------------------------------------------------------------------
/_examples/websocket-initfunc/server/graph/schema.graphqls:
--------------------------------------------------------------------------------
1 | # GraphQL schema example
2 | #
3 |
4 | type Dummy {
5 | id: ID!
6 | text: String!
7 | done: Boolean!
8 | }
9 |
10 | type Mutation {
11 | postMessageTo(subscriber: String!, content: String!): ID!
12 | }
13 |
14 | type Subscription {
15 | subscribe(subscriber: String!): String!
16 | }
17 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/v-ok.go:
--------------------------------------------------------------------------------
1 | package followschema
2 |
3 | // VOkCaseValue model
4 | type VOkCaseValue struct{}
5 |
6 | func (v VOkCaseValue) Value() (string, bool) {
7 | return "hi", true
8 | }
9 |
10 | // VOkCaseNil model
11 | type VOkCaseNil struct{}
12 |
13 | func (v VOkCaseNil) Value() (string, bool) {
14 | return "", false
15 | }
16 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/useptr_test.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | import (
4 | "reflect"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func TestUserPtr(t *testing.T) {
11 | s := &Stub{}
12 | r := reflect.TypeOf(s.QueryResolver.OptionalUnion)
13 | require.True(t, r.Out(0).Kind() == reflect.Interface)
14 | }
15 |
--------------------------------------------------------------------------------
/integration/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | testEnvironment: "node",
3 | testMatch: ["/**/*-test.js"],
4 | testPathIgnorePatterns: ["/node_modules/"],
5 | moduleFileExtensions: ["js"],
6 | modulePaths: ["/node_modules"],
7 | transform: {
8 | '^.+\\.jsx?$': 'babel-jest',
9 | },
10 | };
11 |
--------------------------------------------------------------------------------
/plugin/federation/testdata/allthethings/gqlgen.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - "testdata/allthethings/schema.graphql"
3 | exec:
4 | filename: testdata/allthethings/generated/exec.go
5 | federation:
6 | filename: testdata/allthethings/generated/federation.go
7 |
8 | autobind:
9 | - "github.com/99designs/gqlgen/plugin/federation/testdata/allthethings/model"
10 |
--------------------------------------------------------------------------------
/_examples/chat/models_gen.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
2 |
3 | package chat
4 |
5 | import (
6 | "time"
7 | )
8 |
9 | type Message struct {
10 | ID string `json:"id"`
11 | Text string `json:"text"`
12 | CreatedBy string `json:"createdBy"`
13 | CreatedAt time.Time `json:"createdAt"`
14 | }
15 |
--------------------------------------------------------------------------------
/_examples/type-system-extension/gqlgen.yml:
--------------------------------------------------------------------------------
1 | # .gqlgen.yml example
2 | #
3 | # Refer to https://gqlgen.com/config/
4 | # for detailed .gqlgen.yml documentation.
5 |
6 | schema:
7 | - ./schemas/*.graphql
8 |
9 | exec:
10 | filename: generated.go
11 | model:
12 | filename: models_gen.go
13 | resolver:
14 | filename: resolver.go
15 | type: Resolver
16 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/primitive_objects.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | primitiveObject: [Primitive!]!
3 | primitiveStringObject: [PrimitiveString!]!
4 | }
5 |
6 | type Primitive {
7 | value: Int!
8 | squared: Int!
9 | }
10 |
11 | type PrimitiveString {
12 | value: String!
13 | doubled: String!
14 | len: Int!
15 | }
16 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/useptr_test.go:
--------------------------------------------------------------------------------
1 | package followschema
2 |
3 | import (
4 | "reflect"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func TestUserPtr(t *testing.T) {
11 | s := &Stub{}
12 | r := reflect.TypeOf(s.QueryResolver.OptionalUnion)
13 | require.True(t, r.Out(0).Kind() == reflect.Interface)
14 | }
15 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/primitive_objects.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | primitiveObject: [Primitive!]!
3 | primitiveStringObject: [PrimitiveString!]!
4 | }
5 |
6 | type Primitive {
7 | value: Int!
8 | squared: Int!
9 | }
10 |
11 | type PrimitiveString {
12 | value: String!
13 | doubled: String!
14 | len: Int!
15 | }
16 |
--------------------------------------------------------------------------------
/_examples/federation/reviews/graph/model/models_gen.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
2 |
3 | package model
4 |
5 | type EmailHost struct {
6 | ID string `json:"id"`
7 | }
8 |
9 | func (EmailHost) IsEntity() {}
10 |
11 | type Manufacturer struct {
12 | ID string `json:"id"`
13 | }
14 |
15 | func (Manufacturer) IsEntity() {}
16 |
--------------------------------------------------------------------------------
/plugin/federation/testdata/federation2/federation2.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - "testdata/federation2/federation2.graphql"
3 | exec:
4 | filename: testdata/federation2/generated/exec.go
5 | federation:
6 | filename: testdata/federation2/generated/federation.go
7 | version: 2
8 |
9 | autobind:
10 | - "github.com/99designs/gqlgen/plugin/federation/test_data/model"
11 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/variadic.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | import (
4 | "context"
5 | "strconv"
6 | )
7 |
8 | type VariadicModel struct{}
9 |
10 | type VariadicModelOption func(*VariadicModel)
11 |
12 | func (v VariadicModel) Value(ctx context.Context, rank int, opts ...VariadicModelOption) (string, error) {
13 | return strconv.Itoa(rank), nil
14 | }
15 |
--------------------------------------------------------------------------------
/_examples/config/schema.graphql:
--------------------------------------------------------------------------------
1 | directive @goModel(model: String, models: [String!]) on OBJECT | INPUT_OBJECT | SCALAR | ENUM | INTERFACE | UNION
2 | directive @goField(forceResolver: Boolean, name: String) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION
3 |
4 | type Query {
5 | todos: [Todo!]!
6 | }
7 |
8 | type Mutation {
9 | createTodo(input: NewTodo!): Todo!
10 | }
11 |
--------------------------------------------------------------------------------
/_examples/federation/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | testEnvironment: "node",
3 | testMatch: ["/**/*-test.js"],
4 | testPathIgnorePatterns: ["/node_modules/"],
5 | moduleFileExtensions: ["js"],
6 | modulePaths: ["/node_modules"],
7 | // transform: {
8 | // '^.+\\.jsx?$': 'babel-jest',
9 | // },
10 | };
11 |
--------------------------------------------------------------------------------
/client/readme.md:
--------------------------------------------------------------------------------
1 | This client is used internally for testing. I wanted a simple graphql client sent user specified queries.
2 |
3 | You might want to look at:
4 | - https://github.com/shurcooL/graphql: Uses reflection to build queries from structs.
5 | - https://github.com/machinebox/graphql: Probably would have been a perfect fit, but it uses form encoding instead of json...
6 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/variadic.go:
--------------------------------------------------------------------------------
1 | package followschema
2 |
3 | import (
4 | "context"
5 | "strconv"
6 | )
7 |
8 | type VariadicModel struct{}
9 |
10 | type VariadicModelOption func(*VariadicModel)
11 |
12 | func (v VariadicModel) Value(ctx context.Context, rank int, opts ...VariadicModelOption) (string, error) {
13 | return strconv.Itoa(rank), nil
14 | }
15 |
--------------------------------------------------------------------------------
/_examples/config/model.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import "fmt"
4 |
5 | type User struct {
6 | ID string
7 | FirstName, LastName string
8 | Role UserRole
9 | }
10 |
11 | func (user *User) FullName() string {
12 | return fmt.Sprintf("%s %s", user.FirstName, user.LastName)
13 | }
14 |
15 | type UserRole struct {
16 | RoleName string
17 | }
18 |
--------------------------------------------------------------------------------
/_examples/embedding/subdir/cfgdir/generate_in_gendir.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - schemadir/*.graphqls
3 | - ../*.graphqls
4 | - '*.graphqls'
5 | exec:
6 | dir: gendir
7 | filename: gendir/generated.go
8 | package: gendir
9 |
10 | federation:
11 | filename: gendir/federation_gen.go
12 | package: gendir
13 |
14 | model:
15 | filename: gendir/model.go
16 | package: gendir
--------------------------------------------------------------------------------
/graphql/any.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import (
4 | "encoding/json"
5 | "io"
6 | )
7 |
8 | func MarshalAny(v interface{}) Marshaler {
9 | return WriterFunc(func(w io.Writer) {
10 | err := json.NewEncoder(w).Encode(v)
11 | if err != nil {
12 | panic(err)
13 | }
14 | })
15 | }
16 |
17 | func UnmarshalAny(v interface{}) (interface{}, error) {
18 | return v, nil
19 | }
20 |
--------------------------------------------------------------------------------
/graphql/context_path_test.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func TestGetFieldInputContext(t *testing.T) {
11 | require.Nil(t, GetFieldContext(context.Background()))
12 |
13 | rc := &PathContext{}
14 | require.Equal(t, rc, GetPathContext(WithPathContext(context.Background(), rc)))
15 | }
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | /docs/public
3 | /docs/.hugo_build.lock
4 | /_examples/chat/node_modules
5 | /integration/node_modules
6 | /integration/schema-fetched.graphql
7 | /_examples/chat/package-lock.json
8 | /_examples/federation/package-lock.json
9 | /_examples/federation/node_modules
10 | /codegen/gen
11 | /gen
12 |
13 | /.vscode
14 | .idea/
15 | *.test
16 | *.out
17 | gqlgen
18 | *.exe
19 |
--------------------------------------------------------------------------------
/_examples/websocket-initfunc/server/Makefile:
--------------------------------------------------------------------------------
1 | bin_name=server
2 |
3 | build:
4 | @echo "building binary..."
5 | # go generate gives missing go sum entry for module errors
6 | # https://github.com/99designs/gqlgen/issues/1483
7 | # you will need to first do a go get -u github.com/99designs/gqlgen
8 | go run -mod=mod github.com/99designs/gqlgen generate .
9 | go build -o ${bin_name} server.go
10 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/scalar_default.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | defaultScalar(arg: DefaultScalarImplementation! = "default"): DefaultScalarImplementation!
3 | }
4 |
5 | """ This doesnt have an implementation in the typemap, so it should act like a string """
6 | scalar DefaultScalarImplementation
7 |
8 | type EmbeddedDefaultScalar {
9 | value: DefaultScalarImplementation
10 | }
11 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/scalar_default.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | defaultScalar(arg: DefaultScalarImplementation! = "default"): DefaultScalarImplementation!
3 | }
4 |
5 | """ This doesnt have an implementation in the typemap, so it should act like a string """
6 | scalar DefaultScalarImplementation
7 |
8 | type EmbeddedDefaultScalar {
9 | value: DefaultScalarImplementation
10 | }
11 |
--------------------------------------------------------------------------------
/graphql/context_root_field_test.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func TestGetRootFieldContext(t *testing.T) {
11 | require.Nil(t, GetRootFieldContext(context.Background()))
12 |
13 | rc := &RootFieldContext{}
14 | require.Equal(t, rc, GetRootFieldContext(WithRootFieldContext(context.Background(), rc)))
15 | }
16 |
--------------------------------------------------------------------------------
/plugin/federation/fedruntime/runtime.go:
--------------------------------------------------------------------------------
1 | package fedruntime
2 |
3 | // Service is the service object that the
4 | // generated.go file will return for the _service
5 | // query
6 | type Service struct {
7 | SDL string `json:"sdl"`
8 | }
9 |
10 | // Everything with a @key implements this
11 | type Entity interface {
12 | IsEntity()
13 | }
14 |
15 | // Used for the Link directive
16 | type Link interface{}
17 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | charset = utf-8
6 | trim_trailing_whitespace = true
7 | insert_final_newline = true
8 | indent_style = space
9 | indent_size = 4
10 |
11 | [*.{go,gotpl}]
12 | indent_style = tab
13 |
14 | [*.yml]
15 | indent_size = 2
16 |
17 | # These often end up with go code inside, so lets keep tabs
18 | [*.{html,md}]
19 | indent_size = 2
20 | indent_style = tab
21 |
--------------------------------------------------------------------------------
/_examples/chat/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 | /corpus
9 |
10 | # production
11 | /build
12 |
13 | # misc
14 | .DS_Store
15 | .env.local
16 | .env.development.local
17 | .env.test.local
18 | .env.production.local
19 |
20 | npm-debug.log*
21 | yarn-debug.log*
22 | yarn-error.log*
23 |
--------------------------------------------------------------------------------
/.chglog/config.yml:
--------------------------------------------------------------------------------
1 | style: github
2 | template: CHANGELOG-full-history.tpl.md
3 | info:
4 | title: CHANGELOG
5 | repository_url: https://github.com/99designs/gqlgen
6 | options:
7 | commits:
8 | # filters:
9 | # Type: []
10 | commit_groups:
11 | # title_maps: []
12 | header:
13 | pattern: "^(.*)$"
14 | pattern_maps:
15 | - Subject
16 | notes:
17 | keywords:
18 | - BREAKING CHANGE
--------------------------------------------------------------------------------
/plugin/federation/testdata/entityresolver/generated/errors.go:
--------------------------------------------------------------------------------
1 | package generated
2 |
3 | import "errors"
4 |
5 | // Errors defined for retained code that we want to stick around between generations.
6 | var (
7 | ErrResolvingHelloWithErrorsByName = errors.New("error resolving HelloWithErrorsByName")
8 | ErrEmptyKeyResolvingHelloWithErrorsByName = errors.New("error (empty key) resolving HelloWithErrorsByName")
9 | )
10 |
--------------------------------------------------------------------------------
/graphql/handler/transport/headers.go:
--------------------------------------------------------------------------------
1 | package transport
2 |
3 | import "net/http"
4 |
5 | func writeHeaders(w http.ResponseWriter, headers map[string][]string) {
6 | if len(headers) == 0 {
7 | headers = map[string][]string{
8 | "Content-Type": {"application/json"},
9 | }
10 | }
11 |
12 | for key, values := range headers {
13 | for _, value := range values {
14 | w.Header().Add(key, value)
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/_examples/federation/products/graph/schema.graphqls:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | topProducts(first: Int = 5): [Product]
3 | }
4 |
5 | type Manufacturer @key(fields: "id") {
6 | id: String!
7 | name: String!
8 | }
9 |
10 | type Product @key(fields: "manufacturer { id } id") @key(fields: "upc") {
11 | id: String!
12 | manufacturer: Manufacturer!
13 | upc: String!
14 | name: String!
15 | price: Int!
16 | }
17 |
--------------------------------------------------------------------------------
/graphql/bool_test.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import (
4 | "bytes"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestBoolean(t *testing.T) {
11 | assert.Equal(t, "true", doBooleanMarshal(true))
12 | assert.Equal(t, "false", doBooleanMarshal(false))
13 | }
14 |
15 | func doBooleanMarshal(b bool) string {
16 | var buf bytes.Buffer
17 | MarshalBoolean(b).MarshalGQL(&buf)
18 | return buf.String()
19 | }
20 |
--------------------------------------------------------------------------------
/internal/imports/testdata/unused.go:
--------------------------------------------------------------------------------
1 | package testdata
2 |
3 | import (
4 | a "fmt"
5 | "time"
6 | _ "underscore"
7 | )
8 |
9 | type foo struct {
10 | Time time.Time `json:"text"`
11 | }
12 |
13 | func fn() {
14 | a.Println("hello")
15 | }
16 |
17 | type Message struct {
18 | ID string `json:"id"`
19 | Text string `json:"text"`
20 | CreatedBy string `json:"createdBy"`
21 | CreatedAt time.Time `json:"createdAt"`
22 | }
23 |
--------------------------------------------------------------------------------
/plugin/resolvergen/testdata/singlefile/gqlgen.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - "testdata/schema.graphql"
3 |
4 | exec:
5 | filename: testdata/singlefile/out/ignored.go
6 | model:
7 | filename: testdata/singlefile/out/generated.go
8 | resolver:
9 | filename: testdata/singlefile/out/resolver.go
10 | type: CustomResolverType
11 |
12 | models:
13 | Resolver:
14 | model: github.com/99designs/gqlgen/plugin/resolvergen/testdata/singlefile/out.Resolver
15 |
--------------------------------------------------------------------------------
/_examples/config/models_gen.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
2 |
3 | package config
4 |
5 | type NewTodo struct {
6 | Text string `json:"text"`
7 | UserID string `json:"userId"`
8 | }
9 |
10 | type Todo struct {
11 | ID string `json:"id"`
12 | DatabaseID int `json:"databaseId"`
13 | Description string `json:"text"`
14 | Done bool `json:"done"`
15 | User *User `json:"user"`
16 | }
17 |
--------------------------------------------------------------------------------
/internal/imports/testdata/unused.expected.go:
--------------------------------------------------------------------------------
1 | package testdata
2 |
3 | import (
4 | a "fmt"
5 | "time"
6 | _ "underscore"
7 | )
8 |
9 | type foo struct {
10 | Time time.Time `json:"text"`
11 | }
12 |
13 | func fn() {
14 | a.Println("hello")
15 | }
16 |
17 | type Message struct {
18 | ID string `json:"id"`
19 | Text string `json:"text"`
20 | CreatedBy string `json:"createdBy"`
21 | CreatedAt time.Time `json:"createdAt"`
22 | }
23 |
--------------------------------------------------------------------------------
/internal/rewrite/testdata/example.go:
--------------------------------------------------------------------------------
1 | package testdata
2 |
3 | import (
4 | "fmt"
5 |
6 | lol "bytes"
7 | )
8 |
9 | type Foo struct {
10 | Field int
11 | }
12 |
13 | func (m *Foo) Method(arg int) {
14 | // leading comment
15 |
16 | // field comment
17 | m.Field++
18 |
19 | // trailing comment
20 | }
21 |
22 | func (m *Foo) String() string {
23 | var buf lol.Buffer
24 | buf.WriteString(fmt.Sprintf("%d", m.Field))
25 | return buf.String()
26 | }
27 |
--------------------------------------------------------------------------------
/.github/workflows/check-federation:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -euo pipefail
4 |
5 | cd _examples/federation
6 |
7 | ./start.sh &
8 |
9 | sleep 5
10 | curl -s --connect-timeout 5 \
11 | --max-time 10 \
12 | --retry 5 \
13 | --retry-delay 5 \
14 | --retry-max-time 40 \
15 | --retry-connrefused \
16 | localhost:4003 > /dev/null
17 |
18 | sleep 1
19 |
20 | echo "### running jest integration spec"
21 | ./node_modules/.bin/jest --color
22 |
23 |
--------------------------------------------------------------------------------
/_examples/type-system-extension/schemas/schema.graphql:
--------------------------------------------------------------------------------
1 | # GraphQL schema example
2 | #
3 | # https://gqlgen.com/getting-started/
4 |
5 | schema {
6 | query: MyQuery
7 | }
8 |
9 | interface Node {
10 | id: ID!
11 | }
12 |
13 | type Todo implements Node {
14 | id: ID!
15 | text: String!
16 | state: State!
17 | }
18 |
19 | type MyQuery {
20 | todos: [Todo!]!
21 | }
22 |
23 | union Data = Todo
24 |
25 | enum State {
26 | NOT_YET
27 | DONE
28 | }
29 |
--------------------------------------------------------------------------------
/plugin/resolvergen/testdata/followschema/gqlgen.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - "testdata/schema.graphql"
3 |
4 | exec:
5 | filename: testdata/singlefile/out/ignored.go
6 | model:
7 | filename: testdata/singlefile/out/generated.go
8 | resolver:
9 | type: CustomResolverType
10 | layout: follow-schema
11 | dir: testdata/followschema/out
12 |
13 | models:
14 | Resolver:
15 | model: github.com/99designs/gqlgen/plugin/resolvergen/testdata/singlefile/out.Resolver
16 |
--------------------------------------------------------------------------------
/_examples/chat/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | React App
8 |
9 |
10 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/init-templates/schema.graphqls:
--------------------------------------------------------------------------------
1 | # GraphQL schema example
2 | #
3 | # https://gqlgen.com/getting-started/
4 |
5 | type Todo {
6 | id: ID!
7 | text: String!
8 | done: Boolean!
9 | user: User!
10 | }
11 |
12 | type User {
13 | id: ID!
14 | name: String!
15 | }
16 |
17 | type Query {
18 | todos: [Todo!]!
19 | }
20 |
21 | input NewTodo {
22 | text: String!
23 | userId: String!
24 | }
25 |
26 | type Mutation {
27 | createTodo(input: NewTodo!): Todo!
28 | }
29 |
--------------------------------------------------------------------------------
/api/testdata/default/graph/schema.graphqls:
--------------------------------------------------------------------------------
1 | # GraphQL schema example
2 | #
3 | # https://gqlgen.com/getting-started/
4 |
5 | type Todo {
6 | id: ID!
7 | text: String!
8 | done: Boolean!
9 | user: User!
10 | }
11 |
12 | type User {
13 | id: ID!
14 | name: String!
15 | }
16 |
17 | type Query {
18 | todos: [Todo!]!
19 | }
20 |
21 | input NewTodo {
22 | text: String!
23 | userId: String!
24 | }
25 |
26 | type Mutation {
27 | createTodo(input: NewTodo!): Todo!
28 | }
29 |
--------------------------------------------------------------------------------
/graphql/handler/extension/introspection_test.go:
--------------------------------------------------------------------------------
1 | package extension
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/99designs/gqlgen/graphql"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func TestIntrospection(t *testing.T) {
12 | rc := &graphql.OperationContext{
13 | DisableIntrospection: true,
14 | }
15 | require.Nil(t, Introspection{}.MutateOperationContext(context.Background(), rc))
16 | require.Equal(t, false, rc.DisableIntrospection)
17 | }
18 |
--------------------------------------------------------------------------------
/graphql/recovery.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "os"
7 | "runtime/debug"
8 |
9 | "github.com/vektah/gqlparser/v2/gqlerror"
10 | )
11 |
12 | type RecoverFunc func(ctx context.Context, err interface{}) (userMessage error)
13 |
14 | func DefaultRecover(ctx context.Context, err interface{}) error {
15 | fmt.Fprintln(os.Stderr, err)
16 | fmt.Fprintln(os.Stderr)
17 | debug.PrintStack()
18 |
19 | return gqlerror.Errorf("internal system error")
20 | }
21 |
--------------------------------------------------------------------------------
/_examples/selection/schema.graphql:
--------------------------------------------------------------------------------
1 | interface Event {
2 | selection: [String!]
3 | collected: [String!]
4 | }
5 |
6 | type Post implements Event {
7 | message: String!
8 | sent: Time!
9 | selection: [String!]
10 | collected: [String!]
11 | }
12 |
13 | type Like implements Event {
14 | reaction: String!
15 | sent: Time!
16 | selection: [String!]
17 | collected: [String!]
18 | }
19 |
20 | type Query {
21 | events: [Event!]
22 | }
23 |
24 | scalar Time
25 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/wrapped_type.graphql:
--------------------------------------------------------------------------------
1 | # regression test for https://github.com/99designs/gqlgen/issues/721
2 |
3 | extend type Query {
4 | wrappedStruct: WrappedStruct!
5 | wrappedScalar: WrappedScalar!
6 | wrappedMap: WrappedMap!
7 | wrappedSlice: WrappedSlice!
8 | }
9 |
10 | type WrappedStruct { name: WrappedScalar!, desc: WrappedScalar }
11 | scalar WrappedScalar
12 | type WrappedMap { get(key: String!): String! }
13 | type WrappedSlice { get(idx: Int!): String! }
14 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/wrapped_type.graphql:
--------------------------------------------------------------------------------
1 | # regression test for https://github.com/99designs/gqlgen/issues/721
2 |
3 | extend type Query {
4 | wrappedStruct: WrappedStruct!
5 | wrappedScalar: WrappedScalar!
6 | wrappedMap: WrappedMap!
7 | wrappedSlice: WrappedSlice!
8 | }
9 |
10 | type WrappedStruct { name: WrappedScalar!, desc: WrappedScalar }
11 | scalar WrappedScalar
12 | type WrappedMap { get(key: String!): String! }
13 | type WrappedSlice { get(idx: Int!): String! }
14 |
--------------------------------------------------------------------------------
/plugin/resolvergen/testdata/filetemplate/gqlgen.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - "testdata/schema.graphql"
3 |
4 | exec:
5 | filename: testdata/singlefile/out/ignored.go
6 | model:
7 | filename: testdata/singlefile/out/generated.go
8 | resolver:
9 | type: CustomResolverType
10 | layout: follow-schema
11 | dir: testdata/filetemplate/out
12 | filename_template: "{name}.custom.go"
13 |
14 | models:
15 | Resolver:
16 | model: github.com/99designs/gqlgen/plugin/resolvergen/testdata/singlefile/out.Resolver
17 |
--------------------------------------------------------------------------------
/_examples/config/server/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "net/http"
6 |
7 | todo "github.com/99designs/gqlgen/_examples/config"
8 | "github.com/99designs/gqlgen/graphql/handler"
9 | "github.com/99designs/gqlgen/graphql/playground"
10 | )
11 |
12 | func main() {
13 | http.Handle("/", playground.Handler("Todo", "/query"))
14 | http.Handle("/query", handler.NewDefaultServer(
15 | todo.NewExecutableSchema(todo.New()),
16 | ))
17 | log.Fatal(http.ListenAndServe(":8081", nil))
18 | }
19 |
--------------------------------------------------------------------------------
/_examples/federation/accounts/graph/model/models_gen.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
2 |
3 | package model
4 |
5 | type EmailHost struct {
6 | ID string `json:"id"`
7 | Name string `json:"name"`
8 | }
9 |
10 | func (EmailHost) IsEntity() {}
11 |
12 | type User struct {
13 | ID string `json:"id"`
14 | Host *EmailHost `json:"host"`
15 | Email string `json:"email"`
16 | Username string `json:"username"`
17 | }
18 |
19 | func (User) IsEntity() {}
20 |
--------------------------------------------------------------------------------
/plugin/federation/testdata/entityresolver/gqlgen.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - "testdata/entityresolver/schema.graphql"
3 | exec:
4 | filename: testdata/entityresolver/generated/exec.go
5 | federation:
6 | filename: testdata/entityresolver/generated/federation.go
7 | model:
8 | filename: testdata/entityresolver/generated/model/models.go
9 | package: model
10 | resolver:
11 | filename: testdata/entityresolver/resolver.go
12 | layout: follow-schema
13 | dir: testdata/entityresolver
14 | package: entityresolver
15 |
--------------------------------------------------------------------------------
/_examples/federation/start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function cleanup {
4 | kill "$ACCOUNTS_PID"
5 | kill "$PRODUCTS_PID"
6 | kill "$REVIEWS_PID"
7 | }
8 | trap cleanup EXIT
9 |
10 | go build -o /tmp/srv-accounts ./accounts
11 | go build -o /tmp/srv-products ./products
12 | go build -o /tmp/srv-reviews ./reviews
13 |
14 | /tmp/srv-accounts &
15 | ACCOUNTS_PID=$!
16 |
17 | /tmp/srv-products &
18 | PRODUCTS_PID=$!
19 |
20 | /tmp/srv-reviews &
21 | REVIEWS_PID=$!
22 |
23 | sleep 1
24 |
25 | node gateway/index.js
26 |
--------------------------------------------------------------------------------
/graphql/map.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io"
7 | )
8 |
9 | func MarshalMap(val map[string]interface{}) Marshaler {
10 | return WriterFunc(func(w io.Writer) {
11 | err := json.NewEncoder(w).Encode(val)
12 | if err != nil {
13 | panic(err)
14 | }
15 | })
16 | }
17 |
18 | func UnmarshalMap(v interface{}) (map[string]interface{}, error) {
19 | if m, ok := v.(map[string]interface{}); ok {
20 | return m, nil
21 | }
22 |
23 | return nil, fmt.Errorf("%T is not a map", v)
24 | }
25 |
--------------------------------------------------------------------------------
/_examples/websocket-initfunc/server/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/gqlgen/_examples/websocket-initfunc/server
2 |
3 | go 1.18
4 |
5 | require (
6 | github.com/99designs/gqlgen v0.17.25
7 | github.com/go-chi/chi v1.5.4
8 | github.com/gorilla/websocket v1.5.0
9 | github.com/rs/cors v1.8.3
10 | github.com/vektah/gqlparser/v2 v2.5.1
11 | )
12 |
13 | require (
14 | github.com/agnivade/levenshtein v1.1.1 // indirect
15 | github.com/hashicorp/golang-lru/v2 v2.0.1 // indirect
16 | github.com/mitchellh/mapstructure v1.5.0 // indirect
17 | )
18 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/ptr_to_ptr_input.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | type PtrToPtrOuter struct {
4 | Name string
5 | Inner *PtrToPtrInner
6 | StupidInner *******PtrToPtrInner
7 | }
8 |
9 | type PtrToPtrInner struct {
10 | Key string
11 | Value string
12 | }
13 |
14 | type UpdatePtrToPtrOuter struct {
15 | Name *string
16 | Inner **UpdatePtrToPtrInner
17 | StupidInner ********UpdatePtrToPtrInner
18 | }
19 |
20 | type UpdatePtrToPtrInner struct {
21 | Key *string
22 | Value *string
23 | }
24 |
--------------------------------------------------------------------------------
/_examples/scalars/server/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "net/http"
6 |
7 | "github.com/99designs/gqlgen/_examples/scalars"
8 | "github.com/99designs/gqlgen/graphql/handler"
9 | "github.com/99designs/gqlgen/graphql/playground"
10 | )
11 |
12 | func main() {
13 | http.Handle("/", playground.Handler("Starwars", "/query"))
14 | http.Handle("/query", handler.NewDefaultServer(scalars.NewExecutableSchema(scalars.Config{Resolvers: &scalars.Resolver{}})))
15 |
16 | log.Fatal(http.ListenAndServe(":8084", nil))
17 | }
18 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/ptr_to_ptr_input.go:
--------------------------------------------------------------------------------
1 | package followschema
2 |
3 | type PtrToPtrOuter struct {
4 | Name string
5 | Inner *PtrToPtrInner
6 | StupidInner *******PtrToPtrInner
7 | }
8 |
9 | type PtrToPtrInner struct {
10 | Key string
11 | Value string
12 | }
13 |
14 | type UpdatePtrToPtrOuter struct {
15 | Name *string
16 | Inner **UpdatePtrToPtrInner
17 | StupidInner ********UpdatePtrToPtrInner
18 | }
19 |
20 | type UpdatePtrToPtrInner struct {
21 | Key *string
22 | Value *string
23 | }
24 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/maps.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | mapStringInterface(in: MapStringInterfaceInput): MapStringInterfaceType
3 | mapNestedStringInterface(in: NestedMapInput): MapStringInterfaceType
4 | }
5 |
6 | type MapStringInterfaceType @goModel(model: "map[string]interface{}") {
7 | a: String
8 | b: Int
9 | }
10 |
11 | input MapStringInterfaceInput @goModel(model: "map[string]interface{}") {
12 | a: String
13 | b: Int
14 | }
15 |
16 | input NestedMapInput {
17 | map: MapStringInterfaceInput
18 | }
19 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/maps.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | mapStringInterface(in: MapStringInterfaceInput): MapStringInterfaceType
3 | mapNestedStringInterface(in: NestedMapInput): MapStringInterfaceType
4 | }
5 |
6 | type MapStringInterfaceType @goModel(model: "map[string]interface{}") {
7 | a: String
8 | b: Int
9 | }
10 |
11 | input MapStringInterfaceInput @goModel(model: "map[string]interface{}") {
12 | a: String
13 | b: Int
14 | }
15 |
16 | input NestedMapInput {
17 | map: MapStringInterfaceInput
18 | }
19 |
--------------------------------------------------------------------------------
/_examples/selection/server/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "net/http"
6 |
7 | "github.com/99designs/gqlgen/_examples/selection"
8 | "github.com/99designs/gqlgen/graphql/handler"
9 | "github.com/99designs/gqlgen/graphql/playground"
10 | )
11 |
12 | func main() {
13 | http.Handle("/", playground.Handler("Selection Demo", "/query"))
14 | http.Handle("/query", handler.NewDefaultServer(selection.NewExecutableSchema(selection.Config{Resolvers: &selection.Resolver{}})))
15 | log.Fatal(http.ListenAndServe(":8086", nil))
16 | }
17 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/defaults.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | defaultParameters(
3 | falsyBoolean: Boolean = false
4 | truthyBoolean: Boolean = true
5 | ): DefaultParametersMirror!
6 | }
7 |
8 | extend type Mutation {
9 | defaultInput(input: DefaultInput!): DefaultParametersMirror!
10 | }
11 |
12 | input DefaultInput {
13 | falsyBoolean: Boolean = false
14 | truthyBoolean: Boolean = true
15 | }
16 |
17 | type DefaultParametersMirror {
18 | falsyBoolean: Boolean
19 | truthyBoolean: Boolean
20 | }
21 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/defaults.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | defaultParameters(
3 | falsyBoolean: Boolean = false
4 | truthyBoolean: Boolean = true
5 | ): DefaultParametersMirror!
6 | }
7 |
8 | extend type Mutation {
9 | defaultInput(input: DefaultInput!): DefaultParametersMirror!
10 | }
11 |
12 | input DefaultInput {
13 | falsyBoolean: Boolean = false
14 | truthyBoolean: Boolean = true
15 | }
16 |
17 | type DefaultParametersMirror {
18 | falsyBoolean: Boolean
19 | truthyBoolean: Boolean
20 | }
21 |
--------------------------------------------------------------------------------
/_examples/config/.gqlgen.yml:
--------------------------------------------------------------------------------
1 | # .gqlgen.yml _examples
2 | #
3 | # Refer to https://gqlgen.com/config/
4 | # for detailed .gqlgen.yml documentation.
5 |
6 | schema: "*.graphql"
7 | exec:
8 | filename: generated.go
9 | model:
10 | filename: models_gen.go
11 | resolver:
12 | type: Resolver
13 | layout: follow-schema
14 | dir: .
15 |
16 | models:
17 | Todo: # Object
18 | fields:
19 | text:
20 | fieldName: Description # Field
21 | NewTodo: # Input
22 | fields:
23 | userId:
24 | fieldName: UserID # Field
25 |
--------------------------------------------------------------------------------
/internal/code/util_test.go:
--------------------------------------------------------------------------------
1 | package code
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | )
8 |
9 | func TestNormalizeVendor(t *testing.T) {
10 | require.Equal(t, "bar/baz", NormalizeVendor("foo/vendor/bar/baz"))
11 | require.Equal(t, "[]bar/baz", NormalizeVendor("[]foo/vendor/bar/baz"))
12 | require.Equal(t, "*bar/baz", NormalizeVendor("*foo/vendor/bar/baz"))
13 | require.Equal(t, "*[]*bar/baz", NormalizeVendor("*[]*foo/vendor/bar/baz"))
14 | require.Equal(t, "[]*bar/baz", NormalizeVendor("[]*foo/vendor/bar/baz"))
15 | }
16 |
--------------------------------------------------------------------------------
/graphql/upload.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | )
7 |
8 | type Upload struct {
9 | File io.ReadSeeker
10 | Filename string
11 | Size int64
12 | ContentType string
13 | }
14 |
15 | func MarshalUpload(f Upload) Marshaler {
16 | return WriterFunc(func(w io.Writer) {
17 | io.Copy(w, f.File)
18 | })
19 | }
20 |
21 | func UnmarshalUpload(v interface{}) (Upload, error) {
22 | upload, ok := v.(Upload)
23 | if !ok {
24 | return Upload{}, fmt.Errorf("%T is not an Upload", v)
25 | }
26 | return upload, nil
27 | }
28 |
--------------------------------------------------------------------------------
/_examples/chat/schema.graphql:
--------------------------------------------------------------------------------
1 | type Chatroom {
2 | name: String!
3 | messages: [Message!]!
4 | }
5 |
6 | type Message {
7 | id: ID!
8 | text: String!
9 | createdBy: String!
10 | createdAt: Time!
11 | }
12 |
13 | type Query {
14 | room(name:String!): Chatroom
15 | }
16 |
17 | type Mutation {
18 | post(text: String!, username: String!, roomName: String!): Message!
19 | }
20 |
21 | type Subscription {
22 | messageAdded(roomName: String!): Message!
23 | }
24 |
25 | scalar Time
26 |
27 | directive @user(username: String!) on SUBSCRIPTION
28 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/issue896.graphql:
--------------------------------------------------------------------------------
1 | # This example should build stable output. If the file content starts
2 | # alternating nondeterministically between two outputs, then see
3 | # https://github.com/99designs/gqlgen/issues/896.
4 |
5 | extend schema {
6 | query: Query
7 | subscription: Subscription
8 | }
9 |
10 | type CheckIssue896 {id: Int}
11 |
12 | extend type Query {
13 | issue896a: [CheckIssue896!] # Note the "!" or lack thereof.
14 | }
15 |
16 | extend type Subscription {
17 | issue896b: [CheckIssue896] # Note the "!" or lack thereof.
18 | }
19 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/issue896.graphql:
--------------------------------------------------------------------------------
1 | # This example should build stable output. If the file content starts
2 | # alternating nondeterministically between two outputs, then see
3 | # https://github.com/99designs/gqlgen/issues/896.
4 |
5 | extend schema {
6 | query: Query
7 | subscription: Subscription
8 | }
9 |
10 | type CheckIssue896 {id: Int}
11 |
12 | extend type Query {
13 | issue896a: [CheckIssue896!] # Note the "!" or lack thereof.
14 | }
15 |
16 | extend type Subscription {
17 | issue896b: [CheckIssue896] # Note the "!" or lack thereof.
18 | }
19 |
--------------------------------------------------------------------------------
/_examples/config/resolver.go:
--------------------------------------------------------------------------------
1 | //go:generate go run ../../testdata/gqlgen.go
2 |
3 | package config
4 |
5 | func New() Config {
6 | c := Config{
7 | Resolvers: &Resolver{
8 | todos: []*Todo{
9 | {DatabaseID: 1, Description: "A todo not to forget", Done: false},
10 | {DatabaseID: 2, Description: "This is the most important", Done: false},
11 | {DatabaseID: 3, Description: "Please do this or else", Done: false},
12 | },
13 | nextID: 3,
14 | },
15 | }
16 | return c
17 | }
18 |
19 | type Resolver struct {
20 | todos []*Todo
21 | nextID int
22 | }
23 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/ptr_to_ptr_input.graphql:
--------------------------------------------------------------------------------
1 | type PtrToPtrOuter {
2 | name: String!
3 | inner: PtrToPtrInner
4 | stupidInner: PtrToPtrInner
5 | }
6 |
7 | type PtrToPtrInner {
8 | key: String!
9 | value: String!
10 | }
11 |
12 | input UpdatePtrToPtrOuter {
13 | name: String
14 | inner: UpdatePtrToPtrInner
15 | stupidInner: UpdatePtrToPtrInner
16 | }
17 |
18 | input UpdatePtrToPtrInner {
19 | key: String
20 | value: String
21 | }
22 |
23 | extend type Mutation {
24 | updatePtrToPtr(input: UpdatePtrToPtrOuter!): PtrToPtrOuter!
25 | }
26 |
--------------------------------------------------------------------------------
/.github/workflows/check-init:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -euo pipefail
4 |
5 | gqlgen_dir=$(pwd)
6 | cd $(mktemp -d)
7 | go mod init inittest
8 | printf '// +build tools\npackage tools\nimport _ "github.com/99designs/gqlgen"' | gofmt > tools.go
9 | go mod tidy
10 | go mod edit -replace=github.com/99designs/gqlgen="$gqlgen_dir"
11 | go mod tidy
12 |
13 | if ! go run github.com/99designs/gqlgen init ; then
14 | echo "gqlgen init failed"
15 | exit 125
16 | fi
17 |
18 | if ! go run github.com/99designs/gqlgen generate ; then
19 | echo "gqlgen generate failed"
20 | exit 125
21 | fi
22 |
--------------------------------------------------------------------------------
/_examples/websocket-initfunc/server/readme.md:
--------------------------------------------------------------------------------
1 | # WebSocket Init App
2 |
3 | Example server app using websocket `InitFunc`.
4 |
5 | ## Build and Run the server app
6 |
7 | First get an update from gqlgen:
8 | ```bash
9 | go mod tidy
10 | go get -u github.com/99designs/gqlgen
11 | ```
12 |
13 | Next just make the build:
14 | ```bash
15 | make build
16 | ```
17 |
18 | Run the server:
19 | ```bash
20 | ./server
21 | 2022/07/07 16:49:46 connect to http://localhost:8080/ for GraphQL playground
22 | ```
23 |
24 | You may now implement a websocket client to subscribe for websocket messages.
--------------------------------------------------------------------------------
/codegen/testserver/followschema/nulls.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | errorBubble: Error
3 | errorBubbleList: [Error!]
4 | errorList: [Error]
5 | errors: Errors
6 | valid: String!
7 | invalid: String!
8 | }
9 |
10 | extend type Subscription {
11 | errorRequired: Error!
12 | }
13 |
14 | type Errors {
15 | a: Error!
16 | b: Error!
17 | c: Error!
18 | d: Error!
19 | e: Error!
20 | }
21 |
22 | type Error {
23 | id: ID!
24 | errorOnNonRequiredField: String
25 | errorOnRequiredField: String!
26 | nilOnRequiredField: String!
27 | }
28 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/ptr_to_ptr_input.graphql:
--------------------------------------------------------------------------------
1 | type PtrToPtrOuter {
2 | name: String!
3 | inner: PtrToPtrInner
4 | stupidInner: PtrToPtrInner
5 | }
6 |
7 | type PtrToPtrInner {
8 | key: String!
9 | value: String!
10 | }
11 |
12 | input UpdatePtrToPtrOuter {
13 | name: String
14 | inner: UpdatePtrToPtrInner
15 | stupidInner: UpdatePtrToPtrInner
16 | }
17 |
18 | input UpdatePtrToPtrInner {
19 | key: String
20 | value: String
21 | }
22 |
23 | extend type Mutation {
24 | updatePtrToPtr(input: UpdatePtrToPtrOuter!): PtrToPtrOuter!
25 | }
26 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/embedded.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | embeddedCase1: EmbeddedCase1
3 | embeddedCase2: EmbeddedCase2
4 | embeddedCase3: EmbeddedCase3
5 | }
6 |
7 | type EmbeddedCase1 @goModel(model:"singlefile.EmbeddedCase1") {
8 | exportedEmbeddedPointerExportedMethod: String!
9 | }
10 |
11 | type EmbeddedCase2 @goModel(model:"singlefile.EmbeddedCase2") {
12 | unexportedEmbeddedPointerExportedMethod: String!
13 | }
14 |
15 | type EmbeddedCase3 @goModel(model:"singlefile.EmbeddedCase3") {
16 | unexportedEmbeddedInterfaceExportedMethod: String!
17 | }
18 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/nulls.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | errorBubble: Error
3 | errorBubbleList: [Error!]
4 | errorList: [Error]
5 | errors: Errors
6 | valid: String!
7 | invalid: String!
8 | }
9 |
10 | extend type Subscription {
11 | errorRequired: Error!
12 | }
13 |
14 | type Errors {
15 | a: Error!
16 | b: Error!
17 | c: Error!
18 | d: Error!
19 | e: Error!
20 | }
21 |
22 | type Error {
23 | id: ID!
24 | errorOnNonRequiredField: String
25 | errorOnRequiredField: String!
26 | nilOnRequiredField: String!
27 | }
28 |
--------------------------------------------------------------------------------
/graphql/time.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import (
4 | "errors"
5 | "io"
6 | "strconv"
7 | "time"
8 | )
9 |
10 | func MarshalTime(t time.Time) Marshaler {
11 | if t.IsZero() {
12 | return Null
13 | }
14 |
15 | return WriterFunc(func(w io.Writer) {
16 | io.WriteString(w, strconv.Quote(t.Format(time.RFC3339Nano)))
17 | })
18 | }
19 |
20 | func UnmarshalTime(v interface{}) (time.Time, error) {
21 | if tmpStr, ok := v.(string); ok {
22 | return time.Parse(time.RFC3339Nano, tmpStr)
23 | }
24 | return time.Time{}, errors.New("time should be RFC3339Nano formatted string")
25 | }
26 |
--------------------------------------------------------------------------------
/_examples/federation/products/graph/model/models_gen.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
2 |
3 | package model
4 |
5 | type Manufacturer struct {
6 | ID string `json:"id"`
7 | Name string `json:"name"`
8 | }
9 |
10 | func (Manufacturer) IsEntity() {}
11 |
12 | type Product struct {
13 | ID string `json:"id"`
14 | Manufacturer *Manufacturer `json:"manufacturer"`
15 | Upc string `json:"upc"`
16 | Name string `json:"name"`
17 | Price int `json:"price"`
18 | }
19 |
20 | func (Product) IsEntity() {}
21 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/embedded.graphql:
--------------------------------------------------------------------------------
1 | extend type Query {
2 | embeddedCase1: EmbeddedCase1
3 | embeddedCase2: EmbeddedCase2
4 | embeddedCase3: EmbeddedCase3
5 | }
6 |
7 | type EmbeddedCase1 @goModel(model:"followschema.EmbeddedCase1") {
8 | exportedEmbeddedPointerExportedMethod: String!
9 | }
10 |
11 | type EmbeddedCase2 @goModel(model:"followschema.EmbeddedCase2") {
12 | unexportedEmbeddedPointerExportedMethod: String!
13 | }
14 |
15 | type EmbeddedCase3 @goModel(model:"followschema.EmbeddedCase3") {
16 | unexportedEmbeddedInterfaceExportedMethod: String!
17 | }
18 |
--------------------------------------------------------------------------------
/_examples/federation/reviews/graph/model/models.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | type Product struct {
4 | ID string `json:"id"`
5 | Manufacturer *Manufacturer `json:"manufacturer"`
6 | Reviews []*Review `json:"reviews"`
7 | }
8 |
9 | func (Product) IsEntity() {}
10 |
11 | type Review struct {
12 | Body string
13 | Author *User
14 | Product *Product
15 | }
16 |
17 | type User struct {
18 | ID string `json:"id"`
19 | Host *EmailHost `json:"host"`
20 | Email string `json:"email"`
21 | // Reviews []*Review `json:"reviews"`
22 | }
23 |
24 | func (User) IsEntity() {}
25 |
--------------------------------------------------------------------------------
/codegen/config/testdata/autobinding/scalars/model/model.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "strings"
7 | )
8 |
9 | type Banned bool
10 |
11 | func (b Banned) MarshalGQL(w io.Writer) {
12 | if b {
13 | w.Write([]byte("true"))
14 | } else {
15 | w.Write([]byte("false"))
16 | }
17 | }
18 |
19 | func (b *Banned) UnmarshalGQL(v interface{}) error {
20 | switch v := v.(type) {
21 | case string:
22 | *b = strings.ToLower(v) == "true"
23 | return nil
24 | case bool:
25 | *b = Banned(v)
26 | return nil
27 | default:
28 | return fmt.Errorf("%T is not a bool", v)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/graphql/bool.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "strings"
7 | )
8 |
9 | func MarshalBoolean(b bool) Marshaler {
10 | if b {
11 | return WriterFunc(func(w io.Writer) { w.Write(trueLit) })
12 | }
13 | return WriterFunc(func(w io.Writer) { w.Write(falseLit) })
14 | }
15 |
16 | func UnmarshalBoolean(v interface{}) (bool, error) {
17 | switch v := v.(type) {
18 | case string:
19 | return strings.ToLower(v) == "true", nil
20 | case int:
21 | return v != 0, nil
22 | case bool:
23 | return v, nil
24 | default:
25 | return false, fmt.Errorf("%T is not a bool", v)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/_examples/chat/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "resolveJsonModule": true,
18 | "isolatedModules": true,
19 | "noEmit": true,
20 | "jsx": "preserve"
21 | },
22 | "include": [
23 | "src"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/docs/layouts/partials/version-switcher.html:
--------------------------------------------------------------------------------
1 | {{ $VersionString := getenv "VERSIONS" }}
2 | {{ $Versions := split $VersionString "," }}
3 | {{ $currentVersion := getenv "CURRENT_VERSION" }}
4 |
5 |
6 |
{{ $currentVersion }}
7 |
8 |
{{$currentVersion}}
9 | {{ range $i, $version := $Versions }}
10 | {{ if not (eq $currentVersion $version) }}
11 |
{{$version}}
12 | {{ end }}
13 | {{ end }}
14 |
15 |
16 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/bytes.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | import (
4 | "fmt"
5 | "io"
6 |
7 | "github.com/99designs/gqlgen/graphql"
8 | )
9 |
10 | func MarshalBytes(b []byte) graphql.Marshaler {
11 | return graphql.WriterFunc(func(w io.Writer) {
12 | _, _ = fmt.Fprintf(w, "%q", string(b))
13 | })
14 | }
15 |
16 | func UnmarshalBytes(v interface{}) ([]byte, error) {
17 | switch v := v.(type) {
18 | case string:
19 | return []byte(v), nil
20 | case *string:
21 | return []byte(*v), nil
22 | case []byte:
23 | return v, nil
24 | default:
25 | return nil, fmt.Errorf("%T is not []byte", v)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/graphql/float_test.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import (
4 | "bytes"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestFloat(t *testing.T) {
11 | assert.Equal(t, "123", m2s(MarshalFloat(123)))
12 | assert.Equal(t, "1.2345678901", m2s(MarshalFloat(1.2345678901)))
13 | assert.Equal(t, "1.2345678901234567", m2s(MarshalFloat(1.234567890123456789)))
14 | assert.Equal(t, "1.2e+20", m2s(MarshalFloat(1.2e+20)))
15 | assert.Equal(t, "1.2e-20", m2s(MarshalFloat(1.2e-20)))
16 | }
17 |
18 | func m2s(m Marshaler) string {
19 | var b bytes.Buffer
20 | m.MarshalGQL(&b)
21 | return b.String()
22 | }
23 |
--------------------------------------------------------------------------------
/_examples/federation/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gateway",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "gateway/index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@apollo/gateway": "^0.42.0",
13 | "apollo-server": "^3.3.0",
14 | "graphql": "^15.6.1"
15 | },
16 | "devDependencies": {
17 | "apollo-cache-inmemory": "^1.6.5",
18 | "apollo-client": "^2.6.8",
19 | "apollo-link-http": "^1.5.16",
20 | "jest": "^25.1.0",
21 | "node-fetch": "^2.6.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/bytes.go:
--------------------------------------------------------------------------------
1 | package followschema
2 |
3 | import (
4 | "fmt"
5 | "io"
6 |
7 | "github.com/99designs/gqlgen/graphql"
8 | )
9 |
10 | func MarshalBytes(b []byte) graphql.Marshaler {
11 | return graphql.WriterFunc(func(w io.Writer) {
12 | _, _ = fmt.Fprintf(w, "%q", string(b))
13 | })
14 | }
15 |
16 | func UnmarshalBytes(v interface{}) ([]byte, error) {
17 | switch v := v.(type) {
18 | case string:
19 | return []byte(v), nil
20 | case *string:
21 | return []byte(*v), nil
22 | case []byte:
23 | return v, nil
24 | default:
25 | return nil, fmt.Errorf("%T is not []byte", v)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/.github/workflows/check-coverage:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -euo pipefail
4 | GO111MODULE=off go get github.com/mattn/goveralls
5 |
6 | go test -covermode atomic -coverprofile=/tmp/coverage.out.tmp -coverpkg=./... $(go list github.com/99designs/gqlgen/... | grep -v _examples)
7 | # ignore protobuf files
8 | cat /tmp/coverage.out.tmp | grep -v ".pb.go" > /tmp/coverage.out
9 |
10 | goveralls -coverprofile=/tmp/coverage.out -service=github -ignore='_examples/*/*,_examples/*/*/*,integration/*,integration/*/*,codegen/testserver/*/*,plugin/federation/testdata/*/*/*,*/generated.go,*/*/generated.go,*/*/*/generated.go,graphql/executable_schema_mock.go'
11 |
--------------------------------------------------------------------------------
/_examples/type-system-extension/README.md:
--------------------------------------------------------------------------------
1 | # Type System Extension example
2 |
3 | https://graphql.github.io/graphql-spec/draft/#sec-Type-System-Extensions
4 |
5 | ```
6 | $ go run ./server/server.go
7 | 2018/10/25 12:46:45 connect to http://localhost:8080/ for GraphQL playground
8 |
9 | $ curl -X POST 'http://localhost:8080/query' --data-binary '{"query":"{ todos { id text state verified } }"}'
10 | {"data":{"todos":[{"id":"Todo:1","text":"Buy a cat food","state":"NOT_YET","verified":false},{"id":"Todo:2","text":"Check cat water","state":"DONE","verified":true},{"id":"Todo:3","text":"Check cat meal","state":"DONE","verified":true}]}}
11 | ```
12 |
--------------------------------------------------------------------------------
/docs/layouts/_default/single.html:
--------------------------------------------------------------------------------
1 | {{ define "main" }}
2 |
3 |
4 |
{{ .LinkTitle }}
5 |
{{ .Title }}
6 |
11 |
12 |
13 |
14 |
15 |
16 | {{partial "version-banner"}}
17 | {{ .Content }}
18 |
19 |
20 | {{ end }}
21 |
--------------------------------------------------------------------------------
/graphql/time_test.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import (
4 | "bytes"
5 | "strconv"
6 | "testing"
7 | "time"
8 |
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func TestTime(t *testing.T) {
13 | t.Run("symmetry", func(t *testing.T) {
14 | initialTime := time.Now()
15 | buf := bytes.NewBuffer([]byte{})
16 | MarshalTime(initialTime).MarshalGQL(buf)
17 |
18 | str, err := strconv.Unquote(buf.String())
19 | require.Nil(t, err)
20 | newTime, err := UnmarshalTime(str)
21 | require.Nil(t, err)
22 |
23 | require.True(t, initialTime.Equal(newTime), "expected times %v and %v to equal", initialTime, newTime)
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/_examples/federation/gateway/index.js:
--------------------------------------------------------------------------------
1 | const { ApolloServer } = require('apollo-server');
2 | const { ApolloGateway } = require("@apollo/gateway");
3 |
4 | const gateway = new ApolloGateway({
5 | serviceList: [
6 | { name: 'accounts', url: 'http://localhost:4001/query' },
7 | { name: 'products', url: 'http://localhost:4002/query' },
8 | { name: 'reviews', url: 'http://localhost:4003/query' }
9 | ],
10 | });
11 |
12 | const server = new ApolloServer({
13 | gateway,
14 |
15 | subscriptions: false,
16 | });
17 |
18 | server.listen().then(({ url }) => {
19 | console.log(`🚀 Server ready at ${url}`);
20 | });
21 |
--------------------------------------------------------------------------------
/_examples/fileupload/model/generated.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
2 |
3 | package model
4 |
5 | import (
6 | "github.com/99designs/gqlgen/graphql"
7 | )
8 |
9 | // The `File` type, represents the response of uploading a file.
10 | type File struct {
11 | ID int `json:"id"`
12 | Name string `json:"name"`
13 | Content string `json:"content"`
14 | ContentType string `json:"contentType"`
15 | }
16 |
17 | // The `UploadFile` type, represents the request for uploading a file with certain payload.
18 | type UploadFile struct {
19 | ID int `json:"id"`
20 | File graphql.Upload `json:"file"`
21 | }
22 |
--------------------------------------------------------------------------------
/graphql/context_root_field.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import (
4 | "context"
5 | )
6 |
7 | const rootResolverCtx key = "root_resolver_context"
8 |
9 | type RootFieldContext struct {
10 | // The name of the type this field belongs to
11 | Object string
12 | // The raw field
13 | Field CollectedField
14 | }
15 |
16 | func GetRootFieldContext(ctx context.Context) *RootFieldContext {
17 | if val, ok := ctx.Value(rootResolverCtx).(*RootFieldContext); ok {
18 | return val
19 | }
20 | return nil
21 | }
22 |
23 | func WithRootFieldContext(ctx context.Context, rc *RootFieldContext) context.Context {
24 | return context.WithValue(ctx, rootResolverCtx, rc)
25 | }
26 |
--------------------------------------------------------------------------------
/_examples/dataloader/schema.graphql:
--------------------------------------------------------------------------------
1 | type Query {
2 | customers: [Customer!]
3 |
4 | # these methods are here to test code generation of nested arrays
5 | torture1d(customerIds: [Int!]): [Customer!]
6 | torture2d(customerIds: [[Int!]]): [[Customer!]]
7 | }
8 |
9 | type Customer {
10 | id: Int!
11 | name: String!
12 | address: Address
13 | orders: [Order!]
14 | }
15 |
16 | type Address {
17 | id: Int!
18 | street: String!
19 | country: String!
20 | }
21 |
22 | type Order {
23 | id: Int!
24 | date: Time!
25 | amount: Float!
26 | items: [Item!]
27 | }
28 |
29 | type Item {
30 | name: String!
31 | }
32 | scalar Time
33 |
--------------------------------------------------------------------------------
/plugin/resolvergen/testdata/return_values/resolvers.go:
--------------------------------------------------------------------------------
1 | package return_values
2 |
3 | // THIS CODE IS A STARTING POINT ONLY. IT WILL NOT BE UPDATED WITH SCHEMA CHANGES.
4 |
5 | import (
6 | "context"
7 | )
8 |
9 | type Resolver struct{}
10 |
11 | // // foo
12 | func (r *queryResolver) User(ctx context.Context) (User, error) {
13 | panic("not implemented")
14 | }
15 |
16 | // // foo
17 | func (r *queryResolver) UserPointer(ctx context.Context) (*User, error) {
18 | panic("not implemented")
19 | }
20 |
21 | // Query returns QueryResolver implementation.
22 | func (r *Resolver) Query() QueryResolver { return &queryResolver{r} }
23 |
24 | type queryResolver struct{ *Resolver }
25 |
--------------------------------------------------------------------------------
/api/testdata/federation2/graph/schema.graphqls:
--------------------------------------------------------------------------------
1 | # GraphQL schema example
2 | #
3 | # https://gqlgen.com/getting-started/
4 | extend schema
5 | @link(url: "https://specs.apollo.dev/federation/v2.0",
6 | import: ["@key", "@shareable", "@provides", "@external", "@tag", "@extends", "@override", "@inaccessible"])
7 |
8 | type Todo {
9 | id: ID!
10 | text: String!
11 | done: Boolean!
12 | user: User!
13 | }
14 |
15 | type User {
16 | id: ID!
17 | name: String!
18 | }
19 |
20 | type Query {
21 | todos: [Todo!]!
22 | }
23 |
24 | input NewTodo {
25 | text: String!
26 | userId: String!
27 | }
28 |
29 | type Mutation {
30 | createTodo(input: NewTodo!): Todo!
31 | }
32 |
--------------------------------------------------------------------------------
/plugin/federation/testdata/federation2/federation2.graphql:
--------------------------------------------------------------------------------
1 | extend schema
2 | @link(url: "https://specs.apollo.dev/federation/v2.0",
3 | import: ["@key", "@shareable", "@provides", "@external", "@tag", "@extends", "@override", "@inaccessible"])
4 |
5 | schema {
6 | query: CustomQuery
7 | }
8 |
9 | type Hello @key(fields:"name", resolvable: false) {
10 | name: String!
11 | }
12 |
13 | type World @key(fields: "foo bar", resolvable: false) {
14 | foo: String!
15 | bar: Int!
16 | }
17 |
18 | extend type ExternalExtension @key(fields: " upc ") {
19 | upc: String!
20 | reviews: [Hello]
21 | }
22 |
23 | type CustomQuery {
24 | hello: Hello!
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/docs/layouts/sitemap.xml:
--------------------------------------------------------------------------------
1 |
2 | {{ range .Data.Pages }}
3 | {{ if or .Description (eq .Kind "home") }}
4 |
5 | {{ .Permalink }}
6 | {{ if not .Lastmod.IsZero }}{{ safeHTML ( .Lastmod.Format "2006-01-02T15:04:05-07:00" ) }}{{ end }}
7 | {{ with .Sitemap.ChangeFreq }}{{ . }}{{ end }}
8 | {{ if ge .Sitemap.Priority 0.0 }}{{ .Sitemap.Priority }}{{ end }}
9 |
10 | {{ end }}
11 | {{ end }}
12 |
13 |
14 |
--------------------------------------------------------------------------------
/plugin/modelgen/out/existing.go:
--------------------------------------------------------------------------------
1 | package out
2 |
3 | type ExistingType struct {
4 | Name *string `json:"name"`
5 | Enum *ExistingEnum `json:"enum"`
6 | Int ExistingInterface `json:"int"`
7 | Existing *MissingTypeNullable `json:"existing"`
8 | }
9 |
10 | type ExistingModel struct {
11 | Name string
12 | Enum ExistingEnum
13 | Int ExistingInterface
14 | }
15 |
16 | type ExistingInput struct {
17 | Name string
18 | Enum ExistingEnum
19 | Int ExistingInterface
20 | }
21 |
22 | type ExistingEnum string
23 |
24 | type ExistingInterface interface {
25 | IsExistingInterface()
26 | }
27 |
28 | type ExistingUnion interface {
29 | IsExistingUnion()
30 | }
31 |
--------------------------------------------------------------------------------
/graphql/handler/transport/websocket_close_reason.go:
--------------------------------------------------------------------------------
1 | package transport
2 |
3 | import (
4 | "context"
5 | )
6 |
7 | // A private key for context that only this package can access. This is important
8 | // to prevent collisions between different context uses
9 | var closeReasonCtxKey = &wsCloseReasonContextKey{"close-reason"}
10 |
11 | type wsCloseReasonContextKey struct {
12 | name string
13 | }
14 |
15 | func AppendCloseReason(ctx context.Context, reason string) context.Context {
16 | return context.WithValue(ctx, closeReasonCtxKey, reason)
17 | }
18 |
19 | func closeReasonForContext(ctx context.Context) string {
20 | reason, _ := ctx.Value(closeReasonCtxKey).(string)
21 | return reason
22 | }
23 |
--------------------------------------------------------------------------------
/plugin/resolvergen/testdata/return_values/return_values_test.go:
--------------------------------------------------------------------------------
1 | package return_values
2 |
3 | import (
4 | "reflect"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | //go:generate rm -f resolvers.go
11 | //go:generate go run ../../../../testdata/gqlgen.go -config gqlgen.yml
12 |
13 | func TestResolverReturnTypes(t *testing.T) {
14 | // verify that the return value of the User resolver is a struct, not a pointer
15 | require.Equal(t, "struct", reflect.TypeOf((&queryResolver{}).User).Out(0).Kind().String())
16 | // the UserPointer resolver should return a pointer
17 | require.Equal(t, "ptr", reflect.TypeOf((&queryResolver{}).UserPointer).Out(0).Kind().String())
18 | }
19 |
--------------------------------------------------------------------------------
/codegen/interface.gotpl:
--------------------------------------------------------------------------------
1 | {{- range $interface := .Interfaces }}
2 |
3 | func (ec *executionContext) _{{$interface.Name}}(ctx context.Context, sel ast.SelectionSet, obj {{$interface.Type | ref}}) graphql.Marshaler {
4 | switch obj := (obj).(type) {
5 | case nil:
6 | return graphql.Null
7 | {{- range $implementor := $interface.Implementors }}
8 | case {{$implementor.Type | ref}}:
9 | {{- if $implementor.CanBeNil }}
10 | if obj == nil {
11 | return graphql.Null
12 | }
13 | {{- end }}
14 | return ec._{{$implementor.Name}}(ctx, sel, {{ if $implementor.TakeRef }}&{{ end }}obj)
15 | {{- end }}
16 | default:
17 | panic(fmt.Errorf("unexpected type %T", obj))
18 | }
19 | }
20 |
21 | {{- end }}
22 |
--------------------------------------------------------------------------------
/integration/gqlgen.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - "schema.graphql"
3 | - "user.graphql"
4 | - "testomitempty.graphql"
5 |
6 | exec:
7 | filename: generated.go
8 | model:
9 | filename: models-go/generated.go
10 | resolver:
11 | filename: resolver.go
12 | type: Resolver
13 |
14 | struct_tag: json
15 |
16 | autobind:
17 | - "github.com/99designs/gqlgen/integration/testomitempty"
18 |
19 | models:
20 | Element:
21 | model: github.com/99designs/gqlgen/integration/models-go.Element
22 | Viewer:
23 | model: github.com/99designs/gqlgen/integration/models-go.Viewer
24 | User:
25 | model: github.com/99designs/gqlgen/integration/remote_api.User
26 | fields:
27 | likes:
28 | resolver: true
29 |
--------------------------------------------------------------------------------
/_examples/dataloader/server/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "net/http"
6 |
7 | "github.com/99designs/gqlgen/_examples/dataloader"
8 | "github.com/99designs/gqlgen/graphql/handler"
9 | "github.com/99designs/gqlgen/graphql/playground"
10 | )
11 |
12 | func main() {
13 | router := http.NewServeMux()
14 |
15 | router.Handle("/", playground.Handler("Dataloader", "/query"))
16 | router.Handle("/query", handler.NewDefaultServer(
17 | dataloader.NewExecutableSchema(dataloader.Config{Resolvers: &dataloader.Resolver{}}),
18 | ))
19 |
20 | log.Println("connect to http://localhost:8082/ for graphql playground")
21 | log.Fatal(http.ListenAndServe(":8082", dataloader.LoaderMiddleware(router)))
22 | }
23 |
--------------------------------------------------------------------------------
/docs/readme.md:
--------------------------------------------------------------------------------
1 | Documentation
2 | ====
3 |
4 | This directory contains the markdown source files for the static doc site hosted at [gqlgen.com](https://gqlgen.com)
5 |
6 |
7 | ## Install hugo
8 |
9 | Before working with these docs you will need to install hugo, see [Quickstart](https://gohugo.io/getting-started/quick-start/) for instructions.
10 |
11 |
12 | ## Editing docs
13 |
14 | When editing docs run `hugo serve` and a live reload server will start, then navigate to http://localhost:1313 in your browser. Any changes made will be updated in the browser.
15 |
16 |
17 | ## Publishing docs
18 |
19 | Docs are hosted using [render.com](https://render.com/) and will be automatically deployed when merging to master.
20 |
21 |
--------------------------------------------------------------------------------
/plugin/modelgen/out_struct_pointers/existing.go:
--------------------------------------------------------------------------------
1 | package out_struct_pointers
2 |
3 | type ExistingType struct {
4 | Name *string `json:"name"`
5 | Enum *ExistingEnum `json:"enum"`
6 | Int ExistingInterface `json:"int"`
7 | Existing *MissingTypeNullable `json:"existing"`
8 | }
9 |
10 | type ExistingModel struct {
11 | Name string
12 | Enum ExistingEnum
13 | Int ExistingInterface
14 | }
15 |
16 | type ExistingInput struct {
17 | Name string
18 | Enum ExistingEnum
19 | Int ExistingInterface
20 | }
21 |
22 | type ExistingEnum string
23 |
24 | type ExistingInterface interface {
25 | IsExistingInterface()
26 | }
27 |
28 | type ExistingUnion interface {
29 | IsExistingUnion()
30 | }
31 |
--------------------------------------------------------------------------------
/_examples/federation/reviews/graph/schema.graphqls:
--------------------------------------------------------------------------------
1 | type Review {
2 | body: String!
3 | author: User! @provides(fields: "username")
4 | product: Product!
5 | }
6 |
7 | extend type EmailHost @key(fields: "id") {
8 | id: String! @external
9 | }
10 |
11 | extend type User @key(fields: "id") {
12 | id: ID! @external
13 | host: EmailHost! @external
14 | email: String! @external
15 | reviews: [Review] @requires(fields: "host {id} email")
16 | }
17 |
18 | extend type Manufacturer @key(fields: "id") {
19 | id: String! @external
20 | }
21 |
22 | extend type Product @key(fields: " manufacturer{ id} id") {
23 | id: String! @external
24 | manufacturer: Manufacturer! @external
25 | reviews: [Review]
26 | }
27 |
--------------------------------------------------------------------------------
/internal/imports/prune_test.go:
--------------------------------------------------------------------------------
1 | package imports
2 |
3 | import (
4 | "os"
5 | "strings"
6 | "testing"
7 |
8 | "github.com/99designs/gqlgen/internal/code"
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func TestPrune(t *testing.T) {
13 | // prime the packages cache so that it's not considered uninitialized
14 |
15 | b, err := Prune("testdata/unused.go", mustReadFile("testdata/unused.go"), &code.Packages{})
16 | require.NoError(t, err)
17 | require.Equal(t, strings.ReplaceAll(string(mustReadFile("testdata/unused.expected.go")), "\r\n", "\n"), string(b))
18 | }
19 |
20 | func mustReadFile(filename string) []byte {
21 | b, err := os.ReadFile(filename)
22 | if err != nil {
23 | panic(err)
24 | }
25 | return b
26 | }
27 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/thirdparty.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "strconv"
7 |
8 | "github.com/99designs/gqlgen/graphql"
9 | )
10 |
11 | type ThirdParty struct {
12 | str string
13 | }
14 |
15 | func MarshalThirdParty(tp ThirdParty) graphql.Marshaler {
16 | return graphql.WriterFunc(func(w io.Writer) {
17 | _, err := io.WriteString(w, strconv.Quote(tp.str))
18 | if err != nil {
19 | panic(err)
20 | }
21 | })
22 | }
23 |
24 | func UnmarshalThirdParty(input interface{}) (ThirdParty, error) {
25 | switch input := input.(type) {
26 | case string:
27 | return ThirdParty{str: input}, nil
28 | default:
29 | return ThirdParty{}, fmt.Errorf("unknown type for input: %s", input)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/thirdparty.go:
--------------------------------------------------------------------------------
1 | package followschema
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "strconv"
7 |
8 | "github.com/99designs/gqlgen/graphql"
9 | )
10 |
11 | type ThirdParty struct {
12 | str string
13 | }
14 |
15 | func MarshalThirdParty(tp ThirdParty) graphql.Marshaler {
16 | return graphql.WriterFunc(func(w io.Writer) {
17 | _, err := io.WriteString(w, strconv.Quote(tp.str))
18 | if err != nil {
19 | panic(err)
20 | }
21 | })
22 | }
23 |
24 | func UnmarshalThirdParty(input interface{}) (ThirdParty, error) {
25 | switch input := input.(type) {
26 | case string:
27 | return ThirdParty{str: input}, nil
28 | default:
29 | return ThirdParty{}, fmt.Errorf("unknown type for input: %s", input)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/docs/layouts/partials/version-banner.html:
--------------------------------------------------------------------------------
1 | {{ $currentVersion := getenv "CURRENT_VERSION" }}
2 | {{ $versionString := getenv "VERSIONS" }}
3 | {{ $versions := split $versionString "," }}
4 | {{ $latestVersion := index $versions 0 }}
5 |
6 | {{ if (eq $currentVersion "master") }}
7 |
8 | You are looking at the docs for the unreleased
master branch. The latest version is
{{ $latestVersion }}.
9 |
10 | {{ else if not (eq $latestVersion $currentVersion) }}
11 |
12 | You are looking at the docs for an older version ({{ $currentVersion }}). The latest version is
{{ $latestVersion }}.
13 |
14 | {{ end }}
15 |
--------------------------------------------------------------------------------
/integration/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "test": "jest"
4 | },
5 | "devDependencies": {
6 | "@babel/core": "^7.11.4",
7 | "@graphql-codegen/cli": "^2.12.1",
8 | "@graphql-codegen/schema-ast": "^2.4.1",
9 | "apollo-cache-inmemory": "^1.6.6",
10 | "apollo-client": "^2.6.10",
11 | "apollo-link-http": "^1.5.17",
12 | "apollo-link-persisted-queries": "^0.2.2",
13 | "apollo-link-ws": "^1.0.20",
14 | "babel-jest": "^24.9.0",
15 | "graphql": "^16.3.0",
16 | "graphql-tag": "^2.12.6",
17 | "jest": "^29.0.3",
18 | "node-fetch": "^2.6.7",
19 | "subscriptions-transport-ws": "^0.9.18",
20 | "ws": "^7.4.6"
21 | },
22 | "dependencies": {
23 | "@babel/preset-env": "^7.11.0"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/_examples/config/user.resolvers.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | // This file will be automatically regenerated based on the schema, any resolver implementations
4 | // will be copied through when generating and any unknown code will be moved to the end.
5 | // Code generated by github.com/99designs/gqlgen version v0.17.27-dev
6 |
7 | import (
8 | "context"
9 | )
10 |
11 | // Name is the resolver for the name field.
12 | func (r *roleResolver) Name(ctx context.Context, obj *UserRole) (string, error) {
13 | if obj == nil {
14 | return "", nil
15 | }
16 | return obj.RoleName, nil
17 | }
18 |
19 | // Role returns RoleResolver implementation.
20 | func (r *Resolver) Role() RoleResolver { return &roleResolver{r} }
21 |
22 | type roleResolver struct{ *Resolver }
23 |
--------------------------------------------------------------------------------
/docs/config.yml:
--------------------------------------------------------------------------------
1 | baseurl: https://gqlgen.com/
2 | metadataformat: yaml
3 | title: gqlgen
4 | enableGitInfo: true
5 | pygmentsCodeFences: true
6 | pygmentsUseClasses: true
7 | canonifyURLs: true
8 |
9 | params:
10 | name: gqlgen
11 | description: graphql servers the easy way
12 |
13 | menu:
14 | main:
15 | - name: Introduction
16 | url: /
17 | weight: -10
18 | - name: Reference
19 | identifier: reference
20 | weight: 5
21 | - name: Recipes
22 | identifier: recipes
23 | weight: 10
24 | - name: pkg.go.dev →
25 | parent: reference
26 | url: https://pkg.go.dev/github.com/99designs/gqlgen
27 |
28 | security:
29 | funcs:
30 | getenv:
31 | - '^HUGO_'
32 | - 'VERSIONS'
33 | - 'CURRENT_VERSION'
34 |
--------------------------------------------------------------------------------
/.golangci.yml:
--------------------------------------------------------------------------------
1 | run:
2 | tests: true
3 | skip-dirs:
4 | - bin
5 |
6 | linters-settings:
7 | errcheck:
8 | ignore: fmt:.*,[rR]ead|[wW]rite|[cC]lose,io:Copy
9 |
10 | linters:
11 | disable-all: true
12 | enable:
13 | - bodyclose
14 | - deadcode
15 | - depguard
16 | - dupl
17 | - errcheck
18 | - gocritic
19 | - gofmt
20 | - goimports
21 | - gosimple
22 | - govet
23 | - ineffassign
24 | - misspell
25 | - nakedret
26 | - prealloc
27 | - staticcheck
28 | - structcheck
29 | - typecheck
30 | - unconvert
31 | - unused
32 | - varcheck
33 |
34 | issues:
35 | exclude-rules:
36 | # Exclude some linters from running on tests files.
37 | - path: _test\.go
38 | linters:
39 | - dupl
40 |
--------------------------------------------------------------------------------
/graphql/context_field_test.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 | "github.com/vektah/gqlparser/v2/ast"
9 | )
10 |
11 | func TestGetResolverContext(t *testing.T) {
12 | require.Nil(t, GetFieldContext(context.Background()))
13 |
14 | rc := &FieldContext{}
15 | require.Equal(t, rc, GetFieldContext(WithFieldContext(context.Background(), rc)))
16 | }
17 |
18 | func testContext(sel ast.SelectionSet) context.Context {
19 | ctx := context.Background()
20 |
21 | rqCtx := &OperationContext{}
22 | ctx = WithOperationContext(ctx, rqCtx)
23 |
24 | root := &FieldContext{
25 | Field: CollectedField{
26 | Selections: sel,
27 | },
28 | }
29 | ctx = WithFieldContext(ctx, root)
30 |
31 | return ctx
32 | }
33 |
--------------------------------------------------------------------------------
/_examples/todo/server/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "log"
7 | "net/http"
8 | "runtime/debug"
9 |
10 | "github.com/99designs/gqlgen/_examples/todo"
11 | "github.com/99designs/gqlgen/graphql/handler"
12 | "github.com/99designs/gqlgen/graphql/playground"
13 | )
14 |
15 | func main() {
16 | srv := handler.NewDefaultServer(todo.NewExecutableSchema(todo.New()))
17 | srv.SetRecoverFunc(func(ctx context.Context, err interface{}) (userMessage error) {
18 | // send this panic somewhere
19 | log.Print(err)
20 | debug.PrintStack()
21 | return errors.New("user message on panic")
22 | })
23 |
24 | http.Handle("/", playground.Handler("Todo", "/query"))
25 | http.Handle("/query", srv)
26 | log.Fatal(http.ListenAndServe(":8081", nil))
27 | }
28 |
--------------------------------------------------------------------------------
/_examples/federation/products/graph/products.go:
--------------------------------------------------------------------------------
1 | package graph
2 |
3 | import "github.com/99designs/gqlgen/_examples/federation/products/graph/model"
4 |
5 | var hats = []*model.Product{
6 | {
7 | ID: "111",
8 | Manufacturer: &model.Manufacturer{
9 | ID: "1234",
10 | Name: "Millinery 1234",
11 | },
12 | Upc: "top-1",
13 | Name: "Trilby",
14 | Price: 11,
15 | },
16 | {
17 | ID: "222",
18 | Manufacturer: &model.Manufacturer{
19 | ID: "2345",
20 | Name: "Millinery 2345",
21 | },
22 | Upc: "top-2",
23 | Name: "Fedora",
24 | Price: 22,
25 | },
26 | {
27 | ID: "333",
28 | Manufacturer: &model.Manufacturer{
29 | ID: "2345",
30 | Name: "Millinery 2345",
31 | },
32 | Upc: "top-3",
33 | Name: "Boater",
34 | Price: 33,
35 | },
36 | }
37 |
--------------------------------------------------------------------------------
/_examples/scalars/.gqlgen.yml:
--------------------------------------------------------------------------------
1 | model:
2 | filename: model/generated.go
3 |
4 | models:
5 | User:
6 | model: github.com/99designs/gqlgen/_examples/scalars/model.User
7 | Timestamp:
8 | model: github.com/99designs/gqlgen/_examples/scalars/model.Timestamp
9 | SearchArgs:
10 | model: github.com/99designs/gqlgen/_examples/scalars/model.SearchArgs
11 | Point:
12 | model: github.com/99designs/gqlgen/_examples/scalars/model.Point
13 | ID:
14 | model: github.com/99designs/gqlgen/_examples/scalars/model.ID
15 | Tier:
16 | model: github.com/99designs/gqlgen/_examples/scalars/model.Tier
17 | Banned:
18 | model: github.com/99designs/gqlgen/_examples/scalars/model.Banned
19 | DarkMode:
20 | model: github.com/99designs/gqlgen/_examples/scalars/model.Preferences
21 |
--------------------------------------------------------------------------------
/.github/workflows/security.yml:
--------------------------------------------------------------------------------
1 | name: Security
2 | on: [push, pull_request]
3 | # When a new revision is pushed to a PR, cancel all in-progress CI runs for that
4 | # PR. See https://docs.github.com/en/actions/using-jobs/using-concurrency
5 | concurrency:
6 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
7 | cancel-in-progress: true
8 | jobs:
9 | nancy:
10 | strategy:
11 | matrix:
12 | go: ["1.20"] # nancy is a little flaky
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v3
16 | - uses: actions/setup-go@v3
17 | with:
18 | go-version: ${{ matrix.go }}
19 | - run: go mod download && go list -json -deps all > go.list
20 | - uses: sonatype-nexus-community/nancy-github-action@main
21 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/mutation_with_custom_scalar.go:
--------------------------------------------------------------------------------
1 | package followschema
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io"
7 | "regexp"
8 | )
9 |
10 | var re = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
11 |
12 | type Email string
13 |
14 | func (value *Email) UnmarshalGQL(v interface{}) error {
15 | input, ok := v.(string)
16 | if !ok {
17 | return fmt.Errorf("email expects a string value")
18 | }
19 | if !re.MatchString(input) {
20 | return fmt.Errorf("invalid email format")
21 | }
22 | *value = Email(input)
23 | return nil
24 | }
25 |
26 | func (value Email) MarshalGQL(w io.Writer) {
27 | output, _ := json.Marshal(string(value))
28 | w.Write(output)
29 | }
30 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/mutation_with_custom_scalar.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io"
7 | "regexp"
8 | )
9 |
10 | var re = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
11 |
12 | type Email string
13 |
14 | func (value *Email) UnmarshalGQL(v interface{}) error {
15 | input, ok := v.(string)
16 | if !ok {
17 | return fmt.Errorf("email expects a string value")
18 | }
19 | if !re.MatchString(input) {
20 | return fmt.Errorf("invalid email format")
21 | }
22 | *value = Email(input)
23 | return nil
24 | }
25 |
26 | func (value Email) MarshalGQL(w io.Writer) {
27 | output, _ := json.Marshal(string(value))
28 | w.Write(output)
29 | }
30 |
--------------------------------------------------------------------------------
/docs/static/external-link-alt.svg:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/_examples/config/todo.resolvers.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | // This file will be automatically regenerated based on the schema, any resolver implementations
4 | // will be copied through when generating and any unknown code will be moved to the end.
5 | // Code generated by github.com/99designs/gqlgen version v0.17.27-dev
6 |
7 | import (
8 | "context"
9 | "fmt"
10 | )
11 |
12 | // ID is the resolver for the id field.
13 | func (r *todoResolver) ID(ctx context.Context, obj *Todo) (string, error) {
14 | if obj.ID != "" {
15 | return obj.ID, nil
16 | }
17 |
18 | obj.ID = fmt.Sprintf("TODO:%d", obj.DatabaseID)
19 |
20 | return obj.ID, nil
21 | }
22 |
23 | // Todo returns TodoResolver implementation.
24 | func (r *Resolver) Todo() TodoResolver { return &todoResolver{r} }
25 |
26 | type todoResolver struct{ *Resolver }
27 |
--------------------------------------------------------------------------------
/graphql/handler/extension/introspection.go:
--------------------------------------------------------------------------------
1 | package extension
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/99designs/gqlgen/graphql"
7 | "github.com/vektah/gqlparser/v2/gqlerror"
8 | )
9 |
10 | // EnableIntrospection enables clients to reflect all of the types available on the graph.
11 | type Introspection struct{}
12 |
13 | var _ interface {
14 | graphql.OperationContextMutator
15 | graphql.HandlerExtension
16 | } = Introspection{}
17 |
18 | func (c Introspection) ExtensionName() string {
19 | return "Introspection"
20 | }
21 |
22 | func (c Introspection) Validate(schema graphql.ExecutableSchema) error {
23 | return nil
24 | }
25 |
26 | func (c Introspection) MutateOperationContext(ctx context.Context, rc *graphql.OperationContext) *gqlerror.Error {
27 | rc.DisableIntrospection = false
28 | return nil
29 | }
30 |
--------------------------------------------------------------------------------
/graphql/handler/lru/lru.go:
--------------------------------------------------------------------------------
1 | package lru
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/99designs/gqlgen/graphql"
7 | lru "github.com/hashicorp/golang-lru/v2"
8 | )
9 |
10 | type LRU struct {
11 | lru *lru.Cache[string, any]
12 | }
13 |
14 | var _ graphql.Cache = &LRU{}
15 |
16 | func New(size int) *LRU {
17 | cache, err := lru.New[string, any](size)
18 | if err != nil {
19 | // An error is only returned for non-positive cache size
20 | // and we already checked for that.
21 | panic("unexpected error creating cache: " + err.Error())
22 | }
23 | return &LRU{cache}
24 | }
25 |
26 | func (l LRU) Get(ctx context.Context, key string) (value interface{}, ok bool) {
27 | return l.lru.Get(key)
28 | }
29 |
30 | func (l LRU) Add(ctx context.Context, key string, value interface{}) {
31 | l.lru.Add(key, value)
32 | }
33 |
--------------------------------------------------------------------------------
/_examples/federation/products/graph/schema.resolvers.go:
--------------------------------------------------------------------------------
1 | package graph
2 |
3 | // This file will be automatically regenerated based on the schema, any resolver implementations
4 | // will be copied through when generating and any unknown code will be moved to the end.
5 | // Code generated by github.com/99designs/gqlgen version v0.17.27-dev
6 |
7 | import (
8 | "context"
9 |
10 | "github.com/99designs/gqlgen/_examples/federation/products/graph/model"
11 | )
12 |
13 | // TopProducts is the resolver for the topProducts field.
14 | func (r *queryResolver) TopProducts(ctx context.Context, first *int) ([]*model.Product, error) {
15 | return hats, nil
16 | }
17 |
18 | // Query returns QueryResolver implementation.
19 | func (r *Resolver) Query() QueryResolver { return &queryResolver{r} }
20 |
21 | type queryResolver struct{ *Resolver }
22 |
--------------------------------------------------------------------------------
/.github/workflows/check-integration:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -euo pipefail
4 |
5 | cd integration
6 |
7 | date
8 | go run ./server/server.go &
9 |
10 | sleep 5
11 | curl -s --connect-timeout 5 \
12 | --max-time 10 \
13 | --retry 5 \
14 | --retry-delay 5 \
15 | --retry-max-time 40 \
16 | --retry-connrefused \
17 | localhost:8080 > /dev/null
18 | npm install -g typescript
19 | npm link typescript
20 | echo "### running jest integration spec"
21 | ./node_modules/.bin/jest --color
22 |
23 |
24 | echo "### validating introspected schema"
25 | ./node_modules/.bin/graphql-codegen
26 |
27 | if ! diff <(tail -n +3 schema-expected.graphql) <(tail -n +3 schema-fetched.graphql) ; then
28 | echo "The expected schema has changed, you need to update schema-expected.graphql with any expected changes"
29 | exit 1
30 | fi
31 |
--------------------------------------------------------------------------------
/docs/layouts/index.html:
--------------------------------------------------------------------------------
1 | {{ define "main" }}
2 | {{ range where .Site.Pages "Type" "homepage" }}
3 |
4 | {{ .Description }}
5 |
6 |
{{ .LinkTitle }}
7 |
{{ .Title }}
8 |
9 |
10 |
11 |
12 |
13 | {{partial "version-banner"}}
14 | {{ .Content }}
15 | {{.Scratch.Set "intro" (readFile "content/_introduction.md")}}
16 | {{.Scratch.Set "intro" (split (.Scratch.Get "intro") "\n")}}
17 | {{.Scratch.Set "intro" (after 2 (.Scratch.Get "intro"))}}
18 | {{.Scratch.Set "intro" (delimit (.Scratch.Get "intro") "\n")}}
19 | {{.Scratch.Get "intro"|markdownify}}
20 |
21 |
22 | {{ end }}
23 | {{ end }}
24 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/typefallback_test.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/99designs/gqlgen/client"
8 | "github.com/99designs/gqlgen/graphql/handler"
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func TestTypeFallback(t *testing.T) {
13 | resolvers := &Stub{}
14 |
15 | c := client.New(handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: resolvers})))
16 |
17 | resolvers.QueryResolver.Fallback = func(ctx context.Context, arg FallbackToStringEncoding) (FallbackToStringEncoding, error) {
18 | return arg, nil
19 | }
20 |
21 | t.Run("fallback to string passthrough", func(t *testing.T) {
22 | var resp struct {
23 | Fallback string
24 | }
25 | c.MustPost(`query { fallback(arg: A) }`, &resp)
26 | require.Equal(t, "A", resp.Fallback)
27 | })
28 | }
29 |
--------------------------------------------------------------------------------
/graphql/handler/transport/util.go:
--------------------------------------------------------------------------------
1 | package transport
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io"
7 |
8 | "github.com/99designs/gqlgen/graphql"
9 | "github.com/vektah/gqlparser/v2/gqlerror"
10 | )
11 |
12 | func writeJson(w io.Writer, response *graphql.Response) {
13 | b, err := json.Marshal(response)
14 | if err != nil {
15 | panic(err)
16 | }
17 | w.Write(b)
18 | }
19 |
20 | func writeJsonError(w io.Writer, msg string) {
21 | writeJson(w, &graphql.Response{Errors: gqlerror.List{{Message: msg}}})
22 | }
23 |
24 | func writeJsonErrorf(w io.Writer, format string, args ...interface{}) {
25 | writeJson(w, &graphql.Response{Errors: gqlerror.List{{Message: fmt.Sprintf(format, args...)}}})
26 | }
27 |
28 | func writeJsonGraphqlError(w io.Writer, err ...*gqlerror.Error) {
29 | writeJson(w, &graphql.Response{Errors: err})
30 | }
31 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Test
2 | on: [push, pull_request]
3 | # When a new revision is pushed to a PR, cancel all in-progress CI runs for that
4 | # PR. See https://docs.github.com/en/actions/using-jobs/using-concurrency
5 | concurrency:
6 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
7 | cancel-in-progress: true
8 | jobs:
9 | test:
10 | strategy:
11 | matrix:
12 | os: [ubuntu-latest, windows-latest]
13 | go: ["1.18", "1.20"]
14 | runs-on: ${{ matrix.os }}
15 | continue-on-error: true
16 | steps:
17 | - uses: actions/checkout@v3
18 | - uses: actions/setup-go@v3
19 | with:
20 | go-version: ${{ matrix.go }}
21 | - run: go mod download && go test -race ./...
22 | - run: cd _examples && go mod download && go test -race ./...
23 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/typefallback_test.go:
--------------------------------------------------------------------------------
1 | package followschema
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/99designs/gqlgen/client"
8 | "github.com/99designs/gqlgen/graphql/handler"
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func TestTypeFallback(t *testing.T) {
13 | resolvers := &Stub{}
14 |
15 | c := client.New(handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: resolvers})))
16 |
17 | resolvers.QueryResolver.Fallback = func(ctx context.Context, arg FallbackToStringEncoding) (FallbackToStringEncoding, error) {
18 | return arg, nil
19 | }
20 |
21 | t.Run("fallback to string passthrough", func(t *testing.T) {
22 | var resp struct {
23 | Fallback string
24 | }
25 | c.MustPost(`query { fallback(arg: A) }`, &resp)
26 | require.Equal(t, "A", resp.Fallback)
27 | })
28 | }
29 |
--------------------------------------------------------------------------------
/graphql/handler/transport/error.go:
--------------------------------------------------------------------------------
1 | package transport
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "net/http"
7 |
8 | "github.com/99designs/gqlgen/graphql"
9 | "github.com/vektah/gqlparser/v2/gqlerror"
10 | )
11 |
12 | // SendError sends a best effort error to a raw response writer. It assumes the client can understand the standard
13 | // json error response
14 | func SendError(w http.ResponseWriter, code int, errors ...*gqlerror.Error) {
15 | w.WriteHeader(code)
16 | b, err := json.Marshal(&graphql.Response{Errors: errors})
17 | if err != nil {
18 | panic(err)
19 | }
20 | w.Write(b)
21 | }
22 |
23 | // SendErrorf wraps SendError to add formatted messages
24 | func SendErrorf(w http.ResponseWriter, code int, format string, args ...interface{}) {
25 | SendError(w, code, &gqlerror.Error{Message: fmt.Sprintf(format, args...)})
26 | }
27 |
--------------------------------------------------------------------------------
/graphql/response.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "fmt"
7 |
8 | "github.com/vektah/gqlparser/v2/gqlerror"
9 | )
10 |
11 | // Errors are intentionally serialized first based on the advice in
12 | // https://github.com/facebook/graphql/commit/7b40390d48680b15cb93e02d46ac5eb249689876#diff-757cea6edf0288677a9eea4cfc801d87R107
13 | // and https://github.com/facebook/graphql/pull/384
14 | type Response struct {
15 | Errors gqlerror.List `json:"errors,omitempty"`
16 | Data json.RawMessage `json:"data"`
17 | Extensions map[string]interface{} `json:"extensions,omitempty"`
18 | }
19 |
20 | func ErrorResponse(ctx context.Context, messagef string, args ...interface{}) *Response {
21 | return &Response{
22 | Errors: gqlerror.List{{Message: fmt.Sprintf(messagef, args...)}},
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/RELEASE-CHECKLIST.md:
--------------------------------------------------------------------------------
1 | # When gqlgen gets released, the following things need to happen
2 | Assuming the next version is $NEW_VERSION=v0.16.0 or something like that.
3 |
4 | 1. Run the https://github.com/99designs/gqlgen/blob/master/bin/release:
5 | ```
6 | ./bin/release $NEW_VERSION
7 | ```
8 | 2. git-chglog -o CHANGELOG.md
9 | 3. go generate ./...; cd _examples; go generate ./...; cd ..
10 | 4. git commit and push the CHANGELOG.md
11 | 5. Go to https://github.com/99designs/gqlgen/releases and draft new release, autogenerate the release notes, and Create a discussion for this release
12 | 6. Comment on the release discussion with any really important notes (breaking changes)
13 |
14 | I used https://github.com/git-chglog/git-chglog to automate the changelog maintenance process for now. We could just as easily use go releaser to make the whole thing automated.
15 |
16 |
--------------------------------------------------------------------------------
/_examples/federation/reviews/graph/reviews.go:
--------------------------------------------------------------------------------
1 | package graph
2 |
3 | import "github.com/99designs/gqlgen/_examples/federation/reviews/graph/model"
4 |
5 | var reviews = []*model.Review{
6 | {
7 | Body: "A highly effective form of birth control.",
8 | Product: &model.Product{ID: "111", Manufacturer: &model.Manufacturer{ID: "1234"}},
9 | Author: &model.User{ID: "1234"},
10 | },
11 | {
12 | Body: "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.",
13 | Product: &model.Product{ID: "222", Manufacturer: &model.Manufacturer{ID: "2345"}},
14 | Author: &model.User{ID: "1234"},
15 | },
16 | {
17 | Body: "This is the last straw. Hat you will wear. 11/10",
18 | Product: &model.Product{ID: "333", Manufacturer: &model.Manufacturer{ID: "2345"}},
19 | Author: &model.User{ID: "7777"},
20 | },
21 | }
22 |
--------------------------------------------------------------------------------
/graphql/error.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import (
4 | "context"
5 | "errors"
6 |
7 | "github.com/vektah/gqlparser/v2/gqlerror"
8 | )
9 |
10 | type ErrorPresenterFunc func(ctx context.Context, err error) *gqlerror.Error
11 |
12 | func DefaultErrorPresenter(ctx context.Context, err error) *gqlerror.Error {
13 | var gqlErr *gqlerror.Error
14 | if errors.As(err, &gqlErr) {
15 | return gqlErr
16 | }
17 | return gqlerror.WrapPath(GetPath(ctx), err)
18 | }
19 |
20 | func ErrorOnPath(ctx context.Context, err error) error {
21 | if err == nil {
22 | return nil
23 | }
24 | var gqlErr *gqlerror.Error
25 | if errors.As(err, &gqlErr) {
26 | if gqlErr.Path == nil {
27 | gqlErr.Path = GetPath(ctx)
28 | }
29 | // Return the original error to avoid losing any attached annotation
30 | return err
31 | }
32 | return gqlerror.WrapPath(GetPath(ctx), err)
33 | }
34 |
--------------------------------------------------------------------------------
/plugin/modelgen/testdata/gqlgen.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - "testdata/schema.graphql"
3 |
4 | exec:
5 | filename: out/ignored.go
6 | model:
7 | filename: out/generated.go
8 |
9 | models:
10 | ExistingModel:
11 | model: github.com/99designs/gqlgen/plugin/modelgen/out.ExistingModel
12 | ExistingInput:
13 | model: github.com/99designs/gqlgen/plugin/modelgen/out.ExistingInput
14 | ExistingEnum:
15 | model: github.com/99designs/gqlgen/plugin/modelgen/out.ExistingEnum
16 | ExistingInterface:
17 | model: github.com/99designs/gqlgen/plugin/modelgen/out.ExistingInterface
18 | ExistingUnion:
19 | model: github.com/99designs/gqlgen/plugin/modelgen/out.ExistingUnion
20 | ExistingType:
21 | model: github.com/99designs/gqlgen/plugin/modelgen/out.ExistingType
22 | RenameFieldTest:
23 | fields:
24 | badName:
25 | fieldName: GOODnaME
26 |
27 |
--------------------------------------------------------------------------------
/_examples/embedding/subdir/federation_gen.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
2 |
3 | package subdir
4 |
5 | import (
6 | "context"
7 | "errors"
8 | "strings"
9 |
10 | "github.com/99designs/gqlgen/plugin/federation/fedruntime"
11 | )
12 |
13 | var (
14 | ErrUnknownType = errors.New("unknown type")
15 | ErrTypeNotFound = errors.New("type not found")
16 | )
17 |
18 | func (ec *executionContext) __resolve__service(ctx context.Context) (fedruntime.Service, error) {
19 | if ec.DisableIntrospection {
20 | return fedruntime.Service{}, errors.New("federated introspection disabled")
21 | }
22 |
23 | var sdl []string
24 |
25 | for _, src := range sources {
26 | if src.BuiltIn {
27 | continue
28 | }
29 | sdl = append(sdl, src.Input)
30 | }
31 |
32 | return fedruntime.Service{
33 | SDL: strings.Join(sdl, "\n"),
34 | }, nil
35 | }
36 |
--------------------------------------------------------------------------------
/api/testdata/federation2/graph/federation.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
2 |
3 | package graph
4 |
5 | import (
6 | "context"
7 | "errors"
8 | "strings"
9 |
10 | "github.com/99designs/gqlgen/plugin/federation/fedruntime"
11 | )
12 |
13 | var (
14 | ErrUnknownType = errors.New("unknown type")
15 | ErrTypeNotFound = errors.New("type not found")
16 | )
17 |
18 | func (ec *executionContext) __resolve__service(ctx context.Context) (fedruntime.Service, error) {
19 | if ec.DisableIntrospection {
20 | return fedruntime.Service{}, errors.New("federated introspection disabled")
21 | }
22 |
23 | var sdl []string
24 |
25 | for _, src := range sources {
26 | if src.BuiltIn {
27 | continue
28 | }
29 | sdl = append(sdl, src.Input)
30 | }
31 |
32 | return fedruntime.Service{
33 | SDL: strings.Join(sdl, "\n"),
34 | }, nil
35 | }
36 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/gqlgen.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - "*.graphql"
3 | skip_validation: true
4 | exec:
5 | filename: generated.go
6 | package: singlefile
7 | model:
8 | filename: models-gen.go
9 | package: singlefile
10 | resolver:
11 | filename: resolver.go
12 | package: singlefile
13 | type: Resolver
14 |
15 | autobind:
16 | - "github.com/99designs/gqlgen/codegen/testserver"
17 | - "github.com/99designs/gqlgen/codegen/testserver/singlefile"
18 | - "github.com/99designs/gqlgen/codegen/testserver/singlefile/introspection"
19 | - "github.com/99designs/gqlgen/codegen/testserver/singlefile/invalid-packagename"
20 |
21 | models:
22 | Email:
23 | model: "github.com/99designs/gqlgen/codegen/testserver/singlefile.Email"
24 | StringFromContextFunction:
25 | model: "github.com/99designs/gqlgen/codegen/testserver/singlefile.StringFromContextFunction"
26 |
--------------------------------------------------------------------------------
/_examples/embedding/subdir/gendir/federation_gen.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
2 |
3 | package gendir
4 |
5 | import (
6 | "context"
7 | "errors"
8 | "strings"
9 |
10 | "github.com/99designs/gqlgen/plugin/federation/fedruntime"
11 | )
12 |
13 | var (
14 | ErrUnknownType = errors.New("unknown type")
15 | ErrTypeNotFound = errors.New("type not found")
16 | )
17 |
18 | func (ec *executionContext) __resolve__service(ctx context.Context) (fedruntime.Service, error) {
19 | if ec.DisableIntrospection {
20 | return fedruntime.Service{}, errors.New("federated introspection disabled")
21 | }
22 |
23 | var sdl []string
24 |
25 | for _, src := range sources {
26 | if src.BuiltIn {
27 | continue
28 | }
29 | sdl = append(sdl, src.Input)
30 | }
31 |
32 | return fedruntime.Service{
33 | SDL: strings.Join(sdl, "\n"),
34 | }, nil
35 | }
36 |
--------------------------------------------------------------------------------
/plugin/servergen/server.gotpl:
--------------------------------------------------------------------------------
1 | {{ reserveImport "context" }}
2 | {{ reserveImport "log" }}
3 | {{ reserveImport "net/http" }}
4 | {{ reserveImport "os" }}
5 | {{ reserveImport "github.com/99designs/gqlgen/graphql/playground" }}
6 | {{ reserveImport "github.com/99designs/gqlgen/graphql/handler" }}
7 |
8 | const defaultPort = "8080"
9 |
10 | func main() {
11 | port := os.Getenv("PORT")
12 | if port == "" {
13 | port = defaultPort
14 | }
15 |
16 | srv := handler.NewDefaultServer({{ lookupImport .ExecPackageName }}.NewExecutableSchema({{ lookupImport .ExecPackageName}}.Config{Resolvers: &{{ lookupImport .ResolverPackageName}}.Resolver{}}))
17 |
18 | http.Handle("/", playground.Handler("GraphQL playground", "/query"))
19 | http.Handle("/query", srv)
20 |
21 | log.Printf("connect to http://localhost:%s/ for GraphQL playground", port)
22 | log.Fatal(http.ListenAndServe(":" + port, nil))
23 | }
24 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/gqlgen.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - "*.graphql"
3 | skip_validation: true
4 | exec:
5 | layout: follow-schema
6 | dir: .
7 | package: followschema
8 | model:
9 | filename: models-gen.go
10 | package: followschema
11 | resolver:
12 | filename: resolver.go
13 | package: followschema
14 | type: Resolver
15 |
16 | autobind:
17 | - "github.com/99designs/gqlgen/codegen/testserver"
18 | - "github.com/99designs/gqlgen/codegen/testserver/followschema"
19 | - "github.com/99designs/gqlgen/codegen/testserver/followschema/introspection"
20 | - "github.com/99designs/gqlgen/codegen/testserver/followschema/invalid-packagename"
21 |
22 | models:
23 | Email:
24 | model: "github.com/99designs/gqlgen/codegen/testserver/followschema.Email"
25 | StringFromContextFunction:
26 | model: "github.com/99designs/gqlgen/codegen/testserver/followschema.StringFromContextFunction"
27 |
--------------------------------------------------------------------------------
/plugin/federation/test_data/model/federation.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | type _FieldSet string //nolint:deadcode,unused
4 |
5 | type Hello struct {
6 | Name string
7 | Secondary string
8 | }
9 |
10 | func (Hello) IsEntity() {}
11 |
12 | type World struct {
13 | Foo string
14 | Bar int
15 | }
16 |
17 | func (World) IsEntity() {}
18 |
19 | type ExternalExtension struct {
20 | UPC string
21 | Reviews []*World
22 | }
23 |
24 | func (ExternalExtension) IsEntity() {}
25 |
26 | type NestedKey struct {
27 | ID string
28 | Hello *Hello
29 | }
30 |
31 | func (NestedKey) IsEntity() {}
32 |
33 | type MoreNesting struct {
34 | ID string
35 | World *World
36 | }
37 |
38 | func (MoreNesting) IsEntity() {}
39 |
40 | type VeryNestedKey struct {
41 | ID string
42 | Hello *Hello
43 | World *World
44 | Nested *NestedKey
45 | More *MoreNesting
46 | }
47 |
48 | func (VeryNestedKey) IsEntity() {}
49 |
--------------------------------------------------------------------------------
/_examples/embedding/subdir/resolvers.go:
--------------------------------------------------------------------------------
1 | //go:generate go run ../../../testdata/gqlgen.go -config cfgdir/generate_in_subdir.yml
2 | //go:generate go run ../../../testdata/gqlgen.go -config cfgdir/generate_in_gendir.yml
3 |
4 | package subdir
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/99designs/gqlgen/_examples/embedding/subdir/gendir"
10 | )
11 |
12 | type Resolver struct{ *Resolver }
13 |
14 | func (q *Resolver) Query() QueryResolver {
15 | return q
16 | }
17 | func (q *Resolver) InSchemadir(ctx context.Context) (string, error) {
18 | return "example", nil
19 | }
20 | func (q *Resolver) Parentdir(ctx context.Context) (string, error) {
21 | return "example", nil
22 | }
23 | func (q *Resolver) Subdir(ctx context.Context) (string, error) {
24 | return "example", nil
25 | }
26 |
27 | type GendirResolver struct{ *Resolver }
28 |
29 | func (q *GendirResolver) Query() gendir.QueryResolver {
30 | return &Resolver{}
31 | }
32 |
--------------------------------------------------------------------------------
/plugin/federation/testdata/allthethings/model/federation.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | type _FieldSet string //nolint:deadcode,unused
4 |
5 | type Hello struct {
6 | Name string
7 | Secondary string
8 | }
9 |
10 | func (Hello) IsEntity() {}
11 |
12 | type World struct {
13 | Foo string
14 | Bar int
15 | }
16 |
17 | func (World) IsEntity() {}
18 |
19 | type ExternalExtension struct {
20 | UPC string
21 | Reviews []*World
22 | }
23 |
24 | func (ExternalExtension) IsEntity() {}
25 |
26 | type NestedKey struct {
27 | ID string
28 | Hello *Hello
29 | }
30 |
31 | func (NestedKey) IsEntity() {}
32 |
33 | type MoreNesting struct {
34 | ID string
35 | World *World
36 | }
37 |
38 | func (MoreNesting) IsEntity() {}
39 |
40 | type VeryNestedKey struct {
41 | ID string
42 | Hello *Hello
43 | World *World
44 | Nested *NestedKey
45 | More *MoreNesting
46 | }
47 |
48 | func (VeryNestedKey) IsEntity() {}
49 |
--------------------------------------------------------------------------------
/_examples/chat/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import styled from 'styled-components';
3 | import { Room } from './Room';
4 |
5 | const Input = styled.div`
6 | padding: 4px;
7 | margin: 0 0 4px;
8 |
9 | input {
10 | border: 1px solid #ccc;
11 | padding: 2px;
12 | font-size: 14px;
13 | }
14 | `;
15 |
16 | export const App = () => {
17 | const [name, setName] = useState('tester');
18 | const [channel, setChannel] = useState('#gophers');
19 |
20 | return (
21 | <>
22 |
23 | name: setName(e.target.value)} />
24 |
25 |
26 | channel: setChannel(e.target.value)} />
27 |
28 |
29 |
30 | >
31 | );
32 |
33 | };
34 |
--------------------------------------------------------------------------------
/_examples/fileupload/schema.graphql:
--------------------------------------------------------------------------------
1 | "The `Upload` scalar type represents a multipart file upload."
2 | scalar Upload
3 |
4 | "The `File` type, represents the response of uploading a file."
5 | type File {
6 | id: Int!
7 | name: String!
8 | content: String!
9 | contentType: String!
10 | }
11 |
12 | "The `UploadFile` type, represents the request for uploading a file with certain payload."
13 | input UploadFile {
14 | id: Int!
15 | file: Upload!
16 | }
17 |
18 | "The `Query` type, represents all of the entry points into our object graph."
19 | type Query {
20 | empty: String!
21 | }
22 |
23 | "The `Mutation` type, represents all updates we can make to our data."
24 | type Mutation {
25 | singleUpload(file: Upload!): File!
26 | singleUploadWithPayload(req: UploadFile!): File!
27 | multipleUpload(files: [Upload!]!): [File!]!
28 | multipleUploadWithPayload(req: [UploadFile!]!): [File!]!
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/_examples/todo/schema.graphql:
--------------------------------------------------------------------------------
1 | schema {
2 | query: MyQuery
3 | mutation: MyMutation
4 | }
5 |
6 | type MyQuery {
7 | todo(id: ID!): Todo
8 | lastTodo: Todo
9 | todos: [Todo!]!
10 | }
11 |
12 | type MyMutation {
13 | createTodo(todo: TodoInput!): Todo!
14 | updateTodo(id: ID!, changes: Map!): Todo
15 | }
16 |
17 | type Todo {
18 | id: ID!
19 | text: String!
20 | done: Boolean! @hasRole(role: OWNER) # only the owner can see if a todo is done
21 | }
22 |
23 | "Passed to createTodo to create a new todo"
24 | input TodoInput {
25 | "The body text"
26 | text: String!
27 | "Is it done already?"
28 | done: Boolean
29 | }
30 |
31 | scalar Map
32 |
33 | "Prevents access to a field if the user doesnt have the matching role"
34 | directive @hasRole(role: Role!) on FIELD_DEFINITION
35 | directive @user(id: ID!) on MUTATION | QUERY | FIELD
36 |
37 | enum Role {
38 | ADMIN
39 | OWNER
40 | }
41 |
--------------------------------------------------------------------------------
/_examples/federation/reviews/server.go:
--------------------------------------------------------------------------------
1 | //go:generate go run ../../../testdata/gqlgen.go
2 | package main
3 |
4 | import (
5 | "log"
6 | "net/http"
7 | "os"
8 |
9 | "github.com/99designs/gqlgen/_examples/federation/reviews/graph"
10 | "github.com/99designs/gqlgen/graphql/handler"
11 | "github.com/99designs/gqlgen/graphql/handler/debug"
12 | "github.com/99designs/gqlgen/graphql/playground"
13 | )
14 |
15 | const defaultPort = "4003"
16 |
17 | func main() {
18 | port := os.Getenv("PORT")
19 | if port == "" {
20 | port = defaultPort
21 | }
22 |
23 | srv := handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}}))
24 | srv.Use(&debug.Tracer{})
25 |
26 | http.Handle("/", playground.Handler("GraphQL playground", "/query"))
27 | http.Handle("/query", srv)
28 |
29 | log.Printf("connect to http://localhost:%s/ for GraphQL playground", port)
30 | log.Fatal(http.ListenAndServe(":"+port, nil))
31 | }
32 |
--------------------------------------------------------------------------------
/_examples/federation/accounts/server.go:
--------------------------------------------------------------------------------
1 | //go:generate go run ../../../testdata/gqlgen.go
2 | package main
3 |
4 | import (
5 | "log"
6 | "net/http"
7 | "os"
8 |
9 | "github.com/99designs/gqlgen/_examples/federation/accounts/graph"
10 | "github.com/99designs/gqlgen/graphql/handler"
11 | "github.com/99designs/gqlgen/graphql/handler/debug"
12 | "github.com/99designs/gqlgen/graphql/playground"
13 | )
14 |
15 | const defaultPort = "4001"
16 |
17 | func main() {
18 | port := os.Getenv("PORT")
19 | if port == "" {
20 | port = defaultPort
21 | }
22 |
23 | srv := handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}}))
24 | srv.Use(&debug.Tracer{})
25 |
26 | http.Handle("/", playground.Handler("GraphQL playground", "/query"))
27 | http.Handle("/query", srv)
28 |
29 | log.Printf("connect to http://localhost:%s/ for GraphQL playground", port)
30 | log.Fatal(http.ListenAndServe(":"+port, nil))
31 | }
32 |
--------------------------------------------------------------------------------
/_examples/federation/products/server.go:
--------------------------------------------------------------------------------
1 | //go:generate go run ../../../testdata/gqlgen.go
2 | package main
3 |
4 | import (
5 | "log"
6 | "net/http"
7 | "os"
8 |
9 | "github.com/99designs/gqlgen/_examples/federation/products/graph"
10 | "github.com/99designs/gqlgen/graphql/handler"
11 | "github.com/99designs/gqlgen/graphql/handler/debug"
12 | "github.com/99designs/gqlgen/graphql/playground"
13 | )
14 |
15 | const defaultPort = "4002"
16 |
17 | func main() {
18 | port := os.Getenv("PORT")
19 | if port == "" {
20 | port = defaultPort
21 | }
22 |
23 | srv := handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}}))
24 | srv.Use(&debug.Tracer{})
25 |
26 | http.Handle("/", playground.Handler("GraphQL playground", "/query"))
27 | http.Handle("/query", srv)
28 |
29 | log.Printf("connect to http://localhost:%s/ for GraphQL playground", port)
30 | log.Fatal(http.ListenAndServe(":"+port, nil))
31 | }
32 |
--------------------------------------------------------------------------------
/_examples/scalars/schema.graphql:
--------------------------------------------------------------------------------
1 | type Query {
2 | user(id: ID!): User
3 | search(input: SearchArgs = {location: "37,144", isBanned: false}): [User!]!
4 | userByTier(tier: Tier!, darkMode: DarkMode!): [User!]!
5 | }
6 |
7 | type User {
8 | id: ID!
9 | name: String!
10 | created: Timestamp
11 | modified: Timestamp
12 | valPrefs: DarkMode
13 | ptrPrefs: DarkMode
14 | isBanned: Banned!
15 | primitiveResolver: String!
16 | customResolver: Point!
17 | address: Address
18 | tier: Tier
19 | }
20 |
21 | type Address {
22 | id: ID!
23 | location: Point
24 | }
25 |
26 | input SearchArgs {
27 | location: Point
28 | createdAfter: Timestamp
29 | isBanned: Banned # TODO: This can be a Boolean again once multiple backing types are allowed
30 | }
31 |
32 | enum Tier {
33 | A
34 | B
35 | C
36 | }
37 |
38 | scalar Timestamp
39 | scalar Point
40 | scalar Banned
41 | scalar DarkMode
42 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/response_extension_test.go:
--------------------------------------------------------------------------------
1 | package followschema
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/99designs/gqlgen/client"
8 | "github.com/99designs/gqlgen/graphql"
9 | "github.com/99designs/gqlgen/graphql/handler"
10 | "github.com/stretchr/testify/require"
11 | )
12 |
13 | func TestResponseExtension(t *testing.T) {
14 | resolvers := &Stub{}
15 | resolvers.QueryResolver.Valid = func(ctx context.Context) (s string, e error) {
16 | return "Ok", nil
17 | }
18 |
19 | srv := handler.NewDefaultServer(
20 | NewExecutableSchema(Config{Resolvers: resolvers}),
21 | )
22 |
23 | srv.AroundResponses(func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
24 | graphql.RegisterExtension(ctx, "example", "value")
25 |
26 | return next(ctx)
27 | })
28 |
29 | c := client.New(srv)
30 |
31 | raw, _ := c.RawPost(`query { valid }`)
32 | require.Equal(t, raw.Extensions["example"], "value")
33 | }
34 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/response_extension_test.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/99designs/gqlgen/client"
8 | "github.com/99designs/gqlgen/graphql"
9 | "github.com/99designs/gqlgen/graphql/handler"
10 | "github.com/stretchr/testify/require"
11 | )
12 |
13 | func TestResponseExtension(t *testing.T) {
14 | resolvers := &Stub{}
15 | resolvers.QueryResolver.Valid = func(ctx context.Context) (s string, e error) {
16 | return "Ok", nil
17 | }
18 |
19 | srv := handler.NewDefaultServer(
20 | NewExecutableSchema(Config{Resolvers: resolvers}),
21 | )
22 |
23 | srv.AroundResponses(func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
24 | graphql.RegisterExtension(ctx, "example", "value")
25 |
26 | return next(ctx)
27 | })
28 |
29 | c := client.New(srv)
30 |
31 | raw, _ := c.RawPost(`query { valid }`)
32 | require.Equal(t, raw.Extensions["example"], "value")
33 | }
34 |
--------------------------------------------------------------------------------
/_examples/federation/accounts/graph/schema.resolvers.go:
--------------------------------------------------------------------------------
1 | package graph
2 |
3 | // This file will be automatically regenerated based on the schema, any resolver implementations
4 | // will be copied through when generating and any unknown code will be moved to the end.
5 | // Code generated by github.com/99designs/gqlgen version v0.17.27-dev
6 |
7 | import (
8 | "context"
9 |
10 | "github.com/99designs/gqlgen/_examples/federation/accounts/graph/model"
11 | )
12 |
13 | // Me is the resolver for the me field.
14 | func (r *queryResolver) Me(ctx context.Context) (*model.User, error) {
15 | return &model.User{
16 | ID: "1234",
17 | Host: &model.EmailHost{
18 | ID: "4567",
19 | Name: "Email Host 4567",
20 | },
21 | Email: "me@example.com",
22 | Username: "Me",
23 | }, nil
24 | }
25 |
26 | // Query returns QueryResolver implementation.
27 | func (r *Resolver) Query() QueryResolver { return &queryResolver{r} }
28 |
29 | type queryResolver struct{ *Resolver }
30 |
--------------------------------------------------------------------------------
/codegen/type.go:
--------------------------------------------------------------------------------
1 | package codegen
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/99designs/gqlgen/codegen/config"
7 | )
8 |
9 | func (b *builder) buildTypes() map[string]*config.TypeReference {
10 | ret := map[string]*config.TypeReference{}
11 | for _, ref := range b.Binder.References {
12 | processType(ret, ref)
13 | }
14 | return ret
15 | }
16 |
17 | func processType(ret map[string]*config.TypeReference, ref *config.TypeReference) {
18 | key := ref.UniquenessKey()
19 | if existing, found := ret[key]; found {
20 | // Simplistic check of content which is obviously different.
21 | existingGQL := fmt.Sprintf("%v", existing.GQL)
22 | newGQL := fmt.Sprintf("%v", ref.GQL)
23 | if existingGQL != newGQL {
24 | panic(fmt.Sprintf("non-unique key \"%s\", trying to replace %s with %s", key, existingGQL, newGQL))
25 | }
26 | }
27 | ret[key] = ref
28 |
29 | if ref.IsSlice() || ref.IsPtrToSlice() || ref.IsPtrToPtr() {
30 | processType(ret, ref.Elem())
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/_examples/starwars/server/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "log"
7 | "net/http"
8 |
9 | "github.com/99designs/gqlgen/_examples/starwars"
10 | "github.com/99designs/gqlgen/_examples/starwars/generated"
11 | "github.com/99designs/gqlgen/graphql"
12 | "github.com/99designs/gqlgen/graphql/handler"
13 | "github.com/99designs/gqlgen/graphql/playground"
14 | )
15 |
16 | func main() {
17 | srv := handler.NewDefaultServer(generated.NewExecutableSchema(starwars.NewResolver()))
18 | srv.AroundFields(func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
19 | rc := graphql.GetFieldContext(ctx)
20 | fmt.Println("Entered", rc.Object, rc.Field.Name)
21 | res, err = next(ctx)
22 | fmt.Println("Left", rc.Object, rc.Field.Name, "=>", res, err)
23 | return res, err
24 | })
25 |
26 | http.Handle("/", playground.Handler("Starwars", "/query"))
27 | http.Handle("/query", srv)
28 |
29 | log.Fatal(http.ListenAndServe(":8080", nil))
30 | }
31 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/variadic_test.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 |
9 | "github.com/99designs/gqlgen/client"
10 | "github.com/99designs/gqlgen/graphql/handler"
11 | )
12 |
13 | func TestVariadic(t *testing.T) {
14 | resolver := &Stub{}
15 | resolver.QueryResolver.VariadicModel = func(ctx context.Context) (*VariadicModel, error) {
16 | return &VariadicModel{}, nil
17 | }
18 | c := client.New(handler.NewDefaultServer(
19 | NewExecutableSchema(Config{Resolvers: resolver}),
20 | ))
21 |
22 | var resp struct {
23 | VariadicModel struct {
24 | Value string
25 | }
26 | }
27 | err := c.Post(`query { variadicModel { value(rank: 1) } }`, &resp)
28 | require.NoError(t, err)
29 | require.Equal(t, resp.VariadicModel.Value, "1")
30 |
31 | err = c.Post(`query { variadicModel { value(rank: 2) } }`, &resp)
32 | require.NoError(t, err)
33 | require.Equal(t, resp.VariadicModel.Value, "2")
34 | }
35 |
--------------------------------------------------------------------------------
/plugin/modelgen/testdata/gqlgen_struct_field_pointers.yml:
--------------------------------------------------------------------------------
1 | schema:
2 | - "testdata/schema.graphql"
3 |
4 | exec:
5 | filename: out_struct_pointers/ignored.go
6 | model:
7 | filename: out_struct_pointers/generated.go
8 |
9 | struct_fields_always_pointers: false
10 | omit_getters: true
11 |
12 | models:
13 | ExistingModel:
14 | model: github.com/99designs/gqlgen/plugin/modelgen/out_struct_pointers.ExistingModel
15 | ExistingInput:
16 | model: github.com/99designs/gqlgen/plugin/modelgen/out_struct_pointers.ExistingInput
17 | ExistingEnum:
18 | model: github.com/99designs/gqlgen/plugin/modelgen/out_struct_pointers.ExistingEnum
19 | ExistingInterface:
20 | model: github.com/99designs/gqlgen/plugin/modelgen/out_struct_pointers.ExistingInterface
21 | ExistingUnion:
22 | model: github.com/99designs/gqlgen/plugin/modelgen/out_struct_pointers.ExistingUnion
23 | ExistingType:
24 | model: github.com/99designs/gqlgen/plugin/modelgen/out_struct_pointers.ExistingType
25 |
26 |
--------------------------------------------------------------------------------
/plugin/resolvergen/testdata/singlefile/out/resolver.go:
--------------------------------------------------------------------------------
1 | package customresolver
2 |
3 | // THIS CODE IS A STARTING POINT ONLY. IT WILL NOT BE UPDATED WITH SCHEMA CHANGES.
4 |
5 | import (
6 | "context"
7 | )
8 |
9 | type CustomResolverType struct{}
10 |
11 | // // foo
12 | func (r *queryCustomResolverType) Resolver(ctx context.Context) (*Resolver, error) {
13 | panic("not implemented")
14 | }
15 |
16 | // // foo
17 | func (r *resolverCustomResolverType) Name(ctx context.Context, obj *Resolver) (string, error) {
18 | panic("not implemented")
19 | }
20 |
21 | // Query returns QueryResolver implementation.
22 | func (r *CustomResolverType) Query() QueryResolver { return &queryCustomResolverType{r} }
23 |
24 | // Resolver returns ResolverResolver implementation.
25 | func (r *CustomResolverType) Resolver() ResolverResolver { return &resolverCustomResolverType{r} }
26 |
27 | type queryCustomResolverType struct{ *CustomResolverType }
28 | type resolverCustomResolverType struct{ *CustomResolverType }
29 |
--------------------------------------------------------------------------------
/_examples/chat/src/graphql-sse.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ApolloLink,
3 | Operation,
4 | FetchResult,
5 | Observable,
6 | } from '@apollo/client/core';
7 | import { print } from 'graphql';
8 | import { createClient, ClientOptions, Client } from 'graphql-sse';
9 |
10 | export class SSELink extends ApolloLink {
11 | private client: Client;
12 |
13 | constructor(options: ClientOptions) {
14 | super();
15 | this.client = createClient(options);
16 | }
17 |
18 | public request(operation: Operation): Observable {
19 | return new Observable((sink) => {
20 | return this.client.subscribe(
21 | { ...operation, query: print(operation.query) },
22 | {
23 | next: sink.next.bind(sink),
24 | complete: sink.complete.bind(sink),
25 | error: sink.error.bind(sink),
26 | },
27 | );
28 | });
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/_examples/federation/reviews/graph/schema.resolvers.go:
--------------------------------------------------------------------------------
1 | package graph
2 |
3 | // This file will be automatically regenerated based on the schema, any resolver implementations
4 | // will be copied through when generating and any unknown code will be moved to the end.
5 | // Code generated by github.com/99designs/gqlgen version v0.17.27-dev
6 |
7 | import (
8 | "context"
9 |
10 | "github.com/99designs/gqlgen/_examples/federation/reviews/graph/model"
11 | )
12 |
13 | // Reviews is the resolver for the reviews field.
14 | func (r *userResolver) Reviews(ctx context.Context, obj *model.User) ([]*model.Review, error) {
15 | var productReviews []*model.Review
16 | for _, review := range reviews {
17 | if review.Author.ID == obj.ID {
18 | productReviews = append(productReviews, review)
19 | }
20 | }
21 | return productReviews, nil
22 | }
23 |
24 | // User returns UserResolver implementation.
25 | func (r *Resolver) User() UserResolver { return &userResolver{r} }
26 |
27 | type userResolver struct{ *Resolver }
28 |
--------------------------------------------------------------------------------
/internal/rewrite/rewriter_test.go:
--------------------------------------------------------------------------------
1 | package rewrite
2 |
3 | import (
4 | "strings"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/assert"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func TestRewriter(t *testing.T) {
12 | t.Run("default", func(t *testing.T) {
13 | r, err := New("testdata")
14 | require.NoError(t, err)
15 |
16 | body := r.GetMethodBody("Foo", "Method")
17 | require.Equal(t, `
18 | // leading comment
19 |
20 | // field comment
21 | m.Field++
22 |
23 | // trailing comment
24 | `, strings.ReplaceAll(body, "\r\n", "\n"))
25 |
26 | imps := r.ExistingImports("testdata/example.go")
27 | require.Len(t, imps, 2)
28 | assert.Equal(t, []Import{
29 | {
30 | Alias: "",
31 | ImportPath: "fmt",
32 | },
33 | {
34 | Alias: "lol",
35 | ImportPath: "bytes",
36 | },
37 | }, imps)
38 | })
39 |
40 | t.Run("out of scope dir", func(t *testing.T) {
41 | _, err := New("../../../out-of-gomod/package")
42 | require.Error(t, err)
43 | })
44 | }
45 |
--------------------------------------------------------------------------------
/graphql/handler/transport/options.go:
--------------------------------------------------------------------------------
1 | package transport
2 |
3 | import (
4 | "net/http"
5 | "strings"
6 |
7 | "github.com/99designs/gqlgen/graphql"
8 | )
9 |
10 | // Options responds to http OPTIONS and HEAD requests
11 | type Options struct {
12 | // AllowedMethods is a list of allowed HTTP methods.
13 | AllowedMethods []string
14 | }
15 |
16 | var _ graphql.Transport = Options{}
17 |
18 | func (o Options) Supports(r *http.Request) bool {
19 | return r.Method == "HEAD" || r.Method == "OPTIONS"
20 | }
21 |
22 | func (o Options) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
23 | switch r.Method {
24 | case http.MethodOptions:
25 | w.Header().Set("Allow", o.allowedMethods())
26 | w.WriteHeader(http.StatusOK)
27 | case http.MethodHead:
28 | w.WriteHeader(http.StatusMethodNotAllowed)
29 | }
30 | }
31 |
32 | func (o Options) allowedMethods() string {
33 | if len(o.AllowedMethods) == 0 {
34 | return "OPTIONS, GET, POST"
35 | }
36 | return strings.Join(o.AllowedMethods, ", ")
37 | }
38 |
--------------------------------------------------------------------------------
/graphql/handler/transport/reader.go:
--------------------------------------------------------------------------------
1 | package transport
2 |
3 | import (
4 | "errors"
5 | "io"
6 | )
7 |
8 | type bytesReader struct {
9 | s *[]byte
10 | i int64 // current reading index
11 | }
12 |
13 | func (r *bytesReader) Read(b []byte) (n int, err error) {
14 | if r.s == nil {
15 | return 0, errors.New("byte slice pointer is nil")
16 | }
17 | if r.i >= int64(len(*r.s)) {
18 | return 0, io.EOF
19 | }
20 | n = copy(b, (*r.s)[r.i:])
21 | r.i += int64(n)
22 | return
23 | }
24 |
25 | func (r *bytesReader) Seek(offset int64, whence int) (int64, error) {
26 | if r.s == nil {
27 | return 0, errors.New("byte slice pointer is nil")
28 | }
29 | var abs int64
30 | switch whence {
31 | case io.SeekStart:
32 | abs = offset
33 | case io.SeekCurrent:
34 | abs = r.i + offset
35 | case io.SeekEnd:
36 | abs = int64(len(*r.s)) + offset
37 | default:
38 | return 0, errors.New("invalid whence")
39 | }
40 | if abs < 0 {
41 | return 0, errors.New("negative position")
42 | }
43 | r.i = abs
44 | return abs, nil
45 | }
46 |
--------------------------------------------------------------------------------
/plugin/federation/testdata/allthethings/schema.graphql:
--------------------------------------------------------------------------------
1 | type Hello @key(fields: "name") {
2 | name: String!
3 | secondary: String!
4 | }
5 |
6 | type World @key(fields: " foo ") @key(fields: "bar") {
7 | foo: String!
8 | bar: Int!
9 | }
10 |
11 | extend type ExternalExtension @key(fields: " upc ") {
12 | upc: String! @external
13 | reviews: [World]
14 | }
15 |
16 | extend type NestedKey @key(fields: "id hello { name}") {
17 | id: String! @external
18 | hello: Hello
19 | }
20 |
21 | extend type MoreNesting @key(fields: "id") {
22 | id: String! @external
23 | world: World! @external
24 | }
25 |
26 | extend type VeryNestedKey
27 | @key(
28 | fields: "id hello { name} world {foo } world{bar} more { world { foo }}"
29 | ) {
30 | id: String! @external
31 | hello: Hello
32 | world: World
33 | nested: NestedKey @requires(fields: "id hello {secondary }")
34 | more: MoreNesting
35 | }
36 |
37 | type Query {
38 | hello: Hello!
39 | world: World!
40 | }
41 |
--------------------------------------------------------------------------------
/_examples/starwars/benchmarks_test.go:
--------------------------------------------------------------------------------
1 | package starwars
2 |
3 | import (
4 | "net/http/httptest"
5 | "strings"
6 | "testing"
7 |
8 | "github.com/99designs/gqlgen/_examples/starwars/generated"
9 | "github.com/99designs/gqlgen/graphql/handler"
10 | )
11 |
12 | func BenchmarkSimpleQueryNoArgs(b *testing.B) {
13 | server := handler.NewDefaultServer(generated.NewExecutableSchema(NewResolver()))
14 |
15 | q := `{"query":"{ search(text:\"Luke\") { ... on Human { starships { name } } } }"}`
16 |
17 | var body strings.Reader
18 | r := httptest.NewRequest("POST", "/graphql", &body)
19 | r.Header.Set("Content-Type", "application/json")
20 |
21 | b.ReportAllocs()
22 | b.ResetTimer()
23 |
24 | rec := httptest.NewRecorder()
25 | for i := 0; i < b.N; i++ {
26 | body.Reset(q)
27 | rec.Body.Reset()
28 | server.ServeHTTP(rec, r)
29 | if rec.Body.String() != `{"data":{"search":[{"starships":[{"name":"X-Wing"},{"name":"Imperial shuttle"}]}]}}` {
30 | b.Fatalf("Unexpected response: %s", rec.Body.String())
31 | }
32 |
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/plugin/plugin.go:
--------------------------------------------------------------------------------
1 | // plugin package interfaces are EXPERIMENTAL.
2 |
3 | package plugin
4 |
5 | import (
6 | "github.com/99designs/gqlgen/codegen"
7 | "github.com/99designs/gqlgen/codegen/config"
8 | "github.com/vektah/gqlparser/v2/ast"
9 | )
10 |
11 | type Plugin interface {
12 | Name() string
13 | }
14 |
15 | type ConfigMutator interface {
16 | MutateConfig(cfg *config.Config) error
17 | }
18 |
19 | type CodeGenerator interface {
20 | GenerateCode(cfg *codegen.Data) error
21 | }
22 |
23 | // EarlySourceInjector is used to inject things that are required for user schema files to compile.
24 | type EarlySourceInjector interface {
25 | InjectSourceEarly() *ast.Source
26 | }
27 |
28 | // LateSourceInjector is used to inject more sources, after we have loaded the users schema.
29 | type LateSourceInjector interface {
30 | InjectSourceLate(schema *ast.Schema) *ast.Source
31 | }
32 |
33 | // Implementer is used to generate code inside resolvers
34 | type ResolverImplementer interface {
35 | Implement(field *codegen.Field) string
36 | }
37 |
--------------------------------------------------------------------------------
/_examples/chat/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chat",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@apollo/client": "^3.2.3",
7 | "apollo-utilities": "^1.0.26",
8 | "graphql": "^14.0.2",
9 | "graphql-sse": "^2.0.0",
10 | "graphql-tag": "^2.10.0",
11 | "graphql-ws": "^5.8.1",
12 | "react": "^16.6.3",
13 | "react-dom": "^16.6.3",
14 | "react-scripts": "^2.1.1",
15 | "styled-components": "^5.2.0",
16 | "subscriptions-transport-ws": "^0.9.5",
17 | "typescript": "^4.9.4"
18 | },
19 | "scripts": {
20 | "start": "react-scripts start",
21 | "start:graphql-transport-ws": "REACT_APP_WS_PROTOCOL=graphql-transport-ws npm run start",
22 | "start:graphql-sse": "REACT_APP_SSE_PROTOCOL=true npm run start",
23 | "build": "react-scripts build",
24 | "test": "react-scripts test --env=jsdom",
25 | "eject": "react-scripts eject"
26 | },
27 | "browserslist": [
28 | ">0.2%",
29 | "not dead",
30 | "not ie <= 11",
31 | "not op_mini all"
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/scalar_default_test.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/99designs/gqlgen/client"
8 | "github.com/99designs/gqlgen/graphql/handler"
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func TestDefaultScalarImplementation(t *testing.T) {
13 | resolvers := &Stub{}
14 |
15 | c := client.New(handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: resolvers})))
16 |
17 | resolvers.QueryResolver.DefaultScalar = func(ctx context.Context, arg string) (i string, e error) {
18 | return arg, nil
19 | }
20 |
21 | t.Run("with arg value", func(t *testing.T) {
22 | var resp struct{ DefaultScalar string }
23 | c.MustPost(`query { defaultScalar(arg: "fff") }`, &resp)
24 | require.Equal(t, "fff", resp.DefaultScalar)
25 | })
26 |
27 | t.Run("with default value", func(t *testing.T) {
28 | var resp struct{ DefaultScalar string }
29 | c.MustPost(`query { defaultScalar }`, &resp)
30 | require.Equal(t, "default", resp.DefaultScalar)
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/scalar_default_test.go:
--------------------------------------------------------------------------------
1 | package followschema
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/99designs/gqlgen/client"
8 | "github.com/99designs/gqlgen/graphql/handler"
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func TestDefaultScalarImplementation(t *testing.T) {
13 | resolvers := &Stub{}
14 |
15 | c := client.New(handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: resolvers})))
16 |
17 | resolvers.QueryResolver.DefaultScalar = func(ctx context.Context, arg string) (i string, e error) {
18 | return arg, nil
19 | }
20 |
21 | t.Run("with arg value", func(t *testing.T) {
22 | var resp struct{ DefaultScalar string }
23 | c.MustPost(`query { defaultScalar(arg: "fff") }`, &resp)
24 | require.Equal(t, "fff", resp.DefaultScalar)
25 | })
26 |
27 | t.Run("with default value", func(t *testing.T) {
28 | var resp struct{ DefaultScalar string }
29 | c.MustPost(`query { defaultScalar }`, &resp)
30 | require.Equal(t, "default", resp.DefaultScalar)
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/_examples/chat/readme.md:
--------------------------------------------------------------------------------
1 | # Chat App
2 |
3 | Example app using subscriptions to build a chat room.
4 |
5 | ### Server
6 |
7 | ```bash
8 | go run ./server/server.go
9 | ```
10 |
11 | ### Client
12 |
13 | The react app uses two different implementation for the websocket link
14 |
15 | - [apollo-link-ws](https://www.apollographql.com/docs/react/api/link/apollo-link-ws) which uses the deprecated [subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws) library
16 | - [graphql-ws](https://github.com/enisdenjo/graphql-ws)
17 |
18 | First you need to install the dependencies
19 |
20 | ```bash
21 | npm install
22 | ```
23 |
24 | Then to run the app with the `apollo-link-ws` implementation do
25 |
26 | ```bash
27 | npm run start
28 | ```
29 |
30 | or to run the app with the `graphql-ws` implementation (and the newer `graphql-transport-ws` protocol) do
31 |
32 | ```bash
33 | npm run start:graphql-transport-ws
34 | ```
35 |
36 | or to run the app with the `graphql-sse` implementation do
37 |
38 | ```bash
39 | npm run start:graphql-sse
40 | ```
41 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/ptr_to_slice_test.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/99designs/gqlgen/client"
8 | "github.com/99designs/gqlgen/graphql/handler"
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func TestPtrToSlice(t *testing.T) {
13 | resolvers := &Stub{}
14 |
15 | c := client.New(handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: resolvers})))
16 |
17 | resolvers.QueryResolver.PtrToSliceContainer = func(ctx context.Context) (wrappedStruct *PtrToSliceContainer, e error) {
18 | ptrToSliceContainer := PtrToSliceContainer{
19 | PtrToSlice: &[]string{"hello"},
20 | }
21 | return &ptrToSliceContainer, nil
22 | }
23 |
24 | t.Run("pointer to slice", func(t *testing.T) {
25 | var resp struct {
26 | PtrToSliceContainer struct {
27 | PtrToSlice []string
28 | }
29 | }
30 |
31 | err := c.Post(`query { ptrToSliceContainer { ptrToSlice }}`, &resp)
32 | require.NoError(t, err)
33 |
34 | require.Equal(t, []string{"hello"}, resp.PtrToSliceContainer.PtrToSlice)
35 | })
36 | }
37 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/ptr_to_slice_test.go:
--------------------------------------------------------------------------------
1 | package followschema
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/99designs/gqlgen/client"
8 | "github.com/99designs/gqlgen/graphql/handler"
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func TestPtrToSlice(t *testing.T) {
13 | resolvers := &Stub{}
14 |
15 | c := client.New(handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: resolvers})))
16 |
17 | resolvers.QueryResolver.PtrToSliceContainer = func(ctx context.Context) (wrappedStruct *PtrToSliceContainer, e error) {
18 | ptrToSliceContainer := PtrToSliceContainer{
19 | PtrToSlice: &[]string{"hello"},
20 | }
21 | return &ptrToSliceContainer, nil
22 | }
23 |
24 | t.Run("pointer to slice", func(t *testing.T) {
25 | var resp struct {
26 | PtrToSliceContainer struct {
27 | PtrToSlice []string
28 | }
29 | }
30 |
31 | err := c.Post(`query { ptrToSliceContainer { ptrToSlice }}`, &resp)
32 | require.NoError(t, err)
33 |
34 | require.Equal(t, []string{"hello"}, resp.PtrToSliceContainer.PtrToSlice)
35 | })
36 | }
37 |
--------------------------------------------------------------------------------
/graphql/cache.go:
--------------------------------------------------------------------------------
1 | package graphql
2 |
3 | import "context"
4 |
5 | // Cache is a shared store for APQ and query AST caching
6 | type Cache interface {
7 | // Get looks up a key's value from the cache.
8 | Get(ctx context.Context, key string) (value interface{}, ok bool)
9 |
10 | // Add adds a value to the cache.
11 | Add(ctx context.Context, key string, value interface{})
12 | }
13 |
14 | // MapCache is the simplest implementation of a cache, because it can not evict it should only be used in tests
15 | type MapCache map[string]interface{}
16 |
17 | // Get looks up a key's value from the cache.
18 | func (m MapCache) Get(ctx context.Context, key string) (value interface{}, ok bool) {
19 | v, ok := m[key]
20 | return v, ok
21 | }
22 |
23 | // Add adds a value to the cache.
24 | func (m MapCache) Add(ctx context.Context, key string, value interface{}) { m[key] = value }
25 |
26 | type NoCache struct{}
27 |
28 | func (n NoCache) Get(ctx context.Context, key string) (value interface{}, ok bool) { return nil, false }
29 | func (n NoCache) Add(ctx context.Context, key string, value interface{}) {}
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2020 gqlgen authors
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/codegen/testserver/singlefile/validtypes_test.go:
--------------------------------------------------------------------------------
1 | package singlefile
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/99designs/gqlgen/client"
8 | "github.com/99designs/gqlgen/graphql/handler"
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func TestValidType(t *testing.T) {
13 | resolvers := &Stub{}
14 | resolvers.QueryResolver.ValidType = func(ctx context.Context) (validType *ValidType, e error) {
15 | return &ValidType{
16 | DifferentCase: "new",
17 | DifferentCaseOld: "old",
18 | }, nil
19 | }
20 |
21 | c := client.New(handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: resolvers})))
22 |
23 | t.Run("fields with differing cases can be distinguished", func(t *testing.T) {
24 | var resp struct {
25 | ValidType struct {
26 | New string `json:"differentCase"`
27 | Old string `json:"different_case"`
28 | }
29 | }
30 | err := c.Post(`query { validType { differentCase, different_case } }`, &resp)
31 | require.NoError(t, err)
32 |
33 | require.Equal(t, "new", resp.ValidType.New)
34 | require.Equal(t, "old", resp.ValidType.Old)
35 | })
36 | }
37 |
--------------------------------------------------------------------------------
/codegen/testserver/followschema/validtypes_test.go:
--------------------------------------------------------------------------------
1 | package followschema
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/99designs/gqlgen/client"
8 | "github.com/99designs/gqlgen/graphql/handler"
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func TestValidType(t *testing.T) {
13 | resolvers := &Stub{}
14 | resolvers.QueryResolver.ValidType = func(ctx context.Context) (validType *ValidType, e error) {
15 | return &ValidType{
16 | DifferentCase: "new",
17 | DifferentCaseOld: "old",
18 | }, nil
19 | }
20 |
21 | c := client.New(handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: resolvers})))
22 |
23 | t.Run("fields with differing cases can be distinguished", func(t *testing.T) {
24 | var resp struct {
25 | ValidType struct {
26 | New string `json:"differentCase"`
27 | Old string `json:"different_case"`
28 | }
29 | }
30 | err := c.Post(`query { validType { differentCase, different_case } }`, &resp)
31 | require.NoError(t, err)
32 |
33 | require.Equal(t, "new", resp.ValidType.New)
34 | require.Equal(t, "old", resp.ValidType.Old)
35 | })
36 | }
37 |
--------------------------------------------------------------------------------
/integration/schema.graphql:
--------------------------------------------------------------------------------
1 | "This directive does magical things"
2 | directive @magic(kind: Int) on FIELD_DEFINITION
3 |
4 | scalar Map
5 |
6 | type Element {
7 | child: Element!
8 | error: Boolean!
9 | mismatched: [Boolean!]
10 | }
11 |
12 | enum DATE_FILTER_OP {
13 | # multi
14 | # line
15 | # comment
16 | EQ
17 | NEQ
18 | GT
19 | GTE
20 | LT
21 | LTE
22 | }
23 |
24 | input DateFilter {
25 | value: String!
26 | timezone: String = "UTC"
27 | op: DATE_FILTER_OP = EQ
28 | }
29 |
30 | type Viewer {
31 | user: User
32 | }
33 |
34 | input ListCoercion {
35 | enumVal: [ErrorType]
36 | strVal: [String]
37 | intVal: [Int]
38 | scalarVal: [Map]
39 | }
40 |
41 | type Query {
42 | path: [Element]
43 | date(filter: DateFilter!): Boolean!
44 | viewer: Viewer
45 | jsonEncoding: String!
46 | error(type: ErrorType = NORMAL): Boolean!
47 | complexity(value: Int!): Boolean!
48 | coercion(value: [ListCoercion!]): Boolean!
49 | }
50 |
51 | enum ErrorType {
52 | CUSTOM
53 | NORMAL
54 | }
55 |
56 | # this is a comment with a `backtick`
57 |
--------------------------------------------------------------------------------
/integration/schema-expected.graphql:
--------------------------------------------------------------------------------
1 | """This directive does magical things"""
2 | directive @magic(kind: Int) on FIELD_DEFINITION
3 |
4 | enum DATE_FILTER_OP {
5 | EQ
6 | GT
7 | GTE
8 | LT
9 | LTE
10 | NEQ
11 | }
12 |
13 | input DateFilter {
14 | op: DATE_FILTER_OP = EQ
15 | timezone: String = "UTC"
16 | value: String!
17 | }
18 |
19 | type Element {
20 | child: Element!
21 | error: Boolean!
22 | mismatched: [Boolean!]
23 | }
24 |
25 | enum ErrorType {
26 | CUSTOM
27 | NORMAL
28 | }
29 |
30 | input ListCoercion {
31 | enumVal: [ErrorType]
32 | intVal: [Int]
33 | scalarVal: [Map]
34 | strVal: [String]
35 | }
36 |
37 | scalar Map
38 |
39 | type Query {
40 | coercion(value: [ListCoercion!]): Boolean!
41 | complexity(value: Int!): Boolean!
42 | date(filter: DateFilter!): Boolean!
43 | error(type: ErrorType = NORMAL): Boolean!
44 | jsonEncoding: String!
45 | path: [Element]
46 | viewer: Viewer
47 | }
48 |
49 | type RemoteModelWithOmitempty {
50 | newDesc: String
51 | }
52 |
53 | type User {
54 | likes: [String!]!
55 | name: String!
56 | }
57 |
58 | type Viewer {
59 | user: User
60 | }
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/99designs/gqlgen
2 |
3 | go 1.18
4 |
5 | require (
6 | github.com/gorilla/websocket v1.5.0
7 | github.com/hashicorp/golang-lru/v2 v2.0.1
8 | github.com/kevinmbeaulieu/eq-go v1.0.0
9 | github.com/logrusorgru/aurora/v3 v3.0.0
10 | github.com/matryer/moq v0.2.7
11 | github.com/mattn/go-colorable v0.1.13
12 | github.com/mattn/go-isatty v0.0.17
13 | github.com/mitchellh/mapstructure v1.5.0
14 | github.com/stretchr/testify v1.8.2
15 | github.com/urfave/cli/v2 v2.24.4
16 | github.com/vektah/gqlparser/v2 v2.5.1
17 | golang.org/x/text v0.7.0
18 | golang.org/x/tools v0.6.0
19 | google.golang.org/protobuf v1.28.1
20 | gopkg.in/yaml.v3 v3.0.1
21 | )
22 |
23 | require (
24 | github.com/agnivade/levenshtein v1.1.1 // indirect
25 | github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
26 | github.com/davecgh/go-spew v1.1.1 // indirect
27 | github.com/pmezard/go-difflib v1.0.0 // indirect
28 | github.com/russross/blackfriday/v2 v2.1.0 // indirect
29 | github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
30 | golang.org/x/mod v0.8.0 // indirect
31 | golang.org/x/sys v0.5.0 // indirect
32 | )
33 |
--------------------------------------------------------------------------------
/_examples/todo/models_gen.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
2 |
3 | package todo
4 |
5 | import (
6 | "fmt"
7 | "io"
8 | "strconv"
9 | )
10 |
11 | // Passed to createTodo to create a new todo
12 | type TodoInput struct {
13 | // The body text
14 | Text string `json:"text"`
15 | // Is it done already?
16 | Done *bool `json:"done,omitempty"`
17 | }
18 |
19 | type Role string
20 |
21 | const (
22 | RoleAdmin Role = "ADMIN"
23 | RoleOwner Role = "OWNER"
24 | )
25 |
26 | var AllRole = []Role{
27 | RoleAdmin,
28 | RoleOwner,
29 | }
30 |
31 | func (e Role) IsValid() bool {
32 | switch e {
33 | case RoleAdmin, RoleOwner:
34 | return true
35 | }
36 | return false
37 | }
38 |
39 | func (e Role) String() string {
40 | return string(e)
41 | }
42 |
43 | func (e *Role) UnmarshalGQL(v interface{}) error {
44 | str, ok := v.(string)
45 | if !ok {
46 | return fmt.Errorf("enums must be strings")
47 | }
48 |
49 | *e = Role(str)
50 | if !e.IsValid() {
51 | return fmt.Errorf("%s is not a valid Role", str)
52 | }
53 | return nil
54 | }
55 |
56 | func (e Role) MarshalGQL(w io.Writer) {
57 | fmt.Fprint(w, strconv.Quote(e.String()))
58 | }
59 |
--------------------------------------------------------------------------------
/bin/release:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -eu
4 |
5 | if ! [ $# -eq 1 ] ; then
6 | echo "usage: ./bin/release [version]"
7 | exit 1
8 | fi
9 |
10 | VERSION=$1
11 |
12 | if ! git diff-index --quiet HEAD -- ; then
13 | echo "uncommited changes on HEAD, aborting"
14 | exit 1
15 | fi
16 |
17 | if [[ ${VERSION:0:1} != "v" ]] ; then
18 | echo "version strings must start with v"
19 | exit 1
20 | fi
21 |
22 | git fetch origin
23 | git checkout origin/master
24 |
25 | cat > graphql/version.go < graphql/version.go <