graphql

package
v2.16.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2026 License: MIT Imports: 32 Imported by: 0

Documentation

Overview

Package graphql serves GraphQL: a schema of Go values, the validation and execution of operations against it, introspection, the schema's SDL, and the GraphQL-over-HTTP transport. It follows the GraphQL specification (October 2021) and has no dependencies beyond the standard library.

A schema is built from the types in this file — Object, FieldDef, Scalar, Enum, Interface, Union, InputObject, List and NonNull — and NewSchema checks it as the specification's type system requires. NewServer serves one: Execute runs a request, ServeHTTP answers one over HTTP.

Index

Constants

View Source
const (
	DefaultPageSize = 10
	MaxPageSize     = 100
)

The sizes of a page: a Page giving neither first nor last reads DefaultPageSize rows forwards, and one asking for more than MaxPageSize is refused.

View Source
const (
	CodeParseFailed      = "GRAPHQL_PARSE_FAILED"      // the document doesn't parse
	CodeValidationFailed = "GRAPHQL_VALIDATION_FAILED" // a validation rule refuses it
	CodeBadUserInput     = "BAD_USER_INPUT"            // a variable's or argument's value its type refuses
	CodeBadRequest       = "BAD_REQUEST"               // no operation to run, a malformed HTTP request, a subscription
	CodeDepthLimit       = "DEPTH_LIMIT"               // Limits.Depth
	CodeComplexityLimit  = "COMPLEXITY_LIMIT"          // Limits.Complexity
	CodeAliasLimit       = "ALIAS_LIMIT"               // Limits.Aliases
	CodeFieldLimit       = "FIELD_LIMIT"               // Limits.Fields
	CodeSizeLimit        = "SIZE_LIMIT"                // Limits.Bytes
	CodeTimeout          = "TIMEOUT"                   // Limits.Timeout, or the request's context ending
	CodeInternal         = "INTERNAL_SERVER_ERROR"     // a resolver's panic, without Config.Present
)

The extensions.code of the errors the engine itself reports. Errors a resolver returns carry what Config.Present gives them.

View Source
const (
	MediaGraphQLResponse = "application/graphql-response+json"
	MediaJSON            = "application/json"
)

The media types of GraphQL over HTTP.

View Source
const (
	DefaultDepth      = 10
	DefaultComplexity = 1000
	DefaultListSize   = 10
	DefaultAliases    = 30
	DefaultFields     = 500
	DefaultBytes      = 100_000
	DefaultTimeout    = 10 * time.Second
)

Limits' defaults.

View Source
const (
	CodeInvalidInput    = "INVALID_INPUT"   // a form's checks, web.Invalid, a 422
	CodeUnauthenticated = "UNAUTHENTICATED" // web.Unauthorized, a 401
	CodeForbidden       = "FORBIDDEN"       // web.Forbidden, a 403
	CodeNotFound        = "NOT_FOUND"       // web.NotFound, a 404
	CodeConflict        = "CONFLICT"        // web.Conflict, a 409
)

The extensions.code of errors a resolver's error becomes.

View Source
const (
	SchemaEnv = "VUKA_GRAPHQL_SCHEMA"
	CheckEnv  = "VUKA_GRAPHQL_CHECK"
)

The environment variables vuka graphql schema runs the app with: the app writes its schema's SDL (to the file named, or stdout for "-"), or compares it with the committed SDL in the file named, then exits.

View Source
const DefaultChunk = 1000

DefaultChunk is how many keys one call of a loader's function takes at most unless @graphql.Loader{Chunk: n} says otherwise: more keys are split into calls of that many.

View Source
const DefaultDeprecationReason = "No longer supported"

DefaultDeprecationReason is the reason of a deprecation that gives none.

Variables

View Source
var (
	IncludeDirective = &Directive{
		Name:        "include",
		Description: "Directs the executor to include this field or fragment only when the `if` argument is true.",
		Locations:   []string{"FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"},
		Args:        []*ArgDef{{Name: "if", Description: "Included when true.", Type: &NonNull{Of: Boolean}}},
	}
	SkipDirective = &Directive{
		Name:        "skip",
		Description: "Directs the executor to skip this field or fragment when the `if` argument is true.",
		Locations:   []string{"FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"},
		Args:        []*ArgDef{{Name: "if", Description: "Skipped when true.", Type: &NonNull{Of: Boolean}}},
	}
	DeprecatedDirective = &Directive{
		Name:        "deprecated",
		Description: "Marks an element of a GraphQL schema as no longer supported.",
		Locations:   []string{"FIELD_DEFINITION", "ARGUMENT_DEFINITION", "INPUT_FIELD_DEFINITION", "ENUM_VALUE"},
		Args: []*ArgDef{{
			Name:        "reason",
			Description: "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/).",
			Type:        String,
			Default:     &language.StringValue{Value: DefaultDeprecationReason},
		}},
	}
	SpecifiedByDirective = &Directive{
		Name:        "specifiedBy",
		Description: "Exposes a URL that specifies the behavior of this scalar.",
		Locations:   []string{"SCALAR"},
		Args:        []*ArgDef{{Name: "url", Description: "The URL that specifies the behavior of this scalar.", Type: &NonNull{Of: String}}},
	}
)

The specification's directives, which every schema has.

