CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/golang-github-com--graphql-go--graphql

Complete GraphQL implementation in Go with schema definition, query execution, and validation.

Overview
Eval results
Files

execution.mddocs/reference/

Execution

Execute GraphQL queries, mutations, and subscriptions against a schema.

Primary Entry Point: Do

Do is the all-in-one function that parses, validates, and executes a GraphQL operation.

func Do(p Params) *Result

type Params struct {
    // The GraphQL schema to validate and execute against.
    Schema Schema

    // A GraphQL language formatted string representing the requested operation.
    RequestString string

    // The value provided as the first argument to resolver functions on the top
    // level type (e.g. the query object type).
    RootObject map[string]interface{}

    // A mapping of variable name to runtime value for all variables defined
    // in the RequestString.
    VariableValues map[string]interface{}

    // The name of the operation to use if RequestString contains multiple
    // possible operations. Can be omitted if only one operation is present.
    OperationName string

    // Context may be provided to pass application-specific per-request
    // information to resolve functions.
    Context context.Context
}
type Result struct {
    Data       interface{}                `json:"data"`
    Errors     []gqlerrors.FormattedError `json:"errors,omitempty"`
    Extensions map[string]interface{}     `json:"extensions,omitempty"`
}

func (r *Result) HasErrors() bool

Example:

result := graphql.Do(graphql.Params{
    Schema:        schema,
    RequestString: `query Hero($ep: Episode) { hero(episode: $ep) { name } }`,
    VariableValues: map[string]interface{}{
        "ep": "JEDI",
    },
    Context: ctx,
})
if result.HasErrors() {
    log.Printf("errors: %v", result.Errors)
}

Low-Level Execute

Use Execute when you have already parsed the document (e.g., to cache the AST).

func Execute(p ExecuteParams) (result *Result)

type ExecuteParams struct {
    Schema        Schema
    Root          interface{}
    AST           *ast.Document
    OperationName string
    Args          map[string]interface{} // variable values
    Context       context.Context
}

Example:

doc, err := parser.Parse(parser.ParseParams{Source: querySource})
if err != nil {
    // handle parse error
}
result := graphql.Execute(graphql.ExecuteParams{
    Schema:  schema,
    AST:     doc,
    Root:    rootValue,
    Args:    variableValues,
    Context: ctx,
})

Subscriptions

Subscriptions return a channel that emits *Result values. Close the channel from inside the subscribe resolver to end the subscription.

func Subscribe(p Params) chan *Result

Subscribe uses the same Params as Do but performs the subscribe phase instead of execute. The subscription field resolver (Field.Subscribe) returns a channel that is iterated.

SubscribeParams is an alternative params struct (defined for future use; the current Subscribe function takes Params):

type SubscribeParams struct {
    Schema          Schema
    RequestString   string
    RootValue       interface{}
    VariableValues  map[string]interface{}
    OperationName   string
    FieldResolver   FieldResolveFn
    FieldSubscriber FieldResolveFn
}
func ExecuteSubscription(p ExecuteParams) chan *Result

ExecuteSubscription is like Execute but for subscription operations. Does not support extensions.

Example:

// Define a subscription field
subscriptionType := graphql.NewObject(graphql.ObjectConfig{
    Name: "Subscription",
    Fields: graphql.Fields{
        "messageAdded": &graphql.Field{
            Type: messageType,
            Subscribe: func(p graphql.ResolveParams) (interface{}, error) {
                ch := make(chan interface{})
                go func() {
                    for msg := range messageChannel {
                        ch <- msg
                    }
                    close(ch)
                }()
                return ch, nil
            },
            Resolve: func(p graphql.ResolveParams) (interface{}, error) {
                return p.Source, nil
            },
        },
    },
})

// Execute subscription
c := graphql.Subscribe(graphql.Params{
    Schema:        schema,
    RequestString: `subscription { messageAdded { id text } }`,
})
for result := range c {
    // handle each result
    fmt.Println(result.Data)
}

