Product
Introducing License Enforcement in Socket
Ensure open-source compliance with Socket’s License Enforcement Beta. Set up your License Policy and secure your software!
github.com/graph-gophers/graphql-go
The goal of this project is to provide full support of the GraphQL draft specification with a set of idiomatic, easy to use Go packages.
While still under heavy development (internal
APIs are almost certainly subject to change), this library is
safe for production use.
context.Context
OpenTelemetry
and OpenTracing
standardsWe're trying out the GitHub Project feature to manage graphql-go
's development roadmap.
Feedback is welcome and appreciated.
In order to run a simple GraphQL server locally create a main.go
file with the following content:
package main
import (
"log"
"net/http"
graphql "github.com/graph-gophers/graphql-go"
"github.com/graph-gophers/graphql-go/relay"
)
type query struct{}
func (_ *query) Hello() string { return "Hello, world!" }
func main() {
s := `
type Query {
hello: String!
}
`
schema := graphql.MustParseSchema(s, &query{})
http.Handle("/query", &relay.Handler{Schema: schema})
log.Fatal(http.ListenAndServe(":8080", nil))
}
Then run the file with go run main.go
. To test:
curl -XPOST -d '{"query": "{ hello }"}' localhost:8080/query
For more realistic usecases check our examples section.
A resolver must have one method or field for each field of the GraphQL type it resolves. The method or field name has to be exported and match the schema's field's name in a non-case-sensitive way.
You can use struct fields as resolvers by using SchemaOpt: UseFieldResolvers()
. For example,
opts := []graphql.SchemaOpt{graphql.UseFieldResolvers()}
schema := graphql.MustParseSchema(s, &query{}, opts...)
When using UseFieldResolvers
schema option, a struct field will be used only when:
The method has up to two arguments:
context.Context
argument.*struct { ... }
argument if the corresponding GraphQL field has arguments. The names of the struct fields have to be exported and have to match the names of the GraphQL arguments in a non-case-sensitive way.The method has up to two results:
error
result.Example for a simple resolver method:
func (r *helloWorldResolver) Hello() string {
return "Hello world!"
}
The following signature is also allowed:
func (r *helloWorldResolver) Hello(ctx context.Context) (string, error) {
return "Hello world!", nil
}
UseStringDescriptions()
enables the usage of double quoted and triple quoted. When this is not enabled, comments are parsed as descriptions instead.UseFieldResolvers()
specifies whether to use struct field resolvers.MaxDepth(n int)
specifies the maximum field nesting depth in a query. The default is 0 which disables max depth checking.MaxParallelism(n int)
specifies the maximum number of resolvers per request allowed to run in parallel. The default is 10.Tracer(tracer trace.Tracer)
is used to trace queries and fields. It defaults to noop.Tracer
.Logger(logger log.Logger)
is used to log panics during query execution. It defaults to exec.DefaultLogger
.PanicHandler(panicHandler errors.PanicHandler)
is used to transform panics into errors during query execution. It defaults to errors.DefaultPanicHandler
.DisableIntrospection()
disables introspection queries.Errors returned by resolvers can include custom extensions by implementing the ResolverError
interface:
type ResolverError interface {
error
Extensions() map[string]interface{}
}
Example of a simple custom error:
type droidNotFoundError struct {
Code string `json:"code"`
Message string `json:"message"`
}
func (e droidNotFoundError) Error() string {
return fmt.Sprintf("error [%s]: %s", e.Code, e.Message)
}
func (e droidNotFoundError) Extensions() map[string]interface{} {
return map[string]interface{}{
"code": e.Code,
"message": e.Message,
}
}
Which could produce a GraphQL error such as:
{
"errors": [
{
"message": "error [NotFound]: This is not the droid you are looking for",
"path": [
"droid"
],
"extensions": {
"code": "NotFound",
"message": "This is not the droid you are looking for"
}
}
],
"data": null
}
By default the library uses noop.Tracer
. If you want to change that you can use the OpenTelemetry or the OpenTracing implementations, respectively:
// OpenTelemetry tracer
package main
import (
"github.com/graph-gophers/graphql-go"
"github.com/graph-gophers/graphql-go/example/starwars"
otelgraphql "github.com/graph-gophers/graphql-go/trace/otel"
"github.com/graph-gophers/graphql-go/trace/tracer"
)
// ...
_, err := graphql.ParseSchema(starwars.Schema, nil, graphql.Tracer(otelgraphql.DefaultTracer()))
// ...
Alternatively you can pass an existing trace.Tracer instance:
tr := otel.Tracer("example")
_, err = graphql.ParseSchema(starwars.Schema, nil, graphql.Tracer(&otelgraphql.Tracer{Tracer: tr}))
// OpenTracing tracer
package main
import (
"github.com/graph-gophers/graphql-go"
"github.com/graph-gophers/graphql-go/example/starwars"
"github.com/graph-gophers/graphql-go/trace/opentracing"
"github.com/graph-gophers/graphql-go/trace/tracer"
)
// ...
_, err := graphql.ParseSchema(starwars.Schema, nil, graphql.Tracer(opentracing.Tracer{}))
// ...
If you need to implement a custom tracer the library would accept any tracer which implements the interface below:
type Tracer interface {
TraceQuery(ctx context.Context, queryString string, operationName string, variables map[string]interface{}, varTypes map[string]*introspection.Type) (context.Context, func([]*errors.QueryError))
TraceField(ctx context.Context, label, typeName, fieldName string, trivial bool, args map[string]interface{}) (context.Context, func(*errors.QueryError))
TraceValidation(context.Context) func([]*errors.QueryError)
}
FAQs
Unknown package
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
Ensure open-source compliance with Socket’s License Enforcement Beta. Set up your License Policy and secure your software!
Product
We're launching a new set of license analysis and compliance features for analyzing, managing, and complying with licenses across a range of supported languages and ecosystems.
Product
We're excited to introduce Socket Optimize, a powerful CLI command to secure open source dependencies with tested, optimized package overrides.