View Source
var (
	Int = &Scalar{
		Name:         "Int",
		Description:  "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.",
		Serialize:    serializeInt,
		ParseValue:   parseIntValue,
		ParseLiteral: parseIntLiteral,
	}
	Float = &Scalar{
		Name:         "Float",
		Description:  "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).",
		Serialize:    serializeFloat,
		ParseValue:   parseFloatValue,
		ParseLiteral: parseFloatLiteral,
	}
	String = &Scalar{
		Name:         "String",
		Description:  "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.",
		Serialize:    serializeString,
		ParseValue:   parseStringValue,
		ParseLiteral: parseStringLiteral,
	}
	Boolean = &Scalar{
		Name:         "Boolean",
		Description:  "The `Boolean` scalar type represents `true` or `false`.",
		Serialize:    serializeBoolean,
		ParseValue:   parseBooleanValue,
		ParseLiteral: parseBooleanLiteral,
	}
	ID = &Scalar{
		Name:         "ID",
		Description:  "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.",
		Serialize:    serializeID,
		ParseValue:   parseIDValue,
		ParseLiteral: parseIDLiteral,
	}
)

The specification's scalars. Resolvers get Int as int (32-bit), Float as float64, String and ID as string, Boolean as bool; each serializes the Go values that hold it without loss: any integer kind within 32 bits for Int, any number for Float, a string or an integer for ID.

View Source
var DateTime = &Scalar{
	Name:           "DateTime",
	Description:    "A date and time, in RFC 3339: 2026-10-26T09:30:00Z.",
	SpecifiedByURL: "https://scalars.graphql.org/andimarek/date-time",
	Serialize: func(v any) (any, error) {
		t, ok := v.(time.Time)
		if p, isPtr := v.(*time.Time); isPtr && p != nil {
			t, ok = *p, true
		}
		if !ok {
			return nil, fmt.Errorf("DateTime cannot represent value: %s", inspect(v))
		}
		return t.Format(time.RFC3339Nano), nil
	},
	ParseValue: func(v any) (any, error) {
		s, ok := v.(string)
		if !ok {
			return nil, fmt.Errorf("DateTime cannot represent a non string value: %s", inspect(v))
		}
		t, err := time.Parse(time.RFC3339Nano, s)
		if err != nil {
			return nil, fmt.Errorf("DateTime cannot represent %q: write a date and time in RFC 3339, like 2026-10-26T09:30:00Z", s)
		}
		return t, nil
	},
}

DateTime is a time.Time, written in RFC 3339 with the fraction of a second it has: "2026-10-26T09:30:00Z".

Functions

func Arg

func Arg(name string, more ...string) vuka.Bundle

Arg names the argument a parameter is, in place of the parameter's name (which Naming would apply to): written before the parameter, it takes the name, func Users(ctx context.Context, @graphql.Arg("cursor") after *string). Above a function or method, the older form, it takes the parameter's name first: @graphql.Arg("after", "cursor").

func As

func As[T any](v any) T

As is v, a coerced input value or a resolver's, as a T: the zero T for nil; a *T's element.

func AsID

func AsID(params ...string) vuka.Bundle

AsID makes a parameter an argument of type ID — a string or an integer a client sends back as it received it, "7" (or 7) — written before it: func Owned(@graphql.AsID owner int64). A parameter of an integer or a string type named id, or ending in ID or Id (ownerID), is one already. Above a function or method, the older form, it names the parameters: @graphql.AsID("owner"). An input struct's field takes a graphql:",id" tag instead.

func AsInt

func AsInt(params ...string) vuka.Bundle

AsInt keeps an integer parameter an Int though its name ends in ID or Id, written before it: func Visits(@graphql.AsInt lastSeenID int). Above a function or method, the older form, it names the parameters: @graphql.AsInt("lastSeenID"). An input struct's or an object's field takes a graphql:",int" tag instead.

func AsOption added in v2.14.0

func AsOption[T any](v any) vuka.Option[T]

AsOption is v, a coerced input value, as a vuka.Option[T]: None for nil, Some of v as a T otherwise.

func AsString

func AsString(params ...string) vuka.Bundle

AsString keeps a string parameter a String though its name ends in ID or Id, written before it: func Track(@graphql.AsString trackingID string). Above a function or method, the older form, it names the parameters: @graphql.AsString("trackingID"). A field takes a graphql:",string" tag instead.

func CamelCase

func CamelCase(s string) string

CamelCase is a Go name in lower camel case, as fields are named by default: CreatedAt is createdAt, ID is id, URLPath is urlPath, UserID is userID.

func Deref

func Deref[T any](p *T) any

Deref is the value p points to, nil for nil: a field or result of a pointer to a scalar or an enum.

func Get

func Get[T any](c *Call, i int) T

Get is parameter i of c as a T: an argument's value, the zero T when the request gave none or null, or a dependency.

func GetOption added in v2.14.0

func GetOption[T any](c *Call, i int) vuka.Option[T]

GetOption is parameter i of c, an argument of type vuka.Option[T]: None when the request gave none or null.

func GetPtr

func GetPtr[E any](c *Call, i int) *E

GetPtr is parameter i of c, an argument of a pointer type *E: nil when the request gave none or null.

func OmitEmpty

func OmitEmpty[E any](xs []E) any

OmitEmpty is the slice xs, nil when it is empty: a list field tagged graphql:",omitempty".

func OmitZero

func OmitZero[T comparable](v T) any

OmitZero is v, nil when it is its type's zero value: a field tagged graphql:",omitempty".

func OptionValue added in v2.14.0

func OptionValue[T any](o vuka.Option[T]) any

OptionValue is o's value, nil for None: a field or a result of type vuka.Option[T].

func Ptr

func Ptr[E any](v any) *E

Ptr is v as a *E: nil for nil, a pointer to a copy of an E.

func Register

func Register(p Package)

Register adds a package's operations and types to the schema of every app serving web.GraphQL. The code the compiler generates for a package's @graphql.Query and @graphql.Mutation functions calls it at init.

func RegisterValue

