Prompt and context
You own a B2B SaaS with an established REST API. Large customers want GraphQL to compose cross-resource queries, while engineering worries about query cost, authorization boundaries, caching, and long-term governance. Decide whether to launch GraphQL and explain the scope, metrics, risks, and migration plan.
This is an API product decision, not an invitation to implement a GraphQL server. The GraphQL specification describes a query language and execution engine for data-model capabilities and requirements; GitHub's public API supports both queries and mutations. Your job is to turn those capabilities into a testable product choice.
What the interviewer is testing
- Starting with customer workflows and measurable pain instead of choosing GraphQL because it is fashionable.
- Comparing REST, GraphQL, and an aggregation layer on discovery, round trips, authorization, caching, and observability.
- Turning schema, query complexity, pagination, and mutation boundaries into product constraints.
- Designing a staged pilot, compatibility plan, pricing approach, and developer-experience metrics.
Questions to clarify first
- Is the pain fewer round trips, less over-fetching, or cross-resource composition? Could existing REST aggregation solve it?
- How many consumers, language stacks, compliance regions, and target SLOs are in scope? Do partners depend on stable contracts?
- Are read-only queries enough, or are writes required? Would writes need transactions, idempotency, and approval?
- Which resources and fields define the tenant boundary? How will depth, response size, and per-tenant budget be limited?
A 30-second answer
I would validate a recurring composition problem with customers and pilot a small read-only resource set. If REST aggregation already solves the high-value workflows cheaply, I would not launch GraphQL for the protocol alone. If several customers need different field combinations and maintaining bespoke endpoints is expensive, I would launch a constrained GraphQL product. The first release would expose a stable query schema, pagination, and complexity budgets, reuse existing identity and tenant authorization, and defer arbitrary mutations. I would scale or stop based on activation, success rate, P95 latency, query cost, support load, and REST migration.
Step-by-step deep dive
Define customer value and alternatives first
Split the request into fewer network round trips, less over-fetching, and cross-resource composition. For each, record the current REST call graph, end-to-end latency, number of bespoke endpoints, and customer-built proxy cost. If one REST aggregation endpoint solves most valuable workflows, include GraphQL governance cost in the comparison instead of counting requests alone.
Set a product boundary instead of exposing the database
The first schema should cover resources with stable semantics, clear tenant ownership, and observable behavior. Tag every field with sensitivity, authorization rules, version promises, and freshness. Review queries and mutations separately: validate read value first, then consider writes after idempotency, audit, and error semantics are mature.
Make query cost an enforceable budget
GraphQL's flexible selection set moves cost from endpoint count to query shape. Limit maximum depth, node count, page size, and timeout, and estimate cost by schema field or resolver. Reject over-budget requests with actionable errors while recording tenant, operation name, estimated cost, and actual resource use.
Preserve identity, authorization, and tenant boundaries
GraphQL changes request shape; it must not bypass existing OAuth, service accounts, tenant isolation, or field-level permissions. Enforce authorization in resolvers or a shared data-access layer rather than only at the root query. Batch reads must prevent cross-tenant joins, unauthorized cache reuse, and information leaks through errors.
Plan developer experience and compatibility
Provide schema documentation, example queries, error guidance, pagination conventions, operation-name requirements, and a changelog. Breaking schema changes need a deprecation window, caller scanning, and named contacts. REST and GraphQL may share domain models, but do not promise one-to-one field parity forever.
Define a pilot, metrics, and exit criteria
Choose 2 to 3 representative customers and read-only workflows with fixed resources and budgets. Track active apps, valid-query rate, P95/P99 latency, cost per query, blocked authorization attempts, support tickets, and time to complete customer tasks. Low adoption, high cost, or rising governance incidents should shrink the schema or stop expansion rather than be hidden by adding fields.
{
"pilot": {"tenants": 3, "mode": "read-only", "maxDepth": 6, "costBudget": 100},
"exit": {"p95LatencyMs": 400, "errorRate": 0.01, "supportTicketsPerTenant": 2}
}Example of a strong answer
I would not treat GraphQL as an inevitable replacement for REST. I would use customer evidence to confirm that composition, over-fetching, or bespoke endpoint maintenance is large enough, and compare it with the delivery cost of a REST aggregation layer. If the pilot earns its place, I would productize GraphQL as a governed API: a stable read-only schema, existing OAuth and tenant authorization, required operation names, depth, node, pagination, and cost limits, plus schema docs and a deprecation window. Google Apigee models an API product as a bundle of resources, methods, access levels, and quotas, which is a useful reminder to design GraphQL access control, limits, and plans together. I would use active customers, success rate, P95, unit query cost, and support burden to decide whether to expand; only then would I add resources and narrowly scoped mutations.
Common mistakes
- Saying “the frontend is more flexible” without proving customer value or comparing REST aggregation.
- Mapping the GraphQL schema directly to database tables and ignoring domain semantics, authorization, and sensitive fields.
- Allowing unlimited depth, pagination, or nesting without a cost model and rejection strategy.
- Launching queries and mutations together without idempotency, audit, approval, or rollback boundaries.
- Tracking adoption alone while ignoring latency, cost, blocked authorization, and support burden.
- Promising a one-time migration for every REST customer while ignoring dual-track docs, deprecation, and rollback.
Follow-ups and responses
If customers only want fewer requests, why not build REST aggregation?
Quantify both options with call graphs and maintenance cost. Fixed, frequent workflows with clear boundaries favor an aggregation endpoint; continually changing combinations across many customers make constrained GraphQL more valuable. Pilot the same workflows before choosing the protocol surface.
How do you keep GraphQL queries from taking down the backend?
Enforce depth, node, pagination, and timeout limits at the edge; maintain field cost weights in the schema; batch and cache in resolvers; and rate-limit by tenant and priority. Log operation name, estimated cost, and resource use for rejected queries instead of returning an opaque server error.
When would you expose mutations?
Only after read-only authorization, errors, auditing, and observability are stable. Start with low-risk, idempotent, compensatable writes. Each mutation needs input validation, conflict semantics, permissions, audit events, and retry behavior; financial, deletion, and cross-tenant actions should remain dedicated workflows.
How would REST and GraphQL coexist?
Keep REST as the stable compatibility surface and use GraphQL for new workflows without requiring field-for-field parity. Share identity, domain authorization, audit, and SLOs, while measuring caller migration and the cost of each surface separately. Discuss REST deprecation only when customer value, operating cost, and compatibility risk are supported by evidence.