skip to content

Transports & Interception

GraphQL runs over an HTTP endpoint, with WebSocket or RSocket for subscriptions, GraphiQL for exploration, and interceptors carrying headers and security context into the execution. Interviewers ask how authentication reaches a resolver, and interception is the answer.

part ofSpring for GraphQLoverview, primer and where to startread it →
on this pageshow

questions

5

How does Spring for GraphQL expose the GraphQL API over HTTP, and how do you enable the GraphiQL UI for exploring it?

level: juniorimportance: must knowfreq 45%

answer

  1. single POST /graphql, body carries the query
  2. spring.graphql.path relocates it
  3. GraphiQL off by default -> enabled=true
  4. /graphiql playground is dev-only
  5. 200 OK + errors[] envelope

basics

~10 s

Spring for GraphQL serves a single endpoint at POST /graphql. GraphiQL is a built-in in-browser query playground, disabled by default; enable it with spring.graphql.graphiql.enabled=true, then open /graphiql.

solid answer

~40 s

The spring-boot-starter-graphql auto-configuration maps one HTTP endpoint, POST /graphql (path configurable via spring.graphql.path). Clients send a JSON body with query, optional operationName, and variables; the response is a JSON envelope with data and errors. GraphQL uses one URL for everything — the operation type is in the request body, not the path or verb. GraphiQL is an official in-browser IDE (autocomplete, docs explorer, run queries) bundled with the starter but off by default. Turn it on with spring.graphql.graphiql.enabled=true and browse to /graphiql (path set by spring.graphql.graphiql.path). You typically enable it only in dev/staging because it exposes your full schema and lets anyone run queries. Schema files live under src/main/resources/graphql/*.graphqls by default.

code

java · 16 lines
java
// application.properties
// spring.graphql.path=/graphql            (default)
// spring.graphql.graphiql.enabled=true    (turn on the in-browser IDE)
// spring.graphql.graphiql.path=/graphiql  (default)

@Controller
class BookController {

    @QueryMapping
    public Book book(@Argument String id) {   // resolves the `book(id: ID!)` field
        return repository.findById(id);
    }
}
// Schema at src/main/resources/graphql/schema.graphqls:
//   type Query { book(id: ID!): Book }
//   type Book  { id: ID!, title: String }

go deeper

for a junior

Know it's one POST /graphql endpoint and that GraphiQL needs spring.graphql.graphiql.enabled=true.

for a middle

Explain the JSON envelope, the 200-with-errors behavior, and why GraphiQL should be dev-only.

for a senior

Discuss introspection hardening, content-type negotiation, and gating the playground behind profiles/auth.

for a principal

Weigh GraphQL's single-endpoint model against REST for caching, observability, and gateway routing decisions.

**What Spring for GraphQL is.** Spring for GraphQL is the Spring integration on top of the graphql-java engine. Adding `spring-boot-starter-graphql` (usually alongside `spring-boot-starter-web` or `-webflux`) auto-configures a runnable GraphQL server. **The HTTP transport.** Unlike REST, GraphQL exposes a *single* endpoint. By default it is **`POST /graphql`** (change with the property `spring.graphql.path`). The HTTP method and URL never vary per operation — *what* you want is expressed entirely in the request body: ```json { "query": "query($id: ID!){ book(id:$id){ title } }", "operationName": null, "variables": { "id": "42" } } ``` The server always responds `200 OK` (even for GraphQL-level errors) with a JSON envelope: ```json { "data": { "book": { "title": "..." } }, "errors": [ ] } ``` `errors` is populated for validation or data-fetching failures; `data` and `errors` can coexist (partial results). Spring also supports **GET /graphql** for queries when explicitly used, and negotiates content type `application/graphql-response+json`. **Where the schema comes from.** By default Spring loads schema definition files matching `classpath:graphql/**/*.graphqls`. `@Controller` beans with `@QueryMapping`, `@MutationMapping`, `@SchemaMapping`, and `@SubscriptionMapping` methods supply the data fetchers. **GraphiQL.** GraphiQL (note the *i* — it is a specific open-source project, not just "graphical") is an in-browser IDE: schema documentation explorer, field autocomplete, and a console to run queries against your endpoint. The starter bundles a copy but it is **disabled by default**. Enable it: ```properties spring.graphql.graphiql.enabled=true # optional, defaults to /graphiql spring.graphql.graphiql.path=/graphiql ``` Then open `http://localhost:8080/graphiql`. **Gotchas / when-to-use.** - GraphiQL exposes your **entire schema** and lets any visitor run operations, so gate it: enable only in dev/staging, or put it behind auth. Do not ship it wide-open in production. - Introspection (the query GraphiQL uses to learn the schema) is on by default; you can disable it with `spring.graphql.schema.introspection.enabled=false` to harden production. - Because everything is one POST, standard REST tooling (per-path caching, HTTP verbs mapping to CRUD) does not apply — caching/observability are done differently. - 200-with-errors surprises people used to REST status codes; check the `errors` array, not the HTTP status, for GraphQL failures.

  • Why does a GraphQL error still return HTTP 200?
    The GraphQL-over-HTTP convention puts operation-level errors in the response body's `errors` array rather than in the HTTP status, since one request can produce partial data plus errors. Transport-level failures (malformed JSON, unsupported media type) can still yield 4xx.
  • How would you keep GraphiQL out of production?
    Bind spring.graphql.graphiql.enabled to a profile (e.g. set true only in application-dev.properties), or leave it false and additionally disable introspection with spring.graphql.schema.introspection.enabled=false to prevent schema discovery.

saying these in an interview costs you the question

  • Thinking each GraphQL operation has its own URL/path like REST
  • Believing GraphiQL is enabled by default
  • Assuming GraphQL errors come back as HTTP 4xx/5xx
  • Confusing GraphiQL (the IDE) with the /graphql endpoint itself

context

open as a page

What is WebGraphQlInterceptor and how do you use it to read an incoming HTTP header and make its value available to a data fetcher?

level: seniorimportance: must knowfreq 34%

basics

~20 s

WebGraphQlInterceptor is a bean that wraps every web GraphQL request. In intercept(request, chain) you read request.getHeaders(), put a value into the GraphQLContext (via request.configureExecutionInput or an attribute), then a data fetcher reads it with @ContextValue.

open as a page

Which transports does Spring for GraphQL support for subscriptions, and why can't a plain HTTP POST /graphql handle them the way it handles queries and mutations?

level: middleimportance: should knowfreq 35%

basics

~10 s

Subscriptions stream many results over time, so they need a persistent connection: WebSocket (the graphql-transport-ws protocol) or RSocket. A single request/response HTTP POST returns once and closes, so it can't push an ongoing stream.

open as a page

How do you enforce authentication/authorization in a Spring for GraphQL app, and how does the Spring Security context reach a data fetcher that may run on a different thread?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Authenticate at the /graphql endpoint with Spring Security's normal HTTP filter chain. Authorize per field with @PreAuthorize on controller methods. Spring for GraphQL propagates the SecurityContext to data fetchers via context propagation, so method security still works even off-thread.

open as a page

You need cross-cutting logic (correlation IDs, response headers, auth context) applied consistently across HTTP, WebSocket, and RSocket GraphQL transports. How does Spring for GraphQL's interception model let you do this, and what are the ordering and transport-specific trade-offs?

level: principalimportance: nice to knowfreq 15%

basics

~20 s

Use WebGraphQlInterceptor for HTTP and WebSocket, and RSocketGraphQlInterceptor for RSocket. Each is a chained filter around execution where you read/write context and headers. Control order with Ordered/@Order; put shared logic in the GraphQLContext so all transports converge.

open as a page