func RegisterValue[T comparable](v T, attrs ...any)

RegisterValue records the attributes written on an enum constant — @graphql.Value, @graphql.Deprecated — which Go's registry of declarations has no place for. The compiler generates the call for a constant carrying any; Go code may call it too.

func Related[P any](ctx context.Context, parent *P, field string, load func(ctx context.Context, parents []*P, field string) error) error

Related is a relation's rows read into parent: load, given the parents of a request's level that need them, reads them into each; outside a request it is called with parent alone. field names the relation (the toolbar's traces show it); the compiler generates Related's calls for the fields of an orm model holding a relation.

func SnakeCase

func SnakeCase(s string) string

SnakeCase is a Go name in snake case: CreatedAt is created_at, UserID is user_id, URLPath is url_path.

func TypeString

func TypeString(t TypeDef) string

TypeString writes t as a document does: "[String!]!".

Types

type ArgDef

type ArgDef struct {
	Name, Description string
	Type              TypeDef
	Default           language.Value
	Deprecated        bool
	DeprecationReason string
}

ArgDef is an argument of a field or a directive. Default is the value used when it isn't given; nil for none.

type ArgName

type ArgName struct{ Param, Name string }

ArgName names an argument: the attribute Arg gives on a function or a method.

type BatchTrace

type BatchTrace struct {
	Loader string // "OrdersByUser", "Post.Author"
	Keys   int
	Start  time.Time
	Dur    time.Duration
	Err    error
}

BatchTrace is a batch a loader ran: how many keys, how long, its error.

type Binding

type Binding interface {
	// contains filtered or unexported methods
}

Binding describes a Go type of the schema: Struct (an object), FormInput (an input object) or Consts (an enum).

type Boolish

type Boolish interface{ ~bool }

Integer, Floating, Text and Boolish are the Go types IntOf, FloatOf, StringOf and BooleanOf take.

type Call

type Call struct {
	// contains filtered or unexported fields
}

Call is what a resolver is given: the value of each parameter of its function, by index (the context's is nil).

func (*Call) Arg

func (c *Call) Arg(i int) any

Arg is the value of parameter i: an argument's, coerced to its Go type (absent when the request gives none), or a dependency's.

type Change

type Change struct {
	Breaking bool
	Path     string
	Message  string
}

Change is a difference between two versions of a schema. Breaking says a client written against the old one may fail against the new: a type, field, argument or enum value removed or renamed, a type changed in a way its values don't fit (an output made nullable, an input made required), a required argument or input field added, a union member or an implemented interface dropped. Path names the element: "User", "User.email", "Query.users(first:)", "Status.ACTIVE".

func Diff

func Diff(old, new *Schema) []Change

Diff lists what changed from old to new, in a stable order: the old schema's types by name, each one's fields, arguments and values in order, then what new adds.

func (Change) String

func (c Change) String() string

type Config

type Config struct {
	Schema *Schema
	Limits Limits
	// Introspection allows __schema and __type; off, a document selecting
	// them fails validation. __typename is always allowed.
	Introspection bool
	// Present turns a resolver's error (or a Guard's, or a *PanicError)
	// into the response's errors: their messages and extensions. The
	// engine fills each one's Path and Locations when it leaves them
	// empty. Nil shows err.Error(), except for a panic, shown as "internal
	// error".
	Present func(ctx context.Context, err error) []*Error
	// CacheSize is how many parsed and validated documents are kept, by
	// the SHA-256 of their text. Default 256; negative keeps none.
	CacheSize int
	// Observe, when set, is called after each request with the operation
	// run (zero when none was), the response and how long it took.
	Observe func(ctx context.Context, op OperationInfo, res *Response, d time.Duration)
	// Trace, when set, is asked for each request's Trace: nil traces
	// nothing.
	Trace func(ctx context.Context) *Trace
}

Config configures a Server.

type Connection

type Connection[T any] struct {
	Edges    []Edge[T]
	PageInfo PageInfo
	// contains filtered or unexported fields
}

Connection is a page of a list, as GraphQL's cursor connections have it: the page's edges, each a node and its cursor, what lies around the page, and the list's length when a query asks for it. An operation or field returning a Connection[User] is a field of type UserConnection, its edges UserEdge:

@graphql.Query
func Users(ctx context.Context, page graphql.Page) (graphql.Connection[User], error) {
	return graphql.Paginate(ctx, User.Objects.OrderBy("name"), page)
}

{ users(first: 10, after: $cursor) { edges { cursor node { name } } pageInfo { hasNextPage endCursor } totalCount } }

func Paginate

func Paginate[T any](ctx context.Context, from Pageable[T], page Page) (Connection[T], error)

Paginate is the page of from that page asks for. A query set's cursors are keyset cursors where its ordering allows, positions otherwise (see the orm's CursorPage); a cursor of another list, first and last given together, a negative size or one above MaxPageSize are the client's errors (BAD_USER_INPUT).

func (Connection[T]) TotalCount

func (c Connection[T]) TotalCount(ctx context.Context) (int, error)

TotalCount is how many rows the whole list holds: counted only when a query selects it.

type Const

type Const[T comparable] struct {
	Go    string // the constant's name
	Doc   string
	Value T
}

Const is a constant of a Consts.

type Consts

type Consts[T comparable] struct {
	Doc    string
	Values []Const[T]
}

Consts is the enum type a Go type T is: its constants.

type Deprecated

type Deprecated string

Deprecated marks a field, an argument's operation or an enum value deprecated, with the reason introspection and the schema's SDL show: @graphql.Deprecated("use displayName").

type Directive

type Directive struct {
	Name, Description string
	Locations         []string
	Args              []*ArgDef
	Repeatable        bool
}

Directive declares a directive the schema accepts. Locations are the specification's names: "FIELD", "FRAGMENT_SPREAD", "OBJECT", ….

type Edge

type Edge[T any] struct {
	Cursor string
	Node   T
}

Edge is a node of a Connection and its cursor: where a next page starts (after) or ends (before).

type Enum

type Enum struct {
	Name, Description string
	Values            []*EnumValueDef
	// Serialize names the value a resolved Go value is; nil compares it
	// with each value's Value.
	Serialize func(v any) (string, error)
}

Enum is a type of named values.

func (*Enum) TypeName

func (t *Enum) TypeName() string

TypeName is the type's name.

type EnumValueDef

type EnumValueDef struct {
	Name, Description string
	Deprecated        bool
	DeprecationReason string
	Value             any
}

EnumValueDef is one value of an Enum. Value is what resolvers get for it and return for it; nil stands for its name.

type Error

type Error struct {
	Message    string         `json:"message"`
	Locations  []Location     `json:"locations,omitempty"`
	Path       []any          `json:"path,omitempty"`
	Extensions map[string]any `json:"extensions,omitempty"`
	Err        error          `json:"-"`
}

Error is an error of a response, as the specification shapes it: a message, where in the document it arose, the path of the field it belongs to, and extensions (extensions.code says what kind it is). Err is its cause, never sent.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap is the cause.

type Field

type Field string

Field names the field a method is, in place of its name in lower camel case: @graphql.Field("displayName") on FullName. A struct field takes a graphql:"name" tag instead.

type FieldDef

type FieldDef struct {
	Name, Description string
	Deprecated        bool
	DeprecationReason string
	Args              []*ArgDef
	Type              TypeDef
	// Resolve gives the field's value from its parent's (p.Source); nil
	// reads key Name of a map[string]any source.
	Resolve func(ctx context.Context, p ResolveParams) (any, error)
	// Guard runs before Resolve: its error makes the field null, with
	// that error at its path.
	Guard func(ctx context.Context) error
	// Trivial marks a field that is cheap to resolve (a struct field's
	// read): it resolves inline, never on a goroutine of its own.
	Trivial bool
	// Cost is the field's weight in a query's complexity; 0 counts 1.
	Cost int
}

FieldDef is a field of an Object or Interface.

type FieldTrace

type FieldTrace struct {
	Path  string // "pets.0.owner"
	Field string // "Pet.owner"
	Start time.Time
	Dur   time.Duration
	Err   bool // it failed: its error is the response's
}

FieldTrace is a field a request resolved.

type Floating

type Floating interface{ ~float32 | ~float64 }

Integer, Floating, Text and Boolish are the Go types IntOf, FloatOf, StringOf and BooleanOf take.

type FormInput

type FormInput[T any] struct {
	Doc    string
	Fields []InputMember[T]
}

FormInput is the input object type a Go struct T is when an argument takes it: its fields, from T's exported fields. An argument's value is checked as a form is before the operation runs (ui.CheckForm): validate: tags, Clean<Field>, Clean.

type IDParams

type IDParams []string

IDParams makes parameters IDs: the attribute AsID gives.

type Input

type Input string

Input names the GraphQL input type a struct is when an argument takes it, in place of its Go name: @graphql.Input("CreateUserInput").

type InputFieldDef

type InputFieldDef struct {
	Name, Description string
	Type              TypeDef
	Default           language.Value
	Deprecated        bool
	DeprecationReason string
}

InputFieldDef is a field of an InputObject.

type InputMember

type InputMember[T any] struct {
	Go   string
	Name string // a graphql:"name" tag's name
	Doc  string
	Type TypeDef
	Set  func(dst *T, v any)
}

InputMember is a field of a FormInput, and how it is set.

type InputObject

type InputObject struct {
	Name, Description string
	Fields            []*InputFieldDef
	// Build makes the value resolvers get from the coerced fields, by
	// name: a field not given and without a default is absent, one given
	// null is nil. Nil gives the map itself.
	Build func(fields map[string]any) (any, error)
}

InputObject is a type of input values with fields: an argument's or a variable's.

func (*InputObject) TypeName

func (t *InputObject) TypeName() string

TypeName is the type's name.

type IntParams

type IntParams []string

IntParams makes parameters Ints: the attribute AsInt gives.

type Integer

type Integer interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
}

