GraphQL sources let you place an existing GraphQL API behind a governed Virtual API. Instead of exposing your upstream endpoint directly, you enroll a single GraphQL endpoint, pre-register the queries callers are allowed to run, and let DataHarbor apply the same governance pipeline used for other sources.
GraphQL sources are query-only today. mutation and subscription operations are rejected during enrollment.
The operationName field tells DataHarbor which operation in the document to execute. Documents with multiple operations and no operationName are rejected.
DataHarbor’s operations are the persisted-query equivalent. Apollo Persisted Queries (APQ) and other client-side persisted-query flows are not supported, but the operations[] model gives you the same end result: callers reference a stable, server-curated query by id rather than sending a full document.
DataHarbor parses variable definitions out of each operation document at enrollment time and stores the declared variable names alongside the operation. At runtime:
Only declared variables are forwarded to the upstream. Extra keys in the body are silently dropped.
Required variables (!) are not auto-validated at the broker — if you omit one, the upstream rejects the request and you receive its error response.
Variables stay JSON-native; DataHarbor never string-interpolates caller input into the operation document.
The DataHarbor dashboard shows the parsed variable names on each operation in the connection blade and pre-populates the sample request body with null defaults so callers can see what an operation accepts without re-reading the document.
DataHarbor accepts either method on /fetch/{leaseId}/{operationId}. Use POST whenever you need to pass variables — GET cannot carry a body, so a GET to an operation that declares required variables will fail at the upstream.
DataHarbor forwards only the variables declared by the operation. Extra keys are ignored, and callers cannot inject new GraphQL text into the stored document.
GraphQL responses are still JSON, so you use the same filter spec language described in Virtual APIs and Field Targeting. The key difference is how you choose object names.
Controls run against the response body as a whole, with object selection rooted at the GraphQL envelope:
data.<collection> is the conventional target — DataHarbor matches collection keys under data against the object names in your filter spec.
errors is preserved as-is and passed through to the caller. It is part of the JSON envelope, so you can target it like any other object (e.g., to redact sensitive fields a vendor leaks in error messages), but most filter specs leave it alone.
Use the top-level collection key under data as the object name in your spec. In practice, this is usually the plural resource name, such as properties or users.If your query returns:
useStrictNameMatching: false is a good default for GraphQL sources because different operations often return the same logical object with slightly different shapes.
DataHarbor preserves the normal GraphQL response model.
Upstream result
What callers receive
{ "data": ... }
Normal success with your controls applied
{ "errors": [...] }
The upstream GraphQL errors array is passed through
{ "data": ..., "errors": [...] }
Partial success with both data and errors preserved
HTTP 4xx or 5xx
A transport error from the upstream
GraphQL 200 OK does not always mean success. A response with "errors" in the body is still HTTP 200. Always check the errors field on the parsed response, even when data is present — partial failures are normal in GraphQL and your client must handle them.