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

@bernierllc/contentful-graphql-client

v1.2.0

Published

GraphQL Content API Client for flexible Contentful queries with batching and introspection

Readme

@bernierllc/contentful-graphql-client

GraphQL Content API Client for flexible Contentful queries with batching, introspection, and advanced error handling.

Features

  • Flexible GraphQL Queries - Execute custom queries with variable support
  • Query Batching - Execute multiple queries in parallel for efficiency
  • Schema Introspection - Introspect and cache GraphQL schema
  • Type-Safe - Full TypeScript support with strict typing
  • Error Handling - Enhanced error messages with query context
  • Logging - Integrated structured logging with @bernierllc/logger
  • Preview API - Support for both production and preview APIs

Installation

npm install @bernierllc/contentful-graphql-client

Quick Start

import { ContentfulGraphQLClient } from '@bernierllc/contentful-graphql-client';

// Initialize client
const client = new ContentfulGraphQLClient({
  space: 'your-space-id',
  accessToken: 'your-access-token',
  environment: 'master' // optional, defaults to 'master'
});

// Execute a query
const query = `
  query {
    blogPostCollection(limit: 10) {
      items {
        sys { id }
        title
        slug
        publishDate
      }
    }
  }
`;

const result = await client.query(query);
console.log(result);

API Documentation

Constructor

new ContentfulGraphQLClient(config)

Creates a new GraphQL client instance.

Parameters:

  • config.space (string, required) - Contentful space ID
  • config.accessToken (string, required) - Content Delivery API token
  • config.environment (string, optional) - Environment ID (default: 'master')
  • config.host (string, optional) - Custom GraphQL endpoint
  • config.timeout (number, optional) - Request timeout in ms (default: 30000)
  • config.logger (Logger, optional) - Custom logger instance
  • config.preview (boolean, optional) - Use preview API (default: false)

Example:

const client = new ContentfulGraphQLClient({
  space: 'abc123',
  accessToken: 'token-xyz',
  environment: 'staging',
  timeout: 60000
});

Methods

query<T>(query: string, variables?: object, options?: QueryOptions): Promise<T>

Execute a single GraphQL query.

Parameters:

  • query (string) - GraphQL query string
  • variables (object, optional) - Query variables
  • options (QueryOptions, optional) - Query options (operationName, requestHeaders)

Returns: Promise resolving to query result data

Example:

const query = `
  query GetBlogPost($id: String!) {
    blogPost(id: $id) {
      sys { id }
      title
      body
      author {
        name
        bio
      }
    }
  }
`;

const variables = { id: 'abc123' };
const result = await client.query(query, variables);

batchQuery<T>(queries: ContentfulGraphQLQuery[]): Promise<T[]>

Execute multiple GraphQL queries in parallel.

Parameters:

  • queries (array) - Array of query objects with query and optional variables

Returns: Promise resolving to array of results in same order as input

Example:

const queries = [
  {
    query: '{ blogPostCollection(limit: 5) { items { title } } }'
  },
  {
    query: 'query($id: String!) { author(id: $id) { name } }',
    variables: { id: 'author-123' }
  }
];

const [posts, author] = await client.batchQuery(queries);

queryWithErrors<T>(query: string, variables?: object): Promise<ContentfulGraphQLResponse<T>>

Execute a query and return full response including errors.

Parameters:

  • query (string) - GraphQL query string
  • variables (object, optional) - Query variables

Returns: Promise resolving to response object with data and optional errors

Example:

const result = await client.queryWithErrors('{ entries }');

if (result.errors) {
  console.error('GraphQL errors:', result.errors);
}

console.log('Data:', result.data);

introspectSchema(forceRefresh?: boolean): Promise<GraphQLSchema>

Introspect the GraphQL schema. Results are cached after first call.

Parameters:

  • forceRefresh (boolean, optional) - Force refresh cached schema (default: false)

Returns: Promise resolving to GraphQL schema object

Example:

const schema = await client.introspectSchema();

// Get all types
const typeMap = schema.getTypeMap();
console.log('Available types:', Object.keys(typeMap));