Integer, Floating, Text and Boolish are the Go types IntOf, FloatOf, StringOf and BooleanOf take.

type Interface

type Interface struct {
	Name, Description string
	Interfaces        []*Interface
	Fields            []*FieldDef
	// ResolveType names the object a resolved value is; nil asks each
	// implementing object's IsTypeOf.
	ResolveType func(v any) *Object
}

Interface is an abstract type with fields, which objects implement.

func (*Interface) TypeName

func (t *Interface) TypeName() string

TypeName is the type's name.

type Introspection

type Introspection bool

Introspection, given to web.GraphQL, allows or refuses introspection (__schema, __type): allowed in development, refused otherwise, unless given.

type InvalidInput

type InvalidInput struct {
	Arg    string
	Errors []ui.FormError
}

InvalidInput is a struct argument its form checks refused: each error becomes one of the response's, extensions.code INVALID_INPUT.

func (*InvalidInput) Error

func (e *InvalidInput) Error() string

type Limits

type Limits struct {
	// Depth is how deep fields may nest: { a { b } } is 2. Default 10.
	Depth int
	// Complexity bounds a query's cost: each field costs its FieldDef.Cost
	// (1 by default), and what a list field selects counts once per item
	// it may return — its first, last or limit argument when it has one,
	// else DefaultListSize. Default 1000.
	Complexity int
	// DefaultListSize is how many items a list field without a first,
	// last or limit argument counts for. Default 10.
	DefaultListSize int
	// Aliases is how many aliased fields the operation may hold. Default 30.
	Aliases int
	// Fields is how many field selections the operation may hold, its
	// fragments' counted once each. Default 500.
	Fields int
	// Bytes is the largest query document, in bytes. Default 100000. Over
	// HTTP the body may carry up to 1 MiB more, for the variables.
	Bytes int
	// Timeout bounds a request's execution: resolvers are given a context
	// that ends then, and fields not resolved by then fail with
	// extensions.code TIMEOUT. Default 10 seconds.
	Timeout time.Duration
}

