Build a GraphQL case view for reviewer 29 in organization 6. The schema exposes cases, owners, and activity with honest nullability for older unassigned cases. An additive field replaces an older owner label while old operation documents remain valid during migration. Querying 47 cases with owner names must not issue 47 separate owner service calls; a request-local loader batches and restores key order, with tenant and permission scope in its lookup. The endpoint admits only bounded work: aliases, depth, list page sizes, and weighted fields count toward a request budget. A known operation ID can narrow public traffic but never grants object access. updateCase takes expected revision and a stable idempotency key, records one write and one outbox intent, and returns a typed conflict when the revision is stale. The activity connection pages by event time plus immutable ID so ties do not drop rows.
Project: tenant-safe GraphQL case API
Build contract
- Query historical null owner data and keep old client operations valid during schema change.
- Batch 47 owner lookups without sharing loader results across tenant requests.
- Reject wide aliases, missing pagination limits, and over-budget work before running resolvers.
- Repeat a mutation and page equal-timestamp activity across concurrent inserts without duplicate writes or missing rows.
Implementation checkpoint
function queryAdmitted(parentCount, requestedItems, maximumItems) {
return requestedItems <= maximumItems && parentCount * requestedItems <= 940;
}
console.log(queryAdmitted(23, 47, 40));
// Output: falseCost and boundaries
Schema validation and cost scoring are O(m) in the operation document, while nested list execution can multiply result counts across levels. A request-local batch changes 47 backend round trips into a bounded set of calls but still moves O(n) owner records and needs ordered results. Keyset pagination can use an index to read O(log n plus k) work for k results, whereas deep offset scans may grow with skipped rows. Idempotency adds a small keyed record and a transaction. Monitor estimated versus actual cost, backend calls, denial counts, mutation conflicts, and page gaps.
Failure drill
Declare owner non-null and query a historical case with no owner; observe error propagation and fix the schema contract. Return batched owner rows in another order and ensure the loader restores requested keys. Run reviewer 29 and reviewer 62 concurrently with a shared owner ID; no cache value may cross tenant scope. Send 600 shallow aliases and confirm admission rejects before resolution. Retry updateCase after a timeout and verify one effective write. Page two activity records with equal timestamps using only time as a cursor, detect the missing row, and add the immutable ID tie-breaker.
Acceptance checks
- Old schema operations and historical records obey declared nullability.
- Batch caches stay inside one authorized request.
- Document cost and pagination bounds apply before resolver work.
- Mutation and cursor rules survive retries and equal sort values.
Common Mistakes
- Assuming a typed schema is an access policy.
- Using a process-global loader for tenant data.
- Reading HTTP success as proof a domain mutation applied.
Related lessons
GraphQL Schema Nullability and Evolution; GraphQL Resolver Batching and Tenant Scope; GraphQL Operation Cost and Admission; GraphQL Mutation Errors and Pagination Contracts.
