server

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Aug 4, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package server @notice Mounts a gqlgen handler on Fiber v3, correctly.

@dev "Correctly" is doing real work in that sentence. Every line of Mount exists because leaving it out fails silently: r.All rather than r.Post (or browser clients 405 on the CORS preflight, with nothing in the log), SetQueryCache (or every request re-parses and re-validates), extension.Introspection (or the playground's docs pane is blind).

This package cannot replace gqlgen codegen, and no package could. gqlgen generates code into your module: generated.NewExecutableSchema is a symbol only your own `go tool gqlgen generate` run produces, from your own schema.graphqls. So you still own gqlgen.yml, schema.graphqls, graph/resolver.go and the codegen step — see docs/gqlgen-contract.md, because getting it wrong produces runtime panics that `go build` does not catch.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Mount

func Mount(r fiber.Router, cfg Config)

Mount @notice Registers the same routes on a router you already have — an existing app, or a group.

@dev cfg.Fiber is ignored here: the app already exists, so its configuration is not this function's to set.

@param r a *fiber.App or the result of app.Group(prefix) @param cfg the server configuration; only Schema is required

func New

func New(cfg Config) *fiber.App

New @notice Builds a *fiber.App with the GraphQL endpoint and playground mounted.

@param cfg the server configuration; only Schema is required @return *fiber.App an app ready for Listen, with cfg.Fiber applied

Types

type Config

type Config struct {
	// Schema @notice Your generated executable schema, e.g.
	//   generated.NewExecutableSchema(generated.Config{Resolvers: &graph.Resolver{DB: db}})
	Schema graphql.ExecutableSchema

	// Endpoint @notice The GraphQL path. Default "/graphql".
	Endpoint string

	// Playground @notice The GraphiQL path. Default "/".
	//
	// @dev Fiber matches it exactly, where net/http's Handle("/", ...) was a prefix match — an
	// unknown path is a plain 404 here.
	Playground string

	// DisablePlayground @notice Turns GraphiQL off entirely. Do this in production.
	//
	// @dev A separate bool rather than Playground == "": the zero Config must be the good
	// configuration, so "" has to mean "unset", which leaves no spelling for "off".
	DisablePlayground bool

	// PlaygroundTitle @notice The browser tab title. Default "graphql".
	PlaygroundTitle string

	// DisableIntrospection @notice Turns schema introspection off. Do this in production.
	//
	// @dev Zero value is "on", as with the playground — introspection is what makes the docs
	// pane work, so the zero Config has to keep it.
	//
	// This is defence in depth and a smaller attack surface; it is not confidentiality, and it
	// does not hide your field names. gqlparser's validator appends "Did you mean ...?" to
	// validation errors (gqlparser/validator/core/helpers.go), and PresentError passes
	// validation errors through by design, so a caller who guesses "nam" still learns there is
	// a "name". Do not treat it as a substitute for authorization.
	DisableIntrospection bool

	// RequestTimeout @notice Deadline for the whole request, propagated into the resolver
	// context. Default 15s. Negative disables it.
	//
	// @dev Zero means "unset", as with QueryCache. This is the only bound a query gets:
	// go-pg sets no ReadTimeout or WriteTimeout default, pg.ParseURL rejects statement_timeout
	// in the DSN, and nothing else in the stack imposes one. What makes a context deadline
	// sufficient is that go-pg honours it three ways — the pool wait selects on ctx.Done()
	// (internal/pool/pool.go waitTurn), the socket deadline is ctx.Deadline() verbatim when no
	// ReadTimeout is set (internal/pool/conn.go deadline), and ctx.Done() triggers a real
	// Postgres CancelRequest against the running backend (base.go withConn).
	//
	// 15s is deliberately under go-pg's own 30s PoolTimeout default (options.go init): below
	// it, a saturated pool sheds deterministic 408s; at or above it, the failure mode is a coin
	// flip between ErrPoolTimeout and the timeout. That CancelRequest is best-effort — it dials
	// a second connection and only logs a failure — so a server-authoritative bound still wants
	// statement_timeout via pg.Options.OnConnect. See SECURITY.md.
	RequestTimeout time.Duration

	// QueryCache @notice The parsed-query LRU size. Default 1000. Negative disables it.
	//
	// @dev Zero means "unset", not "off", because a zero-valued Config must not be the
	// pathological one: handler.New starts at graphql.NoCache, and with no cache every
	// request re-parses and re-validates the whole query document. There is no good reason to
	// pass a negative here.
	QueryCache int

	// ComplexityLimit @notice Caps query complexity. Default 1000. Negative disables it.
	//
	// @dev Zero means "unset", as with QueryCache.
	ComplexityLimit int

	// ErrorPresenter @notice The error contract. Default [luimaerr.PresentError].
	ErrorPresenter graphql.ErrorPresenterFunc

	// HTTPMiddleware @notice net/http middleware wrapped around the gqlgen handler, outermost
	// first.
	//
	// @dev The one layer that has all three of: the real *http.Request with its cookies
	// parsed, an http.ResponseWriter whose headers survive back through the adaptor —
	// Set-Cookie included, because fasthttp's Header.Add routes it into the dedicated cookie
	// list rather than the generic map — and r.WithContext, which every resolver sees as its
	// own ctx, typed. Fiber middleware on the mounted group has none of the net/http shapes,
	// so anything written as func(http.Handler) http.Handler — request logging, tracing,
	// tenancy, rate limiting, a session layer — mounts here unchanged and stays portable to
	// chi, echo or plain net/http.
	//
	// The chain runs inside withFiberContext, so each middleware already sees the request
	// context that the resolvers will see: the RequestTimeout deadline is set, c.SetContext
	// values are attached, and whatever the middleware adds rides the same context down.
	// TestHTTPMiddleware pins all three properties.
	HTTPMiddleware []func(http.Handler) http.Handler

	// Configure @notice Runs against the built gqlgen server immediately before it is mounted.
	//
	// @dev One escape hatch rather than a field per knob: srv.Use, AroundOperations,
	// SetRecoverFunc, SetParserTokenLimit and SetDisableSuggestion are all reachable through
	// it, and a new gqlgen extension point needs no change here. Without it, srv is a local
	// that never escapes Mount, and a consumer wanting any of those has to abandon Mount —
	// which is the whole library.
	//
	// It runs after every default above — transports, query cache, introspection, complexity,
	// presenter — so it can override them rather than be silently overridden by them.
	Configure func(*handler.Server)

	// Fiber @notice Passed through to fiber.New. Ignored by Mount.
	//
	// @dev Fiber's BodyLimit defaults to 4 MB where net/http had none — irrelevant to
	// queries, and the thing to raise here the day you add the multipart transport.
	//
	// Setting Fiber.ErrorHandler does nothing useful for resolver errors: the adaptor always
	// returns nil, and so does the timeout middleware on both its normal and its timed-out
	// path, so no resolver error ever becomes a Fiber error. ErrorPresenter is the only error
	// contract there is.
	Fiber fiber.Config
}

Config @notice Assembles the server.

@dev Only Schema is required; every zero value has a working default, so Config{Schema: ...} is the good configuration rather than the pathological one.

Jump to

Keyboard shortcuts

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