Limits bound what one request may ask, checked once the document validates and before anything resolves: each one exceeded is an error of its own (extensions.code DEPTH_LIMIT, COMPLEXITY_LIMIT, ALIAS_LIMIT, FIELD_LIMIT, SIZE_LIMIT), and nothing runs. Introspection's fields (__schema, __type and what they select) count towards none of them, so tools reading the schema aren't refused. A zero value takes the default; a negative one turns the limit off.

type List

type List struct {
	Of TypeDef
	// Items reads a resolved list: its length and its elements; ok is
	// false when v is no list. Nil takes []any.
	Items func(v any) (n int, at func(i int) any, ok bool)
	// Build makes the value resolvers get from a coerced input list; nil
	// gives the []any.
	Build func(items []any) (any, error)
}

List is a list of Of.

func ListOf

func ListOf[E any](of TypeDef) *List

ListOf is a list of E, a Go slice []E, its elements of type of.

func ListOfOption added in v2.14.0

func ListOfOption[E any](of TypeDef) *List

ListOfOption is a list of nullable E, a Go slice []vuka.Option[E]: a None element is a null item, and a null item given is None.

func ListOfPtr added in v2.14.0

func ListOfPtr[E any](of TypeDef) *List

ListOfPtr is a list of nullable E, a Go slice []*E: a nil element is a null item, and a null item given is a nil element.

type Loader

type Loader struct {
	Chunk int
}

Loader makes a function a loader, @graphql.Loader: a function from a request's keys to their values,

@graphql.Loader
func OrdersByUser(ctx context.Context, userIDs []int64, db *DB) (map[int64][]Order, error) { … }

becomes a type of that name, a *LoaderOf[int64, []Order] that field methods and operations take as a dependency and Load from:

func (u User) Orders(ctx context.Context, orders OrdersByUser) ([]Order, error) {
	return orders.Load(ctx, u.ID)
}

The function itself keeps its body under its name lowered (ordersByUser), and NewOrdersByUser(db) makes a loader outside GraphQL. Chunk is how many keys one call of the function takes at most; 0 is DefaultChunk.

type LoaderDef

type LoaderDef struct {
	Go     string       // the type's name
	Type   reflect.Type // the type
	Params []Param      // its function's dependencies, after the context and the keys
	New    func(c *Call) any
}

LoaderDef is a loader type of a package: the type @graphql.Loader made, the dependencies its function takes beside the context and the keys, and how New makes one from their values. A GraphQL request makes one of each type a field or an operation takes, the first time one does.

type LoaderOf

type LoaderOf[K comparable, V any] struct {
	// contains filtered or unexported fields
}

LoaderOf loads values by key in batches: every key a request's fields ask for while it runs, gathered into one call of its function — once each field that can ask for one is waiting, so a batch holds the keys of a whole level of the query — the values kept for the rest of the request.

A key the function's map leaves out loads as V's zero value (nil for a pointer or a slice). The function's error is each waiting Load's, and each field's at its own path.

Outside a GraphQL request — a live page's Mount, a route — there is no level to wait for: Load runs the function for its key at once and LoadMany for its keys together, keeping what they load for the loader's life.

func NewLoader

func NewLoader[K comparable, V any](name string, fetch func(ctx context.Context, keys []K) (map[K]V, error), opts ...Loader) *LoaderOf[K, V]

NewLoader is a loader of fetch's values, named name in the toolbar's traces. Each LoaderOf keeps what it loads: make one per request (the framework does for a GraphQL request), or for whatever lives as long as what it loads may stay as loaded.

func (*LoaderOf[K, V]) Load

func (l *LoaderOf[K, V]) Load(ctx context.Context, key K) (V, error)

Load is key's value: loaded with the other keys the request's fields ask for meanwhile, or kept from an earlier load.

func (*LoaderOf[K, V]) LoadMany

func (l *LoaderOf[K, V]) LoadMany(ctx context.Context, keys []K) ([]V, error)

LoadMany is the values of keys, in their order, loaded together (with the other keys the request asks for meanwhile). The first error is its error.

type Location

type Location struct {
	Line   int `json:"line"`
	Column int `json:"column"`
}

Location is a line and column of the document, 1-based.

type Member

type Member[T any] struct {
	Go   string // the Go field's or method's name
	Name string // a graphql:"name" tag's name; "" for the default
	Doc  string
	Type TypeDef
	// Get reads a struct field.
	Get func(src *T) any
	// Params and Resolve call a method.
	Params  []Param
	Resolve func(ctx context.Context, src *T, c *Call) (any, error)
}

Member is a field of a Struct: a struct field (Get) or a method (Resolve, with its parameters).

type Mutation

type Mutation string

Mutation makes a function an operation of the schema's Mutation type, named as Query names it. Mutations of one request run one after the other, in the order the document writes them.

type NamedType

type NamedType interface {
	TypeDef
	TypeName() string
}

