skip to content

What is a schema-derived GraphQL mock server, and where do its field values come from?

level: juniorimportance: must knowfreq 52%

answer

  1. A server with nothing behind it
  2. The schema is the only input
  3. Each field's declared type decides
  4. Enums pick a member, lists get two
  5. Custom scalars and unions need help

basics

~20 s

A schema-derived mock is a GraphQL server built from the schema alone, with no resolvers behind it. Every field returns a value invented from its declared type - a placeholder string, a number, an enum member, a short list.

solid answer

~50 s

A schema-derived mock takes the schema - SDL text, or an introspection result pulled from a running server - and stands up an endpoint that answers any valid document without a single resolver being written. Values come from each field's **declared type**, never from data: a `String` yields a fixed placeholder, `Int` and `Float` yield numbers, `Boolean` a boolean, `ID` a generated identifier, an enum one of the members the schema declares, and a list field a short fixed-length list. Nesting works because the mock recurses through object types until it reaches leaves. What the schema does not determine, a mock cannot invent - a custom scalar has no derivable value space, and an interface or union field needs a concrete type chosen - so those need explicit overrides. The payoff is that a client team can render screens the day the schema is agreed.

code

graphql · 29 lines
graphql
scalar Money

type Query {
  claim(id: ID!): Claim
}

type Claim {
  id: ID!
  status: ClaimStatus!
  settlementAmount: Money
  adjusterNotes: String
  documents: [ClaimDocument!]!
}

type ClaimDocument {
  id: ID!
  filename: String!
}

enum ClaimStatus { RECEIVED, IN_REVIEW, SETTLED, DENIED }

query ClaimDetail {
  claim(id: "c-1") {
    id
    status
    adjusterNotes
    documents { id filename }
  }
}

go deeper

for a junior

Be ready to say what a mock is built from and what it is not: the schema alone, no resolvers, no data. Knowing that every value is decided by the field's declared type is the whole entry ticket here.

for a middle

Explain the derivation rule per kind of type - scalars, enums, objects, lists - and name the two places it breaks down, custom scalars and abstract types, where the schema simply does not carry enough information to invent a value.

for a senior

Show where you would let a mock run and where you stop trusting it. It proves documents validate and screens render; it proves nothing about who may read a field, how long the real one takes, or whether the values it paired together could co-occur.

for a principal

Own the policy around the artifact: who publishes the schema the mocks are built from, how often it is refreshed from what is deployed, and whether a mock-backed suite is ever allowed to be the only gate before a client ships.

