CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-graphql-fields

Turns GraphQLResolveInfo into a map of the requested fields

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/graphql-fields@2.0.x
Publish Source
CLI
Badge
tessl/npm-graphql-fields badge