npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

graphql-query-to-json

v2.0.6

Published

Convert graphQL queries and mutations to easily readable JSON representations.

Readme

graphql-query-to-json

Statement coverage Function coverage Line coverage Branches badge

A TypeScript library that converts GraphQL query and mutation strings into structured JSON objects. This library serves as the reverse of json-to-graphql-query, enabling programmatic manipulation and analysis of GraphQL queries.

Features

  • Full GraphQL Support: Queries, mutations and subscriptions
  • Variable Handling: Complete variable substitution with validation
  • Arguments: All argument types (strings, integers, floats, objects, arrays, enums)
  • Aliases: Field aliasing with metadata preservation
  • Inline Fragments: Complete support for conditional type-based field selection
  • Type Safety: Full TypeScript support with comprehensive type definitions
  • Error Handling: Descriptive error messages for malformed queries and missing variables
  • Framework Agnostic: Works with any JavaScript/TypeScript environment

Installation

npm install graphql-query-to-json
# or
yarn add graphql-query-to-json

Basic Usage

const {graphQlQueryToJson} = require("graphql-query-to-json")

const query = `
query GetThisStuff($name: String, $lastName: String) {
    viewer {
        personal(criteria: {
            name: $name,
            lastName: $lastName
        }) {
            name
            address
        }
    }
}
`
const result = graphQlQueryToJson(query, {
    variables: {
        name: "PETER",
        lastName: "SCHMIDT",
    },
})

console.log(result)
// Output:
{
  query: {
    viewer: {
      personal: {
        __args: {
          criteria: {
            name: "PETER",
            lastName: "SCHMIDT",
          },
        },
        name: true,
        address: true,
      },
    },
  },
}

Transformation Rules

The library follows predictable transformation patterns:

| GraphQL Element | JSON Representation | Example | |----------------|-------------------|---------| | Scalar Fields | true | namename: true | | Object Fields | Nested objects | user { name }user: { name: true } | | Arguments | __args property | user(id: 1)user: { __args: { id: 1 } } | | Aliases | Field renaming + __aliasFor | renamed: userrenamed: { __aliasFor: "user" } | | Variables | Substituted values | $userId → actual variable value | | Enums | EnumType wrapper | status: ACTIVEstatus: { "value": "ACTIVE" } | | Inline Fragments | __on property | ... on User { name }__on: { __typeName: "User", name: true } |

Comprehensive Examples

Simple Queries

// Single and multiple fields
const query = `
query {
    viewer {
        name
        email
    }
    user {
        profile {
            avatar
            bio
        }
    }
}
`

const result = graphQlQueryToJson(query)

// Output:
{
  query: {
    viewer: {
      name: true,
      email: true
    },
    user: {
      profile: {
        avatar: true,
        bio: true
      }
    }
  }
}

Variables and Arguments

// Query with variables
const query = `
query GetUser($userId: ID!, $includeProfile: Boolean!) {
    user(id: $userId) {
        name
        email
        profile @include(if: $includeProfile) {
            bio
            avatar
        }
    }
}
`

const result = graphQlQueryToJson(query, {
    variables: {
        userId: "123",
        includeProfile: true
    }
})

// Output:
{
  query: {
    user: {
      __args: { id: "123" },
      name: true,
      email: true,
      profile: {
        bio: true,
        avatar: true
      }
    }
  }
}

Scalar Fields with Arguments

// Scalar fields that accept arguments
const query = `
query {
    userCount(filter: "active")
    totalRevenue(currency: "USD", year: 2024)
    averageRating(precision: 2)
}
`

const result = graphQlQueryToJson(query)

// Output:
{
  query: {
    userCount: {
      __args: { filter: "active" }
    },
    totalRevenue: {
      __args: { currency: "USD", year: 2024 }
    },
    averageRating: {
      __args: { precision: 2 }
    }
  }
}

Mutations with Simple Arguments

const mutation = `
mutation {
    getPersonalStuff(name: "PETER") {
        personal {
            name
            address
        }
        other {
            parents
        }
    }
}
`
const result = graphQlQueryToJson(mutation)

// Output:
{
  mutation: {
    getPersonalStuff: {
      __args: {
        name: "PETER",
      },
      personal: {
        name: true,
        address: true,
      },
      other: {
        parents: true,
      },
    },
  },
}

Mutations with Complex Arguments

// Mutation with nested object arguments
const mutation = `
mutation CreateUser($input: UserInput!) {
    createUser(input: $input) {
        id
        name
        profile {
            email
            settings {
                theme
                notifications
            }
        }
    }
}
`

const result = graphQlQueryToJson(mutation, {
    variables: {
        input: {
            name: "John Doe",
            email: "[email protected]",
        }
    }
})

// Output:
{
  mutation: {
    createUser: {
      __args: {
        input: {
          name: "John Doe",
          email: "[email protected]"
        }
      },
      id: true,
      name: true,
      profile: {
        email: true,
        settings: {
          theme: true,
          notifications: true
        }
      }
    }
  }
}

Aliases and Field Renaming

