The GraphQL plugin allows you to test GraphQL APIs using Tavern. It provides specialized request and response handling that understands GraphQL’s unique structure and requirements.
Important Note on Query Formatting¶
GraphQL queries cannot use Tavern’s standard variable formatting (curly braces {}) because GraphQL syntax itself
uses curly braces. If you try to use formatting like {variable} in your GraphQL queries, it will fail because Tavern
will attempt to format them before sending the query.
Instead, use GraphQL variables for any dynamic content:
# ✅ GOOD - Use GraphQL variables
stages:
- name: Query user with variable
graphql_request:
url: "{graphql_server_url}/graphql" # URL formatting works fine
query: |
query GetUser($id: ID!) {
user(id: $id) { # GraphQL variables work fine
id
name
email
}
}
variables:
id: "{user_id}" # Variables in the variables object support formatting
# ❌ BAD - Don't use formatting in queries
stages:
- name: Query user with formatting in query
graphql_request:
url: "{graphql_server_url}/graphql"
query: |
query GetUser {
user(id: "{user_id}") { # This will fail - formatting in query
id
name
}
}Configuration¶
If using the default gql backend for graphql,
default options can be passed to the underlying HTTP transport in the “gql” block at the top level for a test.
The GraphQL configuration schema supports these options:
gql:
headers:
string: string # Default headers for all requestsFor example, to make a query with an authorization header for all requests, not just for a single stage like in the example below:
---
test_name: Query with global authorization header
gql:
headers:
Authorization: "Bearer test-token"
stages:
- name: Query with authorization header
graphql_request:
...Requests¶
Basic Query¶
stages:
- name: Get user by ID
graphql_request:
url: "{graphql_server_url}/graphql"
query: |
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
variables:
id: "1"Query with Variables¶
Use variables for dynamic data. Variables support standard Tavern formatting:
stages:
- name: Create user with test variables
graphql_request:
url: "{graphql_server_url}/graphql"
query: |
mutation CreateUser($name: String!, $email: String!) {
createUser(name: $name, email: $email) {
id
name
email
}
}
variables:
name: "{user_name}" # Formatting works in variables
email: "{user_email}"Query with Headers¶
stages:
- name: Authenticated query
graphql_request:
url: "{graphql_server_url}/graphql"
headers:
Authorization: "Bearer {auth_token}"
Content-Type: "application/json" # Automatically added if not present
query: |
query GetUserData {
me {
id
name
}
}Query with Operation Name¶
stages:
- name: Named operation
graphql_request:
url: "{graphql_server_url}/graphql"
query: |
query GetUserProfile($id: ID!) {
user(id: $id) {
id
name
profile {
bio
avatar
}
}
}
operation_name: GetUserProfile # Optional operation name
variables:
id: "1"Multiple Operations in One Query¶
stages:
- name: Multiple operations
graphql_request:
url: "{graphql_server_url}/graphql"
query: |
query GetUser($id: ID!) {
user(id: $id) {
id
name
}
}
mutation UpdateUser($id: ID!, $name: String!) {
updateUser(id: $id, name: $name) {
id
name
}
}
operation_name: GetUser # Specify which operation to execute
variables:
id: "1"File Uploads¶
GraphQL file uploads are handled through variables using the Upload scalar type. You need to:
Define a GraphQL mutation with an
UploadparameterUse the
files:block in your test to specify which file to uploadThe variable name in
files:must match the parameter name in your mutation
stages:
- name: Upload a file
graphql_request:
url: "{graphql_server_url}/graphql"
query: |
mutation UploadFile($file: Upload!, $title: String!) {
uploadFile(file: $file, title: $title) {
id
filename
url
}
}
variables:
title: "My File"
files:
file: path/to/local/file.txt
graphql_response:
data:
uploadFile:
id: !anyint
filename: "file.txt"You can upload multiple files by specifying them in the files: block:
stages:
- name: Upload multiple files
graphql_request:
url: "{graphql_server_url}/graphql"
query: |
mutation UploadFiles($file1: Upload!, $file2: Upload!) {
uploadMultiple(file1: $file1, file2: $file2) {
id
files {
filename
url
}
}
}
variables:
# Note: variables here should not contain the file data
files:
file1: path/to/first/file.txt
file2: path/to/second/file.txt
graphql_response:
json:
data:
uploadMultiple:
id: !anyint
files:
- filename: "file.txt"
- filename: "file.txt"You can also use the long form to specify the content_type of the file:
stages:
- name: Upload file with custom content type
graphql_request:
url: "{graphql_server_url}/graphql"
query: |
mutation UploadFile($myFileName: Upload!, $title: String!) {
uploadFile(file: $myFileName, title: $title) {
id
filename
}
}
variables:
title: "Custom File"
files:
myFileName:
file_path: path/to/file.txt
content_type: text/plain
graphql_response:
data:
uploadFile:
id: !anyint
filename: "file.txt"Responses¶
GraphQL responses follow the standard GraphQL format with data and/or errors at the top level:
Successful Response¶
stages:
- name: Query user
graphql_request:
url: "{graphql_server_url}/graphql"
query: |
query GetUser($id: ID!) {
user(id: $id) {
id
name
}
}
variables:
id: "1"
graphql_response:
json:
data:
user:
id: "1"
name: "John Doe"Response with Errors¶
stages:
- name: Invalid query
graphql_request:
url: "{graphql_server_url}/graphql"
query: |
query InvalidQuery {
invalidField {
id
}
}
graphql_response:
json:
errors:
- message: "Cannot query field 'invalidField' on type 'Query'."Strictness¶
As described in the strict key checking section in the basics, GraphQL responses
can use the strict key to check that the response contains all or some of the expected keys. See that section
for more details. The json strictness setting is reused for the data key in GraphQL responses.
Error Handling¶
The GraphQL plugin provides specific error handling for common GraphQL scenarios:
Response Structure Validation¶
Tavern automatically validates that GraphQL responses have the correct structure:
Must contain only
dataorerrorsat the top levelCannot have other top-level keys
Status Code Handling¶
GraphQL responses should always return HTTP 200 status codes, even for:
Validation errors
Business logic errors
Missing required fields
Non-200 status codes indicate HTTP-level problems (authentication, network issues, etc.).
Limitations¶
Current Limitations¶
Query Formatting: Cannot use
{variable}formatting in GraphQL queries themselves - use GraphQL variables insteadStreaming: No support for streaming responses (defer/stream directives)
Future Plans¶
Improved error message formatting
Extensions (unsupported by gql so we’d need to implement our own)
‘Partial responses’ (errors and data in the response)