grx

GraphQL server essentials

Answers newcomers’ top questions - what GraphQL is, how schemas and resolvers work, and where grx fits - before you touch a router integration.

If you are new to GraphQL or spinning up your first backend, this page collects the questions people search for most (“what is X?”, “do I need Y?”) and points you to grx-specific guides afterward. Prefer hands-on steps first? Run your first server and treat this doc as backup reading.

Official background when you want the spec voice: GraphQL Learn and FAQ.


What is GraphQL - and how is it different from REST?

GraphQL is a specification for querying and changing data over the network using a single typed API layer. Clients send a single document (query, mutation, or subscription operation) describing the shape of data they want; the server returns JSON that mirrors that shape.

Compared to typical REST:

TopicREST (often)GraphQL
RequestsMany endpoints (/users, /users/1/posts, …)Usually one HTTP URL; operation type encoded in the body
PayloadFixed server-defined responsesClients choose fields - less over-fetching
Versioning/v2 prefixes or duplicate routesPrefer additive schema changes

GraphQL says nothing about your database - you implement how data is loaded (SQL, RPCs, other HTTP APIs).

In grx: you expose an http.Handler (see Routers & transports and Get started).


What do I need to actually build a GraphQL server?

Every conforming GraphQL server needs:

  1. A schema - the typed contract your clients can legally request (Query, and optionally Mutation / Subscription, plus object types and scalars).
  2. Resolution logic - code that fulfills each requested field when a document runs (resolvers, expressed in Go methods in grx).
  3. A transport - HTTP (POST with JSON body is the usual), and optionally WebSocket/SSE for subscriptions.

Missing any of those, clients cannot reliably talk to your service.


What is a schema - and do I write SDL by hand?

A schema is the authoritative description of types and fields GraphQL exposes. Teams often describe it using SDL (Schema Definition Language), the text form you see in tutorials (type Query { hello: String }).

Common workflow labels:

StyleRoughly
SDL / schema‑firstWrite .graphql, then attach resolvers.
Code‑firstDefine types and fields in programming language primitives; SDL can be emitted or inferred.

Either way the runtime artifact at execute time is the same pairing: validated schema graph + resolver functions.

In grx: schemas are authored from exported Go structs and methods, with gql struct tags for wire naming and optionality - not a handwritten SDL drift problem. Concepts: Define your schema. Clients still see a normal GraphQL API (including introspection when enabled).


What are Query, Mutation, and Subscription?

These are GraphQL operation types mapped to Query, Mutation, and Subscription root types in the schema:

OperationTypical useWrites data?
QueryRead tree-shaped data idempotentlyNo
MutationCreate/update/delete workflowsUsually yes
SubscriptionLong-lived stream of server-pushed payloadsDepends on domain

Naming note: query lowercase refers to HTTP / operation kind; type Query is the schema root for read operations - easy to confuse in docs.

In grx: attach structs to schema.Config roots and implement methods - see Get started, Queries and mutations, Realtime subscriptions.


What is a resolver?

A resolver is the logic that yields the runtime value for a single schema field. Execution walks the AST of the client operation; for each field the engine calls parent type → field resolution (conceptually asynchronous).

From the GraphQL execution overview:

  • Execution begins at Query, Mutation, or Subscription roots.
  • Resolvers commonly receive context, args, parent (object value), plus metadata - grx aligns with context.Context and typed structs for arguments.

Thin resolvers delegating to a service/store layer scales better than fat data access sprinkled everywhere.


Does GraphQL call my SQL database automatically?

No. GraphQL resolves graphs of fields. You connect to Postgres, DynamoDB, gRPC backends, caches, whatever your resolvers orchestrate - the spec deliberately stays datasource-agnostic (see GraphQL FAQ).

Patterns that help:

ConcernWhat teams do
MaintainabilityServices/repositories invoked from resolver methods - not raw SQL sprinkled ad hoc in every resolver.
N+1 queriesOne query loads a list, then one DB round-trip per row for nested relation fields - pain at scale - see next section.
Per-request scopeBatch loaders, cache keys, tracing IDs - normally constructed per HTTP request, not globals.

In Go: idiomatic layering + optional DataLoader-like batching libs for your datastore; wire identity via context (Authentication & authorization).


What is the “N+1 problem”?

Classical symptom: users { posts { title } } runs 1 + N database queries because each user’s posts field triggers its own resolver and DB hit.

Mitigations backend teams rely on:

  • Batch loaders keyed per request.
  • Smart JOINs, preload, or dataload patterns in repositories.
  • Observability over resolver timings and SQL audit - catch explosions early.

Nothing in vanilla GraphQL “magically batches” datastore calls - you design for it once nested fields become hot paths.


What is introspection - and should it stay on in production?

Introspection lets clients query the schema itself (__schema, types, fields, directives) - how GraphiQL discovers your surface.

Benefits:

  • Excellent DX locally and in staging tools.
  • Codegen pipelines (clients, mocks).

Operational tension:

Public internet facing APIs sometimes disable introspection, add persisted queries, or gate playground traffic.

Decision factors: attacker reconnaissance versus internal convenience. Tune staging vs production.

With grx - disable introspection: call grx.WithDisableIntrospection(). Related hardening reads: Security (masking, authorizers), Introspection (playground, __schema), Limits (payloads, timeouts, persisted‑query modes) - or the overview hub.


How do authentication and authorization work?

GraphQL is usually one URL, so Authorization, cookies, mTLS identity, etc., land in transport middleware. Your resolvers - or authorizer hooks - read trusted identity off context.

Rough split:

LayerResponsibility
Authenticate HTTPParse tokens, rotate sessions before Execute.
Authorize GraphQL operations or fieldsReject forbidden shapes or fields after identity is known

Deep dive: Authentication & authorization.


How do partial success and errors work?

GraphQL distinguishes transport errors (4xx, 5xx) from GraphQL errors in the execution response while still returning data for whichever branches succeeded. Design mutation payloads (payload/errors union patterns) consciously so clients behave predictably - the spec describes error locations and formatting.

Treat resolver error returns as intentional API surface: log, categorize, expose opaque client messages externally when security matters.


One schema or many - “federation”?

For clients, one stable graph avoids orchestrating multiple subgraphs manually. Organizations either:

  • Maintain a single monolith schema, or
  • Compose schemas across services (federation) - more moving parts than most small teams need initially.

Start monolithic until team boundaries force otherwise.


Where to go next in grx

GoalNext page
What ships in the boxWhat grx is
Run Hello World + routersGet started
Structs ↔ GraphQL modelingDefine your schema
Multipart file mutationsFile uploads
Persisted / trusted opsPersisted queries (APQ)
CRUD-ish API wiringQueries and mutations
Realtime streamsSubscriptions
Middleware + guardsAuthentication & authorization
Ops hardening (introspection off, payloads, masking)Security, Introspection, Limits
Internal mental modelArchitecture
Migrate from older Go serversMigrate

You do not have to memorize the spec upfront - bookmark this page when someone on your team asks “wait, why is GraphQL …?” mid-sprint.

Edit this page on GitHub

Last updated on

On this page