GraphQL Support
Last updated: November 24, 2025
GraphQL Support
REST CLI supports GraphQL queries, mutations, and subscriptions with automatic request formatting and response parsing.
Quick Start
Add # @protocol graphql to any request:
### Get Users
# @protocol graphql
POST https://api.example.com/graphql
{ users { id name email } }
REST CLI automatically:
- Wraps query in
{"query": "..."}JSON format - Sets
Content-Type: application/json - Formats GraphQL responses for readability
- Separates
datafromerrors
Basic Syntax
Simple Query
### Get Countries
# @protocol graphql
POST https://countries.trevorblades.com/graphql
{ countries { code name capital } }
Query with Parameters
### Get Specific Country
# @protocol graphql
POST https://countries.trevorblades.com/graphql
{ country(code: "US") { name capital currency } }
With Variables (Inline)
### Get Country by Code
# @protocol graphql
POST https://countries.trevorblades.com/graphql
query GetCountry {
country(code: "{{countryCode}}") {
name
capital
emoji
}
}
Variables defined in profile or CLI:
restcli -e countryCode=CA get-country.http
Mutations
### Create User
# @protocol graphql
POST https://api.example.com/graphql
Authorization: Bearer {{token}}
mutation {
createUser(input: {
name: "Alice"
email: "[email protected]"
}) {
id
name
createdAt
}
}
Request Format
Protocol Annotation
Required: Add # @protocol graphql before the request.
### Query Name
# @protocol graphql
POST https://your-graphql-endpoint/graphql
{ your query here }
HTTP Method
Use POST (GraphQL standard):
POST https://api.example.com/graphql
Headers
Add authentication or custom headers as normal:
### Authenticated Query
# @protocol graphql
POST https://api.example.com/graphql
Authorization: Bearer {{apiKey}}
X-Request-ID: {{requestId}}
{ viewer { login name } }
Query Body
Write GraphQL query directly in the body (no JSON wrapping needed):
{
users(limit: 10) {
id
name
email
}
}
Or with operation name:
query GetUsers {
users(limit: 10) {
id
name
}
}
Or mutation:
mutation CreatePost {
createPost(title: "Hello", content: "World") {
id
title
}
}
Response Handling
Successful Response
REST CLI extracts and formats the data field:
GraphQL Server Response:
{
"data": {
"users": [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
}
}
Displayed:
{
"users": [
{
"id": 1,
"name": "Alice"
},
{
"id": 2,
"name": "Bob"
}
]
}
Errors
GraphQL errors are formatted for readability:
GraphQL Server Response:
{
"data": null,
"errors": [
{
"message": "Field 'invalidField' not found",
"locations": [{ "line": 2, "column": 3 }],
"path": ["user", "invalidField"]
}
]
}
Displayed:
{
"data": null,
"errors": [
{
"message": "Field 'invalidField' not found",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": ["user", "invalidField"]
}
]
}
Partial Data with Errors
When GraphQL returns both data and errors:
{
"data": {
"user": {
"name": "Alice",
"email": null
}
},
"errors": [
{
"message": "Not authorized to access email",
"path": ["user", "email"]
}
]
}
Both fields are displayed.
Variables and Profiles
With REST CLI Variables
### Get User
# @protocol graphql
POST https://api.example.com/graphql
Authorization: Bearer {{apiToken}}
query {
user(id: {{userId}}) {
id
name
}
}
Profile:
{
"name": "API",
"variables": {
"apiToken": "secret123",
"userId": "42"
}
}
Interactive Variables for GraphQL
Use interactive variables for dynamic queries:
{
"name": "GraphQL API",
"variables": {
"searchQuery": {
"value": "",
"interactive": true
},
"apiKey": {
"value": "sk-...",
"interactive": true
}
}
}
Request:
### Search
# @protocol graphql
POST https://api.example.com/graphql
Authorization: Bearer {{apiKey}}
query {
search(query: "{{searchQuery}}") {
results {
title
description
}
}
}
On execution, prompts for both searchQuery and apiKey.
Filtering and Querying
Apply JMESPath filters to GraphQL responses:
### Get Users (filtered)
# @protocol graphql
# @filter users[?age > `25`]
POST https://api.example.com/graphql
{ users { id name age } }
Advanced Features
Fragments
### Get Users with Fragments
# @protocol graphql
POST https://api.example.com/graphql
query {
users {
...UserFields
}
}
fragment UserFields on User {
id
name
email
createdAt
}
Named Operations
### Multiple Operations
# @protocol graphql
POST https://api.example.com/graphql
query GetUser {
user(id: 1) { name }
}
query GetPosts {
posts(limit: 5) { title }
}
Directives
### Conditional Fields
# @protocol graphql
POST https://api.example.com/graphql
query GetUser($withEmail: Boolean!) {
user(id: 1) {
name
email @include(if: $withEmail)
}
}
Subscriptions
GraphQL subscriptions (WebSocket-based) are planned for future release.
Current workaround: Use SSE-based subscriptions if your API supports them:
### Subscribe to Events
# @streaming true
GET https://api.example.com/graphql/subscriptions?query={{encodedQuery}}
Accept: text/event-stream
Introspection
Query the GraphQL schema:
### Schema Types
# @protocol graphql
POST https://countries.trevorblades.com/graphql
{
__schema {
types {
name
kind
description
}
}
}
### Query Fields
# @protocol graphql
POST https://countries.trevorblades.com/graphql
{
__type(name: "Query") {
name
fields {
name
description
type { name kind }
}
}
}
Comparison with HTTP
| Feature | HTTP | GraphQL |
|---|---|---|
| Protocol annotation | None | # @protocol graphql |
| Method | Any | Always POST |
| Body format | Raw | Wrapped in {"query": "..."} |
| Response | Direct | Extracts data, formats errors |
| Headers | As-is | Auto-adds Content-Type: application/json |