// Multiple aliases for the same field
const query = `
query {
    currentUser: user(id: 1) {
        name
        email
    }
    adminUser: user(id: 2) {
        name
        permissions
    }
    guestUser: user(id: 3) {
        name
        status
    }
}
`

const result = graphQlQueryToJson(query)

// Output:
{
  query: {
    currentUser: {
      __aliasFor: "user",
      __args: { id: 1 },
      name: true,
      email: true
    },
    adminUser: {
      __aliasFor: "user",
      __args: { id: 2 },
      name: true,
      permissions: true
    },
    guestUser: {
      __aliasFor: "user",
      __args: { id: 3 },
      name: true,
      status: true
    }
  }
}

Enum Types

// Enums in arguments
const query = `
query {
    posts(status: PUBLISHED, orderBy: CREATED_DESC) {
        title
        content
    }
    users(role: ADMIN, sortBy: NAME_ASC) {
        name
        email
    }
}
`

const result = graphQlQueryToJson(query)

// Output (enums are wrapped in EnumType objects):
{
  query: {
    posts: {
      __args: {
        status: { "value": "PUBLISHED" },
        orderBy: { "value": "CREATED_DESC" }
      },
      title: true,
      content: true
    },
    users: {
      __args: {
        role: { "value": "ADMIN" },
        sortBy: { "value": "NAME_ASC" }
      },
      name: true,
      email: true
    }
  }
}

Array Arguments

// Lists and arrays as arguments
const mutation = `
mutation {
    updateUser(
        id: "123",
        tags: ["developer", "typescript", "graphql"],
        permissions: [READ, WRITE, ADMIN]
    ) {
        id
        tags
        permissions
    }
}
`

const result = graphQlQueryToJson(mutation)

// Output:
{
  mutation: {
    updateUser: {
      __args: {
        id: "123",
        tags: ["developer", "typescript", "graphql"],
        permissions: [
          "READ",
          "WRITE",
          "ADMIN"
        ]
      },
      id: true,
      tags: true,
      permissions: true
    }
  }
}

Empty Values and Edge Cases

// Empty strings, objects, and arrays
const mutation = `
mutation {
    createRecord(input: {
        name: "",
        metadata: {},
        tags: [],
        count: 0,
        isActive: false
    }) {
        id
        status
    }
}
`

const result = graphQlQueryToJson(mutation)

// Output:
{
  mutation: {
    createRecord: {
      __args: {
        input: {
          name: "",
          metadata: {},
          tags: [],
          count: 0,
          isActive: false
        }
      },
      id: true,
      status: true
    }
  }
}

Deeply Nested Objects

// Complex nested structures
const query = `
query {
    organization {
        teams {
            members {
                user {
                    profile {
                        personalInfo {
                            address {
                                street
                                city
                                country
                            }
                        }
                    }
                }
            }
        }
    }
}
`

const result = graphQlQueryToJson(query)

// Output:
{
  query: {
    organization: {
      teams: {
        members: {
          user: {
            profile: {
              personalInfo: {
                address: {
                  street: true,
                  city: true,
                  country: true
                }
              }
            }
          }
        }
      }
    }
  }
}

Mixed Variable Types

// Float arguments and numeric types
const query = `
query GetProducts {
    products(
        minRating: 4.5,
        maxPrice: 99.99,
        discount: -10.5,
        threshold: 0.001,
        scientific: 2.5e3
    ) {
        name
        rating
        price
    }
    analytics(
        coordinates: {
            lat: 40.7128,
            lng: -74.006
        },
        mixed: [1, 2.5, 3, 4.75]
    ) {
        data
    }
}
`

const result = graphQlQueryToJson(query)

// Output:
{
  query: {
    products: {
      __args: {
        minRating: 4.5,           // ✅ Float as number
        maxPrice: 99.99,          // ✅ Float as number  
        discount: -10.5,          // ✅ Negative float
        threshold: 0.001,         // ✅ Small decimal
        scientific: 2500          // ✅ Scientific notation (2.5e3)
      },
      name: true,
      rating: true,
      price: true
    },
    analytics: {
      __args: {
        coordinates: {
          lat: 40.7128,           // ✅ Nested floats
          lng: -74.006
        },
        mixed: ["1", "2.5", "3", "4.75"]  // Arrays preserve strings
      },
      data: true
    }
  }
}

Inline Fragments

// Single inline fragment
const query = `
query {
    posts {
        title
        ... on TextPost {
            content
            wordCount
        }
    }
}
`

const result = graphQlQueryToJson(query)

// Output:
{
  query: {
    posts: {
      title: true,
      __on: {
        __typeName: "TextPost",
        content: true,
        wordCount: true
      }
    }
  }
}
// Multiple inline fragments
const query = `
query {
    media {
        ... on TextPost {
            content
            author {
                name
            }
        }
        ... on ImagePost {
            imageUrl
            altText
        }
        ... on VideoPost {
            videoUrl
            duration
        }
    }
}
`

const result = graphQlQueryToJson(query)

