@deploybaseline/graphql is the GraphQL kit the Linear and GitHub emulators run on. Use it to serve a GraphQL API from a custom emulator: it reads requests, runs them against your schema, and gives you Relay connections, global IDs, and error helpers. It uses graphql (graphql-js), so queries are validated against your schema exactly as a real server would.
Serve an endpoint
root(context) returns the resolvers for the root fields of Query and Mutation together, keyed by field name. Fields of other types resolve from the objects you return, as in graphql-js. Build the schema with the buildSchema this package exports: graphql-js refuses a schema built by a different copy of the library.
Requests and responses
- POST takes a JSON body (
{ query, variables, operationName }), a form body with the same fields, or anapplication/graphqlbody holding the query. - GET takes
query,variables(JSON), andoperationNameas query parameters, and runs queries only. A mutation over GET gets HTTP 405 withAllow: POST. - Status. By default a request that ran answers 200, even when resolvers returned errors, and a request that could not run answers 400: an empty query, a syntax or validation error, an unknown operation name, or a malformed body. Pass
statusto follow the vendor; Linear answers any error with 400. - Not emulated. A root field that is in the schema but has no resolver answers with the error
Query.<field> is not emulated by baseline(extensions.codeisNOT_EMULATED), so a client hits a clear gap instead of a confusingnull. This lets you start from the vendor’s full schema and add resolvers as you need them. WithstrictFields, the same goes for every field: a property your object does not have fails as<Type>.<field> is not emulated by baselineinstead of reading asnull, which matters when the schema is much larger than what you serve.missingFieldsits in front of that check: Linear uses it to answer unmodeled fields with their type’s empty value (null,false,0, an empty list or connection) and to fail the rest as not emulated, because@linear/sdkselects every scalar of a model. - Errors thrown in a resolver become GraphQL errors with
pathandlocations.graphqlError(message, extensions)addsextensions, such as{ code: 'FORBIDDEN' }.
Helpers
Test coverage
graphqlEndpoint declares every root field in the schema (or the operations you list), and records each root field a test resolves. Provider packages list them in their coverage matrix next to routes, so the coverage gates treat Query.issues like GET /issues:
not_started; it answers “not emulated”. A supported one that no test reaches fails the runtime gate. pnpm conformance counts root fields apart from routes.
Where it runs
The kit is plain HTTP, so a custom emulator with GraphQL works in the CLI and increateEmulator.