GraphQL
Send queries, mutations and subscriptions to GraphQL services, and check their data and their errors, against the services’ schemas. A federated graph’s gateway and a subgraph alone are GraphQL services alike: register each at its URL.
Given the parcels graphql service with the following properties: | url | http://localhost:8400/graphql | | schema | introspection |- Operations come from a file of the project (
.graphql) or a doc string, with variables from a table: a variable takes the type the operation declares for it, so10115is text for aString!. - The checks read the service’s last answer in the scenario. An answer with errors does not fail the step that sends the operation: check its errors.
- Subscriptions go over graphql-ws (the
graphql-transport-wsprotocol, on the url withws://orwss://) or over server-sent events, and belong to the scenario, which ends them when it ends. - The schema is the contract: with a
schemarow (an SDL file of the project, a URL, orintrospection), every operation and its variables are checked against it before they are sent, and every answer’s data against the operation’s types. A subgraph’s SDL may use the federation directives (@key,@link…).
Findings have keys and levels, like the REST pack’s OpenAPI findings:
| Key | Found when |
|---|---|
validation.operation.<rule> |
the operation breaks a validation rule of the GraphQL spec (FieldsOnCorrectType, KnownArgumentNames, ProvidedRequiredArguments…) |
validation.variables.missing |
a required variable is missing |
validation.variables.type |
a variable is not of its type |
validation.response.nonNull |
a non-null field is null, without an error that explains it |
validation.response.type |
a field’s value is not of its type |
validation.response.enum |
a value is not one of its enum’s |
validation.response.missingField |
a field the operation selects is missing |
validation.response.unknownField |
the data has a field the operation does not select |
- Levels:
ERROR(orFAIL) fails the step,WARNandINFOlog the finding,IGNOREdrops it. Every finding is anERRORunlesspacks.graphql.levelsin axx.yaml, or the scenario’sthe GraphQL validation levels are:, says otherwise. - Keys cover the keys below them:
validation.operationsets every operation finding; the most specific key set wins. - Secrets stay secret:
${env:..}values in the properties are masked in logs and failures, and${token:..}names a token of the scenario.
Add it to a project with axx pack add graphql.
Settings
Section titled “Settings”In axx.yaml, under packs.graphql:
| Setting | Takes | Values |
|---|---|---|
levels |
Validation key -> ERROR (or FAIL), WARN, INFO or IGNORE, for every scenario. | names and values |
graphql.service
Section titled “graphql.service”Given the {word} graphql service with the following properties: | property | value |The table may start with the row naming its columns, as above, or go straight to its rows.
Register a GraphQL service under a name: a federated graph’s gateway, a subgraph, or any GraphQL API.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
| Property | Takes | Values | Default |
|---|---|---|---|
url |
the URL operations are posted to | required | |
schema |
its schema, which operations and answers are checked against: an SDL file of the project, a URL, or introspection to ask the service |
||
header.<name> |
a header sent with every operation, such as header.Authorization |
||
timeout |
how long an operation may take, like 5s |
10s |
|
subscriptions |
how subscriptions go | graphql-ws, sse |
graphql-ws |
subscriptions url |
where subscriptions go | the url, with ws://orwss:// for graphql-ws |
Values are expanded (${env:..}, ${sys:..}, ${token:..}); what ${env:..} references expand to is masked everywhere.
Example:
Given the parcels graphql service with the following properties: | url | http://localhost:8400/graphql | | schema | introspection |Given the graph graphql service with the following properties: | url | https://graph.parcels.example/graphql | | schema | graphql/supergraph.graphql | | header.Authorization | Bearer ${token:shop} |Since 0.1.5.
graphql.send.file
Section titled “graphql.send.file”When the {filepath} query/mutation is sent to the {word} graphql service[[ with the following variables:]]Send the query or the mutation of a file of the project, with the table’s variables when the step has one.
| Parameter | Takes | For example |
|---|---|---|
{filepath} |
a file of the project: a path relative to the feature file’s directory, the resources directories or axx.yaml’s directory (looked for in that order), or an absolute path, quoted when it has a space |
seeds/parcels.yaml, kafka/scan-delivered.json |
{word} |
one word, with no spaces | parcels, PX-4101 |
Each row is a variable, or a path into one (address.postcode), and its value: a value takes the type the operation declares for its variable, double quotes make it text, null is null and undefined leaves it out.
Variants, the parts in [[...]] said or left out:
the {filepath} query/mutation is sent to the {word} graphql servicethe {filepath} query/mutation is sent to the {word} graphql service with the following variables:
Example:
When the graphql/parcel.graphql query is sent to the parcels graphql service with the following variables: | reference | PX-GQL-7201 |When the graphql/hold-parcel.graphql mutation is sent to the parcels graphql service with the following variables: | reference | PX-GQL-7202 | | until | 2026-10-05 |Since 0.1.5.
graphql.send.doc
Section titled “graphql.send.doc”When a query/mutation is sent to the {word} graphql service: """ ... """Send the query or the mutation of the doc string.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
Example:
When a query is sent to the parcels graphql service: """ { parcel(reference: "PX-GQL-7201") { status } } """Since 0.1.5.
graphql.subscribe
Section titled “graphql.subscribe”When the {filepath} subscription is started on the {word} graphql service[[ with the following variables:]]Start the subscription of a file of the project, with the table’s variables when the step has one. It belongs to the scenario, which ends it when it ends.
| Parameter | Takes | For example |
|---|---|---|
{filepath} |
a file of the project: a path relative to the feature file’s directory, the resources directories or axx.yaml’s directory (looked for in that order), or an absolute path, quoted when it has a space |
seeds/parcels.yaml, kafka/scan-delivered.json |
{word} |
one word, with no spaces | parcels, PX-4101 |
Each row is a variable, or a path into one (address.postcode), and its value: a value takes the type the operation declares for its variable, double quotes make it text, null is null and undefined leaves it out.
Variants, the parts in [[...]] said or left out:
the {filepath} subscription is started on the {word} graphql servicethe {filepath} subscription is started on the {word} graphql service with the following variables:
Example:
When the graphql/parcel-scanned.graphql subscription is started on the parcels graphql service with the following variables: | reference | PX-GQL-7203 |Since 0.1.5.
graphql.no.errors
Section titled “graphql.no.errors”Then the {word} graphql service answered without errorsCheck that the service’s last answer has no errors.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
Example:
Then the parcels graphql service answered without errorsSince 0.1.5.
graphql.data
Section titled “graphql.data”Then the {word} graphql service's data has the following properties: | path | value |The table may start with the row naming its columns, as above, or go straight to its rows.
Check the data of the service’s last answer.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
Each row is a path into the data (a field, a dotted path like parcel.shop.name, or a JSONPath) and its value, compared as text: null for null and undefined for absent.
Example:
Then the parcels graphql service's data has the following properties: | parcel.status | IN_TRANSIT | | parcel.shop.name | Maple Home |Since 0.1.5.
graphql.error
Section titled “graphql.error”Then the {word} graphql service answered an error where: | path | value |The table may start with the row naming its columns, as above, or go straight to its rows.
Check that the service’s last answer has an error with those values.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
Each row is a path into the error (message, path, extensions.code) and its value, compared as text; the error’s path is its fields and indexes joined with dots, like parcel.shop or parcels.0.reference.
Example:
Then the parcels graphql service answered an error where: | path | holdParcel | | extensions.code | NOT_HOLDABLE |Since 0.1.5.
graphql.received
Section titled “graphql.received”Then [[within {duration} ]]the {word} graphql service's subscription received a message where: | path | value |The table may start with the row naming its columns, as above, or go straight to its rows.
Check that the service’s subscription received a message whose data has those values.
- The check waits for it: 10 seconds, or
within {duration}. - When the subscription has ended, it fails at once, saying why.
| Parameter | Takes | For example |
|---|---|---|
{duration} |
a duration in seconds (s) or minutes (m) |
5s, 2m |
{word} |
one word, with no spaces | parcels, PX-4101 |
Each row is a path into the message’s data and its value, compared as text: null for null and undefined for absent.
Variants, the parts in [[...]] said or left out:
the {word} graphql service's subscription received a message where:within {duration} the {word} graphql service's subscription received a message where:
Example:
Then within 20s the parcels graphql service's subscription received a message where: | parcelScanned.reference | PX-GQL-7203 | | parcelScanned.status | OUT_FOR_DELIVERY |Since 0.1.5.
graphql.levels
Section titled “graphql.levels”Given the GraphQL validation levels are: | validation key | level |The table may start with the row naming its columns, as above, or go straight to its rows.
Set the level of GraphQL validation findings for this scenario, on every GraphQL service it sends operations to.
- A key also sets the keys below it:
validation.operationrelaxesvalidation.operation.FieldsOnCorrectTypetoo. The most specific key set wins. - The rows are merged over
packs.graphql.levelsof axx.yaml. - The pack’s documentation lists the keys, and what each level does.
A row is a validation key and its level: ERROR (or FAIL), WARN, INFO or IGNORE. The key must be one the pack reports, or a prefix of such keys, like validation.operation: any other fails the step, which names the closest keys.
Example:
Given the GraphQL validation levels are: | validation.operation.FieldsOnCorrectType | IGNORE |Since 0.1.5.