// Output:
{
  query: {
    media: {
      __on: [
        {
          __typeName: "TextPost",
          content: true,
          author: {
            name: true
          }
        },
        {
          __typeName: "ImagePost",
          imageUrl: true,
          altText: true
        },
        {
          __typeName: "VideoPost", 
          videoUrl: true,
          duration: true
        }
      ]
    }
  }
}
// Inline fragments with arguments and variables
const query = `
query GetPosts($limit: Int!) {
    posts {
        title
        ... on TextPost {
            comments(limit: $limit) {
                text
                author {
                    name
                }
            }
        }
    }
}
`

const result = graphQlQueryToJson(query, {
    variables: { limit: 5 }
})

// Output:
{
  query: {
    posts: {
      title: true,
      __on: {
        __typeName: "TextPost",
        comments: {
          __args: { limit: 5 },
          text: true,
          author: {
            name: true
          }
        }
      }
    }
  }
}

Subscriptions

// Basic subscription
const subscription = `
subscription {
    messageAdded {
        id
        content
        user {
            name
            email
        }
    }
}
`

const result = graphQlQueryToJson(subscription)

// Output:
{
  subscription: {
    messageAdded: {
      id: true,
      content: true,
      user: {
        name: true,
        email: true
      }
    }
  }
}
// Subscription with variables and arguments
const subscription = `
subscription MessageSubscription($userId: ID!, $channel: String!) {
    messageAdded(userId: $userId, channel: $channel) {
        id
        content
        timestamp
    }
}
`

const result = graphQlQueryToJson(subscription, {
    variables: {
        userId: "123",
        channel: "general"
    }
})

// Output:
{
  subscription: {
    messageAdded: {
      __args: {
        userId: "123",
        channel: "general"
      },
      id: true,
      content: true,
      timestamp: true
    }
  }
}
// Subscription with aliases and enums
const subscription = `
subscription {
    latestMessage: messageAdded(channel: PUBLIC) {
        id
        content
    }
}
`

const result = graphQlQueryToJson(subscription)

// Output:
{
  subscription: {
    latestMessage: {
      __aliasFor: "messageAdded",
      __args: {
        channel: { "value": "PUBLIC" }
      },
      id: true,
      content: true
    }
  }
}

API Reference

graphQlQueryToJson(query, options?)

Parameters:

  • query (string): The GraphQL query, mutation, or subscription string
  • options (object, optional):
    • variables (object): Variables referenced in the query

Returns: JSON object representation of the GraphQL query

Throws:

  • Error if query syntax is invalid
  • Error if variables are referenced but not provided
  • Error if query contains multiple operations

Limitations

While the library supports the core GraphQL features, there are some limitations:

Fragment Support

  • Inline Fragments: ✅ Fully Supported (e.g., ... on TypeName)
  • Named Fragments: Not supported due to multiple definition restriction
// ❌ Named fragments still throw an error
const queryWithFragment = `
query {
    user {
        ...UserFields
    }
}

fragment UserFields on User {
    id
    name
}
`
// Throws: "The parsed query has more than one set of definitions"

// ✅ Inline fragments work perfectly
const queryWithInlineFragment = `
query {
    search {
        ... on User {
            name
        }
        ... on Post {
            title
        }
    }
}
`
// Output: { query: { search: { __on: [...] } } }

Directives

  • Directive Handling: Directives like @include, @skip are parsed but ignored
  • The library focuses on structure extraction rather than directive execution
// ✅ This works but directives are ignored
const queryWithDirective = `
query($includeEmail: Boolean!) {
    user {
        name
        email @include(if: $includeEmail)
    }
}
`
// The @include directive won't affect the output structure

These limitations apply equally to queries, mutations, and subscriptions since they all use the same AST processing logic.

TypeScript Support

Full TypeScript definitions are included:

import { graphQlQueryToJson } from 'graphql-query-to-json'

interface Variables {
  userId: string
  limit: number
}

const variables: Variables = {
  userId: "123",
  limit: 10
}

const result = graphQlQueryToJson(query, { variables })
// Result is properly typed

Development

Building

npm run build        # Compile TypeScript to JavaScript
npm run watch        # Build in watch mode

Testing

npm test              # Run Jest tests
npm run test:coverage # Run tests with coverage

Code Quality

npm run lintFull     # Run Prettier and ESLint with auto-fix

Architecture

The library uses a multi-phase approach:

  1. Parse: Uses graphql library to parse query into AST
  2. Validate: Ensures all variables are provided
  3. Transform: Recursively processes selections, arguments, and aliases
  4. Substitute: Replaces variable placeholders with actual values

Key components:

  • getSelections(): Processes field selections recursively
  • getArguments(): Handles all argument types and nesting
  • replaceVariables(): Deep variable substitution using lodash.mapValues
  • checkEachVariableInQueryIsDefined(): Variable validation with descriptive errors

Use Cases

  • Query Analysis: Programmatically analyse GraphQL query structure
  • Query Transformation: Convert between query formats
  • Testing: Validate query structures in tests
  • Documentation Generation: Extract field usage patterns
  • Caching Keys: Generate cache keys from query structure

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes with tests
  4. Run npm run build && npm test
  5. Submit a pull request

License

MIT License - see LICENSE file for details