GraphQL
GraphQL requests have their own editor — Query, Variables, Schema, Headers, Auth — and send through the ordinary toolbar.
Underneath, the engine executes them as an HTTP POST. That is not a limitation to work
around; it is why GraphQL gets auth injection, {{variable}} resolution, the cookie jar,
layered send settings, gateway rewriting, tests, and history without any of it being
reimplemented.
Author one
Section titled “Author one”- Create a request with protocol GraphQL.
- Set the endpoint URL.
- Write the query or mutation in the Query tab.
- Put variables in the Variables tab as a JSON object.
- Set Operation name when the document contains more than one operation.
query GetUser($id: ID!) { user(id: $id) { id email roles }}{ "id": "{{userId}}" }{{variables}} resolve inside the query text and inside the variables JSON, so "{{userId}}"
above is filled from the active environment at send time.
The Schema tab
Section titled “The Schema tab”A GraphQL endpoint can describe itself. Press Introspect in the Schema tab and Tinspec POSTs the standard introspection query to the endpoint — with this request’s headers, active environment and auth — then renders what comes back.
Two things follow from it:
- A schema explorer. Root operations and their fields first, then the declared types, with a filter box over both. Deprecated fields carry a badge. Clicking a root field inserts a starter document for it, turning its required arguments into query variables; nested field rows are documentation rather than buttons, because a nested field is not an operation on its own.
- Completion in the Query tab. Once a schema is loaded the header says schema loaded ·
⌃Space suggests, and the query editor completes field names at any depth, argument names
inside a field’s parentheses, and input type names after
$name:in a variable definition. Aliases, inline fragments and fragment definitions all resolve.
Introspection is manual and never automatic. It is a real request to somebody’s server, so it happens when you ask for it. It is also a pure side channel: it changes what the editor can offer and nothing about what Send transmits.
When completion goes quiet
Section titled “When completion goes quiet”The completer is a small scanner, not a GraphQL parser — carrying a full grammar to answer “what can I type here” about a document that is invalid mid-keystroke anyway was not worth the bundle. So it deliberately returns nothing for fragment spreads, a union’s selection set, argument and enum values, variable names, and anything after a syntax error.
An empty popup is the signal that the cursor is somewhere the scanner cannot reason about. A confidently wrong completion would cost more.
When the server says no
Section titled “When the server says no”Many servers disable introspection outside development, and the standard way they do it is to
answer 200 with an errors array. Tinspec quotes that error verbatim and says plainly that
the explorer and autocomplete are unavailable for this endpoint — sending is unaffected, and a
query you write by hand works exactly as before.
The query itself is the conservative, widely supported form — no specifiedByURL, no
isDeprecated on arguments — because a query that fails validation against an older server
tells you nothing about your API.
Responses
Section titled “Responses”The response renders in the normal response pane — same JSON folding, same click-to-copy, same Tests tab for results.
Remember that GraphQL reports errors in the body with HTTP 200. A test asserting
status eq 200 will pass on a failed query. Assert on the payload instead:
tests: - source: body path: data.user.id op: exists - source: body path: errors op: isEmptyisEmpty is the right operator for the second one: absent, "", [] and {} all count as
empty, which is exactly the set of shapes a healthy GraphQL response uses for errors.
Chains
Section titled “Chains”GraphQL requests are chainable — they produce exactly one response. Extract from the body with a dotted path as usual:
extract: - var: userId from: body path: data.user.idBind an endpoint as a source
Section titled “Bind an endpoint as a source”Add API source → GraphQL API binds the endpoint itself: the introspection query becomes a
polled spec source, and its root fields materialize as endpoints
in the sidebar, grouped by Query / Mutation / Subscription.
One root field is one endpoint, not one type. That is forced by the protocol: every root field
is a POST to the same URL, so identifying endpoints by URL would collapse the entire API onto
a single row, a single overlay key and a single tab. The operation id (query.user) is the
identity instead.
Being a spec source, it inherits Spec Changes, the breaking-change classification and endpoint overlays — a field that lost an argument reads as a change rather than as a stale SDL file on disk.
Not in this release
Section titled “Not in this release”- Subscriptions. GraphQL over WebSocket is not supported; the engine sends every GraphQL request as an HTTP POST. A subscription root field still appears in the explorer, and in a bound source’s endpoint list, because the server declares it — but sending one only POSTs the document. For a real socket, use the WebSocket protocol directly.
In the file format
Section titled “In the file format”- name: Get user protocol: graphql method: POST url: "{{baseUrl}}/graphql" graphql: query: | query GetUser($id: ID!) { user(id: $id) { id email } } variables: '{"id":"{{userId}}"}' operationName: GetUser auth: provider: users-apivariables is a JSON-encoded string, not a nested mapping. Nothing about introspection is
stored on the request — the poll belongs to the session, and the schema is the server’s.