NamedType is a type with a name: *Scalar, *Enum, *Object, *Interface, *Union or *InputObject.

func NamedOf

func NamedOf(t TypeDef) NamedType

NamedOf is the named type t wraps (t itself when it is named); nil for nil.

type Naming

type Naming struct {
	Fields func(goName string) string
}

Naming is an app's convention for the names its schema takes from Go, given to web.GraphQL: Fields names every field and argument whose name isn't written out (a graphql:"name" tag, @graphql.Field, @graphql.Arg), from its Go name. The default is CamelCase.

web.GraphQL("/graphql", graphql.Naming{Fields: graphql.SnakeCase})

type NonNull

type NonNull struct{ Of TypeDef }

NonNull is Of, never null.

type Object

type Object struct {
	Name, Description string
	Interfaces        []*Interface
	Fields            []*FieldDef
	// IsTypeOf reports whether a resolved value is of this type, for an
	// interface or union without a ResolveType; nil leaves it to the
	// abstract type.
	IsTypeOf func(v any) bool
	// Value normalizes a resolved value before its fields resolve (a T
	// into the *T the fields' resolvers take); nil keeps it. A nil result
	// is null.
	Value func(v any) any
	// Paged marks a connection (Connection[T]): in a query's complexity
	// its lists count as many items as the field returning it asks for
	// (its first or last argument).
	Paged bool
}

Object is a type with fields: what queries select from.

func (*Object) TypeName

func (t *Object) TypeName() string

TypeName is the type's name.

type Operation

type Operation struct {
	Go       string // the function's name: the operation's is CamelCase of it unless @graphql.Query names it
	Mutation bool
	Func     any    // the function, whose attributes (vuka.FuncOf) name and gate it
	Doc      string // its doc comment: the field's description
	Params   []Param
	Type     TypeDef // its result's type
	// Resolve calls the function with its parameters' values.
	Resolve func(ctx context.Context, c *Call) (any, error)
}

Operation is a query or mutation: a function of the package.

type OperationInfo

type OperationInfo struct {
	Name string // "" for an anonymous one
	Type string // "query", "mutation" or "subscription"
}

OperationInfo names the operation a request ran.

type OrderedMap

type OrderedMap struct {
	// contains filtered or unexported fields
}

OrderedMap is an object of a response: its keys in the order the query selected them.

func NewOrderedMap

func NewOrderedMap(n int) *OrderedMap

NewOrderedMap is an empty map with room for n keys.

func (*OrderedMap) Get

func (m *OrderedMap) Get(key string) (any, bool)

Get is key's value.

func (*OrderedMap) Keys

func (m *OrderedMap) Keys() []string

Keys are the keys, in order.

func (*OrderedMap) Len

func (m *OrderedMap) Len() int

Len is how many keys it has.

func (*OrderedMap) MarshalJSON

func (m *OrderedMap) MarshalJSON() ([]byte, error)

MarshalJSON writes the object, its keys in order.

func (*OrderedMap) Set

func (m *OrderedMap) Set(key string, v any)

Set sets key to v, adding it at the end when it is new.

type Package

type Package struct {
	Path       string // the package's import path
	Operations []Operation
	Types      []Binding   // Struct, FormInput and Consts values
	Loaders    []LoaderDef // its @graphql.Loader types
}

Package is a package's part of the schema: its operations and the Go types they reach. A type several packages reach is described by each, alike; the first description registered is used.

type Page

type Page struct {
	First  *int
	After  *string
	Last   *int
	Before *string
}

Page is the arguments a connection's field takes: a parameter of type Page is four arguments, first and after for a page read forwards, last and before for one read backwards.

users(first: Int, after: String, last: Int, before: String): UserConnection!

type PageInfo

type PageInfo struct {
	HasNextPage     bool
	HasPreviousPage bool
	StartCursor     *string
	EndCursor       *string
}

PageInfo is what lies around a Connection's page: whether there are rows past it either way, and the cursors of its first and last edges (null for an empty page).

HasPreviousPage, for a page read forwards (first), is whether it starts after a cursor; HasNextPage, for one read backwards (last), whether it ends before one — as the specification allows, neither is a query of its own.

type Pageable

type Pageable[T any] interface {
	CursorPage(ctx context.Context, after, before string, first, last int) (rows []T, cursors []string, more bool, err error)
	Count(ctx context.Context) (int64, error)
}

Pageable is what Paginate pages: an orm query set (orm.QuerySet), or anything reading a page by cursors as it does — the first rows after the row of cursor after, or the last before the row of cursor before, both bounding the page; each row's cursor; whether rows go on past the page (after it reading forwards, before it reading backwards) — and counting its rows.

func Slice

func Slice[T any](rows []T) Pageable[T]

Slice is a Pageable over rows in memory: cursors are positions in it.

type PanicError

type PanicError struct {
	Field string // "Query.users"
	Value any
	Stack []byte
}

PanicError is a resolver's panic, given to Config.Present as the field's error: Value is what it panicked with, Stack where.

func (*PanicError) Error

func (e *PanicError) Error() string

type Param

type Param struct {
	Name string // the Go parameter's name: the argument's default name
	// Arg is the argument's name as @graphql.Arg before the parameter
	// writes it, which Naming doesn't change; "" for the default.
	Arg  string
	Type TypeDef
	Dep  reflect.Type
}

Param is a parameter of an operation's function or a field's method, the receiver excluded: the context (Type and Dep nil), an argument (Type its type), or a dependency the app provides (Dep its type).

type Query

type Query string

Query makes a function an operation of the schema's Query type, named after the function in lower camel case (Users is users), or as given: @graphql.Query("usersList").

@graphql.Query
func Users(ctx context.Context, first int, db *DB) ([]User, error) { … }

