String! means non-null and [Book!]! a non-null list of non-null books; nullability propagates upward, since a non-null field resolving to null nulls its parent and the error names the parent, so start fields nullable. Every field has a resolver, (parent, args, context, info) — the value its container resolved to, the arguments, a per-request object you build, the parsed selection. Omit one and the default reads the property of the same name off parent, which is why title and year in GraphQL needed no code.
Letting clients compose queries means a small document can imply a lot of database work: each Book resolves its own author, so four books run four lookups — the N+1 problem, where N is whatever the client asked for. DataLoader 13,391 (https://github.com/graphql/dataloader 13,391 ) (2.2.3, MIT) collects the keys requested during one tick of the event loop and calls your batch function once.
import DataLoader from 'dataloader';
async function findAuthors(ids) { // the only code that touches the database
calls.push(JSON.stringify(ids));
return ids.map((id) => rows[id]); // one row per id, in the order asked
}
// the resolver becomes Book.author: (book, _args, ctx) => ctx.authors.load(book.authorId)
// and one fresh loader per request: the cache must never outlive one user's query
const yoga = createYoga({ schema, context: () => ({ authors: new DataLoader(findAuthors) }) });Four books, with the loader and with a plain per-id lookup:
one lookup per book -> 4 round trip(s), keys ["a1"] ["a2"] ["a1"] ["a2"] DataLoader -> 1 round trip(s), keys ["a1","a2"]
Four lookups became one and the duplicate keys collapsed on the way: DataLoader deduplicates as well as batches. The batch function must return an array as long as ids, in the same order, with null or an Error where it found nothing — get that wrong and books quietly show the wrong author. Batching fixes the constant factor, not the shape of the problem: add depth and complexity limits (@escape.tech/graphql-armor 3.2.0 has both as plugins) and a pagination argument on every list field (Pagination).