The project is under heavy development. It is stable enough so we use it in production at Sourcegraph, but expect changes.
- full support of GraphQL spec (October 2016)
- propagation of
null
on resolver errors - everything else
- propagation of
- minimal API
- support for context.Context and OpenTracing
- early error detection at application startup by type-checking if the given resolver matches the schema
- resolvers are purely based on method sets (e.g. it's up to you if you want to resolve a GraphQL interface with a Go interface or a Go struct)
- nice error messages (no internal panics, even with an invalid schema or resolver; please file a bug if you see an internal panic)
- nice errors on resolver validation
- nice errors on all invalid schemas
- nice errors on all invalid queries
- panic handling (a panic in a resolver should not take down the whole app)
- parallel execution of resolvers
A resolver must have one method for each field of the GraphQL type it resolves. The method name has to be exported and match the field's name in a non-case-sensitive way.
The method has up to two arguments:
- Optional
context.Context
argument. - Mandatory
*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:
- The GraphQL field's value as determined by the resolver.
- Optional
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
}
OpenTracing spans are automatically created for each field of the GraphQL query. Fields are marked as trivial if they have no context.Context
argument, no field arguments and no error
result. You can use this to avoid unnecessary clutter in the trace:
type trivialFieldsFilter struct {
rec basictracer.SpanRecorder
}
func (f *trivialFieldsFilter) RecordSpan(span basictracer.RawSpan) {
if b, ok := span.Tags[graphql.OpenTracingTagTrivial].(bool); ok && b {
return
}
f.rec.RecordSpan(span)
}