## The idea A GraphQL schema is a complete, machine-readable description of every type, every field, and every field's type. That is unusually strong material to hand a program. Given the schema alone, and nothing about the business, a tool can already decide what **shape** a valid answer to any document must have. A schema-derived mock exploits exactly that: you hand a mocking layer the schema - as SDL text, or as the introspection result pulled from a deployed server - and it serves an endpoint that parses documents, validates them, and answers them, with no resolvers and no data behind it. Take one slice of an insurance claims graph: ```graphql scalar Money type Claim { id: ID! status: ClaimStatus! settlementAmount: Money adjusterNotes: String documents: [ClaimDocument!]! } enum ClaimStatus { RECEIVED, IN_REVIEW, SETTLED, DENIED } ``` Ask a mock built from this for `claim(id: "c-1") { id status adjusterNotes documents { id } }` and a complete, correctly-typed response comes back immediately. Nobody wrote a `Claim` resolver; nobody has a claims database. ## Where each value comes from Field by field, decided by the field's declared type: - **Built-in scalars** each have a canonical fake. `String` returns a fixed placeholder string, `Int` and `Float` return numbers, `Boolean` returns a boolean, `ID` returns a generated identifier. - **Enums** resolve to one of the members declared in the schema. This is the one case where the schema enumerates the entire value space, so the mock cannot be wrong about the *set* of possible answers, only about which one a real system would have chosen. - **Object types** recurse. The mock descends into whatever the document selected beneath them, mocking each of those fields the same way, to any depth. - **List fields** return a fixed-length list - two items is a common default - each element mocked from the item type. That length is a convention of the mocking layer, not something the schema states. - **Nullability** is generally ignored on the generous side: a nullable field still gets a value, because a mock that returned null at random would make client work harder rather than easier. - **Arguments** are ignored by default. `claim(id: "c-1")` and `claim(id: "c-2")` come back identical, because nothing correlates an argument with a value unless you write that correlation yourself. ## Where the derivation runs out Two kinds of field the schema genuinely does not determine. **Custom scalars.** `scalar Money` declares a name and nothing else. The schema never says whether the serialized value is a number, a string, a minor-unit integer, or an object, and it certainly does not say what a plausible one looks like. A mock has no basis to invent one, so every custom scalar needs a value supplied explicitly. (A `@specifiedBy` URL on the scalar points a human at a specification; it is not machine-readable guidance a mock can follow.) **Abstract types.** For `union ClaimEvent = FnolReceived | AdjusterAssigned | PaymentIssued`, some concrete member has to be chosen before any of its fields can be mocked. The schema does not pick, so a mocking layer either picks arbitrarily - typically the first member - or requires you to say. ## What is specified, and what is convention Mocking is a **convention of tooling**. Nothing about placeholder values, default list length, or how nullability is treated appears in the GraphQL specification, which has nothing to say about mocks at all. Two mocking layers can differ on every one of those details. What *is* specified is the material a mock reads: the type system, and introspection as the way to obtain it from a running server. ## What it buys, and where the boundary sits The value is sequencing. A client team is unblocked the day the schema is agreed rather than the day the backend is finished: screens render, loading and empty states get built, component props settle, and typed client code can be generated against the same schema. A mock is also a real GraphQL server in every respect except where values originate, so it parses and validates - a document the mock rejects would be rejected in production too. The boundary is equally sharp. A mock tells you nothing that is not in the schema. Not whether a given caller may read `adjusterNotes`; not whether `status: SETTLED` can really coexist with a null `settlementAmount`; not whether the real resolver behind `documents` takes 6 ms or 900 ms; not what a response looks like when a field fails. A mock is a shape generator, and shape is the only thing it can be right about.

  • Does a schema-derived mock validate the document it receives, or answer anything it is sent?
    It validates. The mock is a real GraphQL server in every respect except where values come from: it parses the document, checks it against the schema, and rejects unknown fields, wrong argument types and malformed selection sets exactly as a production server would. That is a genuine benefit - a document the mock refuses will be refused in production too. The caveat is freshness: it validates against the copy of the schema the mock was built from, which can be older than what is deployed.
  • Why do two calls to the same field with different arguments come back identical?
    Because default mocking derives values from types, and an argument is not part of a field's type. Nothing in the schema says that `claim(id: "c-1")` and `claim(id: "c-2")` should differ, so the mock produces the same shape and the same placeholder values for both. If a test needs argument-dependent answers, you supply a function for that field that reads its arguments; the mock only ignores them by default.
  • A mock fills every nullable field with a value. Why is that the default, and what does it cost?
    The default is deliberate generosity: a mock exists to unblock rendering, and nobody can build a screen against a payload where optional fields vanish at random. The cost is that the client's null branches - the empty state for missing adjuster notes, the fallback when no settlement amount exists - are never exercised by mock-backed tests. Teams recover that by overriding those specific fields to null in the handful of tests that care about the empty case.

It is a showroom kitchen: every drawer opens, every door is the right size, and nothing in it has ever cooked a meal.

saying these in an interview costs you the question

  • Says a mock needs the real backend running behind it
  • Thinks mock values come from a sample dataset
  • Claims the GraphQL specification defines mock defaults
  • Assumes a custom scalar mocks itself like a String
  • Expects different arguments to return different mock data
  • Believes a mock exercises real resolver logic

context