type Request

type Request struct {
	Query         string
	OperationName string
	Variables     map[string]any
	Extensions    map[string]any
}

Request is a GraphQL request: the document, which of its operations to run (needed when it has several), the variables' values (JSON, decoded with UseNumber) and extensions.

type ResolveInfo

type ResolveInfo struct {
	FieldName  string
	Path       []any // response keys and list indexes from the root
	ParentType *Object
	ReturnType TypeDef
	Operation  *language.OperationDefinition
	Schema     *Schema
	Variables  map[string]any
}

ResolveInfo describes the field being resolved.

type ResolveParams

type ResolveParams struct {
	Source any
	Args   map[string]any
	Info   *ResolveInfo
}

ResolveParams is what a resolver is given: the parent's value, the field's arguments (coerced, by name; an argument not given and without a default is absent) and where it is.

type Response

type Response struct {
	Data       *OrderedMap
	Errors     []*Error
	Extensions map[string]any
	Executed   bool
}

Response is the result of a request. Executed says execution started: the response then has data, null when Data is nil; a request refused before (a document that doesn't parse or validate, variables of the wrong type, a limit) has errors only.

func (*Response) MarshalJSON

func (r *Response) MarshalJSON() ([]byte, error)

MarshalJSON writes the response as the specification shapes it: "errors" first when there are any, then "data" (when executed) and "extensions".

type Scalar

type Scalar struct {
	Name, Description string
	SpecifiedByURL    string
	// Serialize turns a resolved value into the result's value: a string,
	// a bool, a number, nil. Its error is the field's.
	Serialize func(v any) (any, error)
	// ParseValue turns a variable's value — JSON, decoded with UseNumber:
	// json.Number, string, bool, nil, []any or map[string]any — into the
	// value resolvers are given.
	ParseValue func(v any) (any, error)
	// ParseLiteral turns a literal written in the document into the value
	// resolvers are given; nil has the literal read as JSON would be (an
	// enum value as its name) and given to ParseValue.
	ParseLiteral func(v language.Value) (any, error)
}

Scalar is a leaf type: Int, String, a custom scalar such as DateTime.

Several Scalars may share a name. They are one type of the schema, each converting the values where it is used — a Go named type's codec beside the built-in it shows as: introspection and the SDL show the first one the schema meets, a built-in's own when the name is a built-in's.

func BooleanOf

func BooleanOf[T Boolish]() *Scalar

BooleanOf is Boolean for the Go type T.

func FloatOf

func FloatOf[T Floating]() *Scalar

FloatOf is Float for the Go type T.

func IDOf

func IDOf[T Text]() *Scalar

IDOf is ID for a Go string type T.

func IntIDOf

func IntIDOf[T Integer]() *Scalar

IntIDOf is ID for a Go integer type T: written as a string of digits, read from one (or from an integer).

func IntOf

func IntOf[T Integer]() *Scalar

IntOf is Int for the Go integer type T: resolvers return T, arguments arrive as T. A value out of T's range is an error.

func StringOf

func StringOf[T Text]() *Scalar

StringOf is String for the Go type T.

func (*Scalar) TypeName

func (t *Scalar) TypeName() string

TypeName is the type's name.

type Schema

type Schema struct {
	// contains filtered or unexported fields
}

Schema is a checked schema, ready to execute operations against.

func NewSchema

func NewSchema(c SchemaConfig) (*Schema, error)

NewSchema checks c as the specification's type system requires — names, unique names, fields and their types in the right positions, interfaces implemented as declared, union members, enum values, input objects without cycles of non-null fields, default values of their types — and builds the schema. Its error lists every problem.

func ParseSchema

func ParseSchema(sdl string) (*Schema, error)

ParseSchema builds a schema from its SDL, without resolvers: for comparing a schema with an earlier one (Diff), or for validating documents against it. Its custom scalars take and give values as they come. Type extensions are merged into the types they extend.

func (*Schema) Description

func (s *Schema) Description() string

Description is the schema's description.

func (*Schema) Directive

func (s *Schema) Directive(name string) *Directive

Directive is the directive of that name; nil when the schema has none.

func (*Schema) Directives

func (s *Schema) Directives() []*Directive

Directives are the schema's directives, the built-in ones first.

func (*Schema) FieldOf

func (s *Schema) FieldOf(t NamedType, name string) *FieldDef

FieldOf is the field name of an object or interface type; nil when it has none.

func (*Schema) IsPossibleType

func (s *Schema) IsPossibleType(abstract NamedType, obj *Object) bool

IsPossibleType reports whether obj is one of the types abstract may be.

func (*Schema) MutationType

func (s *Schema) MutationType() *Object

MutationType is the mutation root; nil when the schema has none.

func (*Schema) PossibleTypes

func (s *Schema) PossibleTypes(t NamedType) []*Object

PossibleTypes are the objects an abstract type may be: an interface's implementations, a union's members.

func (*Schema) QueryType

func (s *Schema) QueryType() *Object

QueryType is the query root.

func (*Schema) SDL

func (s *Schema) SDL() string

SDL is the schema in the schema definition language: a schema block only when the roots aren't named Query, Mutation and Subscription (or the schema has a description), the directives beyond the built-in ones, then the root types (query, mutation, subscription) and every other type sorted by name; fields, arguments and values in their declared order. Built-in scalars and directives and the introspection types are left out.

func (*Schema) SubscriptionType

func (s *Schema) SubscriptionType() *Object

SubscriptionType is the subscription root; nil when the schema has none.

func (*Schema) Type

func (s *Schema) Type(name string) NamedType

Type is the schema's type of that name; nil when it has none.

func (*Schema) Types

func (s *Schema) Types() []NamedType

Types are the schema's types, sorted by name, built-in and introspection types included.

func (*Schema) Validate

func (s *Schema) Validate(doc *language.Document, introspection bool) []*Error

Validate applies the specification's validation rules (section 5) to an executable document: every error found, each at its locations, with extensions.code GRAPHQL_VALIDATION_FAILED. introspection false refuses __schema and __type as well.

type SchemaConfig

type SchemaConfig struct {
	Query, Mutation, Subscription *Object
	Types                         []NamedType
	Directives                    []*Directive
	Description                   string
}

SchemaConfig is a schema's roots and anything else it holds: types no root reaches, and directives beyond the built-in ones.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server executes requests against a schema.

func NewServer

func NewServer(c Config) (*Server, error)

NewServer is a server for c.Schema.

func (*Server) Check added in v2.9.0

func (s *Server) Check(req Request) []*Error

Check is what Execute would refuse req for, without running it: its syntax, the schema's rules, then — for the operation it names, or its only one — its variables' values and the limits. Nothing is cached. The development toolbar's GraphiQL panel checks its query as it is typed.

func (*Server) Execute

func (s *Server) Execute(ctx context.Context, req Request) *Response

Execute runs a request: parse (or the cache), validation, the limits, the variables' coercion, then the operation. A request refused before execution has errors only (Response.Executed false).

func (*Server) Limits

func (s *Server) Limits() Limits

Limits are the limits the server applies, defaults filled in.

func (*Server) Schema

func (s *Server) Schema() *Schema

Schema is the schema the server executes against.

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP answers a GraphQL request over HTTP, as the GraphQL-over-HTTP specification has it:

  • GET carries query, operationName, variables and extensions (the last two as JSON) in the URL, and runs queries only: a mutation answers 405 with Allow: POST.
  • POST carries them as a JSON object, Content-Type application/json; another content type answers 415, a body beyond Limits.Bytes plus 1 MiB 413, one that isn't such an object 400.
  • The response is application/graphql-response+json when the Accept header prefers it, application/json when it prefers that, names */*, or is missing; 406 when it accepts neither.
  • An application/json response is 200 for any well-formed request, its errors in the body. An application/graphql-response+json one is 400 when the request was refused before execution (it doesn't parse or validate, its variables or operation name are wrong, a limit) and 200 once execution started.
  • Other methods answer 405.

type StringParams

type StringParams []string

StringParams keeps parameters Strings: the attribute AsString gives.

type Struct

type Struct[T any] struct {
	Doc    string
	Fields []Member[T]
}

Struct is the object type a Go struct T is: its fields, from T's exported fields and methods.

type Subscription

type Subscription string

Subscription is reserved for subscription operations, which a later version serves; the compiler refuses it for now.

type Text

type Text interface{ ~string }

Integer, Floating, Text and Boolish are the Go types IntOf, FloatOf, StringOf and BooleanOf take.

type Trace

type Trace struct {
	Field func(FieldTrace)
	Batch func(BatchTrace)
	// Context is the context a field's resolver (or a batch) runs with,
	// given its path and what it is ("Pet.owner"; a batch: "" and "loader
	// OrdersByUser"): what the resolver records under it — the SQL it runs
	// — is then the field's.
	Context func(ctx context.Context, path, field string) context.Context
}

Trace is told what a request resolves, for development tools (the toolbar's GraphQL panel): each field with a resolver of its own (struct fields read in place aren't) and each batch a loader ran, as they end. Config.Trace gives one per request; nil fields are skipped.

type Type

type Type string

Type names the GraphQL type a Go type is, in place of its Go name: @graphql.Type("Person") on type User. On a type an input uses, it names the input type too unless Input does.

type TypeDef

type TypeDef interface {
	// contains filtered or unexported methods
}

TypeDef is a type of a schema: *Scalar, *Enum, *Object, *Interface, *Union, *InputObject (the named types), *List or *NonNull.

var PageArgs TypeDef = pageArgs{}

PageArgs is the type of a Param of type Page: the arguments first, after, last and before, given to the function as a Page.

func EnumOf

func EnumOf[T comparable]() TypeDef

EnumOf is the enum type of T (its Consts).

func InputOf

func InputOf[T any]() TypeDef

InputOf is the input object type of struct T (its FormInput).

func ObjectOf

func ObjectOf[T any]() TypeDef

ObjectOf is the object type of struct T (its Struct).

func TextScalar

func TextScalar[T any, P interface {
	*T
	encoding.TextUnmarshaler
}]() TypeDef

TextScalar is the custom scalar of a Go type T that reads and writes itself as text (encoding.TextMarshaler, encoding.TextUnmarshaler on *T): named after T unless @graphql.Type names it.

type Union

type Union struct {
	Name, Description string
	Types             []*Object
	// ResolveType names the object a resolved value is; nil asks each
	// member's IsTypeOf.
	ResolveType func(v any) *Object
}

Union is an abstract type: one of its object types.

func (*Union) TypeName

func (t *Union) TypeName() string

TypeName is the type's name.

type Value

type Value string

Value names the enum value a constant is, in place of its name in SCREAMING_SNAKE case without its type's name: @graphql.Value("ENABLED") on StatusActive.

Directories

Path Synopsis
Package language reads and writes GraphQL documents: a lexer and a parser for executable documents (operations and fragments) and type-system documents (schema definitions, the SDL), the syntax tree both produce, and a printer.
Package language reads and writes GraphQL documents: a lexer and a parser for executable documents (operations and fragments) and type-system documents (schema definitions, the SDL), the syntax tree both produce, and a printer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL