or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-graphql-fields

Turns GraphQLResolveInfo into a map of the requested fields

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/graphql-fields@2.0.x

To install, run

npx @tessl/cli install tessl/npm-graphql-fields@2.0.0

index.mddocs/

GraphQL Fields

GraphQL Fields is a JavaScript utility library that transforms GraphQLResolveInfo objects into structured field maps. It flattens fragments and handles directives (@include, @skip) to create clean field objects for optimization purposes, making it particularly valuable for performance optimization in GraphQL applications.

Package Information

  • Package Name: graphql-fields
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install graphql-fields

Core Imports

const graphqlFields = require('graphql-fields');

For ES modules:

import graphqlFields from 'graphql-fields';

Basic Usage

const graphqlFields = require('graphql-fields');

// In a GraphQL resolver
const resolver = (root, args, context, info) => {
  const requestedFields = graphqlFields(info);
  console.log(requestedFields);
  
  // Use field map to optimize data fetching
  const topLevelFields = Object.keys(requestedFields);
  return fetch(`/api/user?fields=${topLevelFields.join(',')}`);
};

Capabilities

Field Map Generation

Transforms GraphQLResolveInfo into a structured field map, flattening all fragments and handling directives.

/**
 * Transforms GraphQLResolveInfo into a structured field map
 * @param {Object} info - GraphQL resolver info object containing fieldNodes/fieldASTs
 * @param {Object} [obj={}] - Base object to merge results into
 * @param {Object} [options={}] - Configuration options
 * @param {boolean} [options.processArguments=false] - Enable argument processing
 * @param {string[]} [options.excludedFields=[]] - Array of field names to exclude
 * @returns {Object} Flattened map of requested fields
 */
function graphqlFields(info, obj, options);

Argument Processing

When enabled via options, extracts and processes field arguments into the result map.

const fieldsWithArgs = graphqlFields(info, {}, { processArguments: true });

Usage Example:

// GraphQL query with arguments:
// user(id: "123") { 
//   profile(includePrivate: true) { 
//     firstName 
//   } 
// }

const fields = graphqlFields(info, {}, { processArguments: true });
// Result:
// {
//   "profile": {
//     "firstName": {},
//     "__arguments": [
//       {
//         "includePrivate": {
//           "kind": "BooleanValue",
//           "value": true
//         }
//       }
//     ]
//   }
// }

Field Exclusion

Excludes specific fields from the result map, commonly used to filter out __typename.

const fieldsWithoutTypename = graphqlFields(info, {}, { 
  excludedFields: ['__typename'] 
});

Usage Example:

// Exclude __typename from results
const cleanFields = graphqlFields(info, {}, { 
  excludedFields: ['__typename'] 
});

Fragment Flattening

Automatically resolves and flattens both inline fragments and named fragments.

Input Query:

{
  user {
    ...UserProfile
    profile {
      firstName
    }
  }
}

fragment UserProfile on User {
  id
  email
  profile {
    lastName
  }
}

Output:

{
  "profile": {
    "firstName": {},
    "lastName": {}
  },
  "email": {},
  "id": {}
}

Directive Processing

Handles @include and @skip directives, excluding fields based on directive conditions.

Input Query:

{
  user {
    id
    email @include(if: $includeEmail)
    profile @skip(if: $skipProfile) {
      firstName
    }
  }
}

Behavior:

  • Fields with @include(if: false) are excluded
  • Fields with @skip(if: true) are excluded
  • Directive conditions are evaluated from query variables

Types

/**
 * @typedef {Object} GraphQLFieldsOptions
 * @property {boolean} [processArguments=false] - Enable argument processing
 * @property {string[]} [excludedFields=[]] - Array of field names to exclude
 */

/**
 * @typedef {Object} ArgumentValue
 * @property {string} kind - The GraphQL argument kind (e.g., 'StringValue', 'IntValue', 'Variable')
 * @property {*} value - The resolved argument value
 */

/**
 * @typedef {Object.<string, ArgumentValue>} ProcessedArgument
 * Object mapping argument names to their processed values
 */

Field Map Structure:

  • Basic fields: { "fieldName": {} }
  • Nested fields: { "parentField": { "childField": {} } }
  • With arguments: { "fieldName": { "__arguments": ProcessedArgument[] } }

Advanced Usage

REST API Optimization

Use field maps to optimize REST API calls based on requested GraphQL fields:

const resolver = async (root, args, context, info) => {
  const fields = graphqlFields(info);
  const requestedFields = Object.keys(fields);
  
  // Only fetch needed fields from REST API
  const response = await fetch(
    `/api/users/${args.id}?fields=${requestedFields.join(',')}`
  );
  
  return response.json();
};

Database Query Optimization

Optimize database queries by selecting only requested fields:

const resolver = async (root, args, context, info) => {
  const fields = graphqlFields(info);
  const hasProfile = 'profile' in fields;
  const hasAddressBook = 'addressBook' in fields;
  
  let query = 'SELECT id, email FROM users WHERE id = ?';
  const joins = [];
  
  if (hasProfile) {
    joins.push('LEFT JOIN profiles ON users.id = profiles.user_id');
  }
  if (hasAddressBook) {
    joins.push('LEFT JOIN address_books ON users.id = address_books.user_id');
  }
  
  if (joins.length > 0) {
    query += ' ' + joins.join(' ');
  }
  
  return database.query(query, [args.id]);
};

Nested Field Analysis

Analyze nested field requirements for complex data fetching:

const resolver = async (root, args, context, info) => {
  const fields = graphqlFields(info);
  
  // Check which profile fields are requested
  if (fields.profile) {
    const profileFields = Object.keys(fields.profile);
    console.log('Requested profile fields:', profileFields);
    
    // Conditional data fetching based on nested fields
    if (profileFields.includes('displayName')) {
      // Fetch display name specific data
    }
    if (profileFields.includes('email')) {
      // Fetch email specific data
    }
  }
};

Error Handling

The function handles malformed or missing input gracefully:

  • Returns empty object {} if no valid fields are found
  • Handles missing AST structures without throwing exceptions
  • Safely processes fragments that may not exist in the fragment map
  • Gracefully handles missing or invalid directive arguments