Resolver Functions

type FieldResolveFn func(p ResolveParams) (interface{}, error)

type ResolveParams struct {
    // Source is the source/parent value.
    Source interface{}

    // Args is a map of arguments for the current field.
    Args map[string]interface{}

    // Info contains information about the current execution state.
    Info ResolveInfo

    // Context is the per-request context value.
    Context context.Context
}

type ResolveInfo struct {
    FieldName      string
    FieldASTs      []*ast.Field
    Path           *ResponsePath
    ReturnType     Output
    ParentType     Composite
    Schema         Schema
    Fragments      map[string]ast.Definition
    RootValue      interface{}
    Operation      ast.Definition
    VariableValues map[string]interface{}
}

Default Resolver

If no Resolve function is specified, the default resolver is used:

func DefaultResolveFn(p ResolveParams) (interface{}, error)

The default resolver:

  1. Checks if Source implements the FieldResolver interface (has a Resolve(ResolveParams) method) and calls it.
  2. Otherwise, uses reflection to find a field or method on Source with the same name (case-insensitive) as the GraphQL field.
type FieldResolver interface {
    Resolve(p ResolveParams) (interface{}, error)
}

Response Path

type ResponsePath struct {
    Prev *ResponsePath
    Key  interface{} // string for field names, int for list indices
}

func (p *ResponsePath) AsArray() []interface{}
func (p *ResponsePath) WithKey(key interface{}) *ResponsePath

IsTypeOf

Used for interface and union type resolution at the object level:

type IsTypeOfFn func(p IsTypeOfParams) bool

type IsTypeOfParams struct {
    Value   interface{}
    Info    ResolveInfo
    Context context.Context
}

Extensions

Extensions add middleware-like hooks to schema execution.

type Extension interface {
    // Init initializes the extension and returns a (possibly modified) context.
    Init(context.Context, *Params) context.Context

    // Name returns the extension name.
    Name() string

    // ParseDidStart is called before parsing begins.
    ParseDidStart(context.Context) (context.Context, ParseFinishFunc)

    // ValidationDidStart is called before validation begins.
    ValidationDidStart(context.Context) (context.Context, ValidationFinishFunc)

    // ExecutionDidStart is called before execution begins.
    ExecutionDidStart(context.Context) (context.Context, ExecutionFinishFunc)

    // ResolveFieldDidStart is called before each field is resolved.
    ResolveFieldDidStart(context.Context, *ResolveInfo) (context.Context, ResolveFieldFinishFunc)

    // HasResult returns true if the extension wants to add data to the result.
    HasResult() bool

    // GetResult returns extension data to merge into result.Extensions.
    GetResult(context.Context) interface{}
}

type ParseFinishFunc           func(error)
type ValidationFinishFunc      func([]gqlerrors.FormattedError)
type ExecutionFinishFunc        func(*Result)
type ResolveFieldFinishFunc     func(interface{}, error)

Add extensions to a schema:

schema.AddExtensions(myExtension)

Or via SchemaConfig:

schema, _ := graphql.NewSchema(graphql.SchemaConfig{
    Query:      queryType,
    Extensions: []graphql.Extension{myExtension},
})

Error Handling in Resolvers

Resolvers return (interface{}, error). Any non-nil error becomes a FormattedError in Result.Errors. The field value in Result.Data is set to null for that field.

For partial results with errors (field-level errors), return a non-nil value along with a non-nil error; the error is appended to Result.Errors and the field value may still be included.

Located errors provide location information:

func NewLocatedError(err interface{}, nodes []ast.Node) *gqlerrors.Error
func NewLocatedErrorWithPath(err interface{}, nodes []ast.Node, path []interface{}) *gqlerrors.Error

Install with Tessl CLI

npx tessl i tessl/golang-github-com--graphql-go--graphql

docs

index.md

tile.json