clearSchemaCache(): void

Clear the cached schema. Useful when schema changes.

Example:

client.clearSchemaCache();

setHeaders(headers: Record<string, string>): void

Update client headers (e.g., for changing access token).

Parameters:

  • headers (object) - Headers to merge with existing headers

Example:

client.setHeaders({
  'Authorization': 'Bearer new-token',
  'X-Custom-Header': 'custom-value'
});

getEndpoint(): string

Get the current GraphQL endpoint URL.

Returns: Endpoint URL string

Example:

const endpoint = client.getEndpoint();
console.log('GraphQL endpoint:', endpoint);

Advanced Usage

Using Custom Headers

const result = await client.query(
  '{ entries }',
  undefined,
  {
    requestHeaders: {
      'X-Contentful-User-Agent': 'my-app/1.0.0'
    }
  }
);

Using GraphQL Fragments

const query = `
  fragment PostFields on BlogPost {
    sys { id }
    title
    slug
    publishDate
  }

  query {
    blogPostCollection(limit: 10) {
      items {
        ...PostFields
      }
    }
  }
`;

const result = await client.query(query);

Pagination

const query = `
  query GetPosts($skip: Int!, $limit: Int!) {
    blogPostCollection(skip: $skip, limit: $limit, order: publishDate_DESC) {
      total
      skip
      limit
      items {
        sys { id }
        title
        publishDate
      }
    }
  }
`;

let skip = 0;
const limit = 10;
let allPosts = [];

while (true) {
  const result = await client.query(query, { skip, limit });

  allPosts.push(...result.blogPostCollection.items);

  if (result.blogPostCollection.items.length < limit) {
    break;
  }

  skip += limit;
}

Preview Mode

Use the preview API to fetch draft content:

const previewClient = new ContentfulGraphQLClient({
  space: 'your-space-id',
  accessToken: 'your-preview-token',
  environment: 'master',
  preview: true
});

const drafts = await previewClient.query('{ entries }');

Custom Logger

import { Logger, LogLevel, ConsoleTransport } from '@bernierllc/logger';

const customLogger = new Logger({
  level: LogLevel.DEBUG,
  transports: [new ConsoleTransport()],
  context: { app: 'my-app' }
});

const client = new ContentfulGraphQLClient({
  space: 'your-space-id',
  accessToken: 'your-token',
  logger: customLogger
});

Error Handling

The client provides enhanced error handling with query context:

try {
  const result = await client.query('{ invalidField }');
} catch (error) {
  console.error('Query failed:', error.message);
  console.error('Status:', error.status);
  console.error('GraphQL errors:', error.errors);
  console.error('Original error:', error.originalError);
}

MECE Principles

This package follows MECE (Mutually Exclusive, Collectively Exhaustive) principles:

Includes:

  • GraphQL query execution
  • Schema introspection
  • Type-safe query building
  • Variable interpolation
  • Fragment support
  • Query batching

Excludes:

  • ❌ Mutations (Contentful GraphQL is read-only)
  • ❌ Subscriptions (use webhooks)
  • ❌ REST API operations (use CMA/CDA clients)

TypeScript Support

Full TypeScript support with strict typing:

interface BlogPost {
  sys: { id: string };
  title: string;
  slug: string;
  publishDate: string;
}

interface BlogPostCollection {
  blogPostCollection: {
    items: BlogPost[];
    total: number;
  };
}

const result = await client.query<BlogPostCollection>(query);
// result is fully typed as BlogPostCollection

Performance Tips

  1. Use Query Batching - Execute multiple independent queries in parallel
  2. Cache Schema - Schema introspection is cached automatically
  3. Select Only Needed Fields - GraphQL allows precise field selection
  4. Use Fragments - Reuse field selections across queries
  5. Implement Pagination - Use skip and limit for large collections

License

Copyright (c) 2025 Bernier LLC

This file is licensed to the client under a limited-use license. The client may use and modify this code only within the scope of the project it was delivered for. Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.

Related Packages