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

@explorer02/api-playground

v2.1.2

Published

API Playground component

Readme

@explorer02/api-playground

A React component library for interactive GraphQL & REST API exploration.

npm version Live Demo


Features

  • 14 built-in template types covering static data display, query/mutation execution, form-driven workflows, REST API testing, streaming (SSE, WebSocket, GraphQL Subscriptions), schema introspection, and more
  • Monaco Editor integration with syntax highlighting for JSON, GraphQL, JavaScript, and TypeScript
  • Apollo Cache Viewer for inspecting and editing the Apollo Client normalized cache
  • Form-driven queries and mutations with validation, initial values, and configurable field layouts
  • REST API client with support for GET, POST, PUT, DELETE, and PATCH methods
  • Server-Sent Events (SSE) streaming with real-time event display and connection statistics
  • WebSocket client for bidirectional messaging with message log and connection management
  • GraphQL Subscriptions over WebSocket (graphql-ws protocol) with live message streaming
  • Schema introspection via the SCHEMA_VIEWER template
  • Execution timing displayed for query and mutation operations
  • Query history for previously executed operations
  • Keyboard shortcuts including Cmd/Ctrl+Enter to execute queries and mutations
  • Fully configurable via TypeScript with exported types for every template config

Installation

npm install @explorer02/api-playground

Peer Dependencies

The following peer dependencies must be installed in your project:

  • react (>=18.0.0)
  • react-dom (>=18.0.0)
  • @apollo/client (>=3.8.0)
  • graphql (>=16.0.0)

CSS Imports

Important: You must import the stylesheet for the playground to render correctly. Without this import, components will appear unstyled.

import '@explorer02/api-playground/dist/styles/index.css';

Quick Start

import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';
import { APIPlayground, Template } from '@explorer02/api-playground';
import '@explorer02/api-playground/dist/styles/index.css';

const client = new ApolloClient({
  uri: 'https://your-graphql-endpoint.com/graphql',
  cache: new InMemoryCache(),
});

const config = [
  {
    id: 'example',
    type: Template.STATIC_DATA,
    title: 'Example Data',
    data: { message: 'Hello, world!' },
  },
];

function App() {
  return (
    <ApolloProvider client={client}>
      <APIPlayground config={config} />
    </ApolloProvider>
  );
}

Templates

STATIC_DATA

Displays a static JSON object or string in a Monaco editor. Useful for showing configuration data, environment info, or any read-only content.

Config type:

type StaticDataConfig = {
  id: string;
  title: string;
  type: Template.STATIC_DATA;
  data: object | string;
  language?: Language; // default: JSON. Options: JSON, GRAPHQL, JAVASCRIPT, TYPESCRIPT
  readOnly?: boolean;
};

Example:

{
  id: 'current_user',
  type: Template.STATIC_DATA,
  title: 'Current User',
  data: {
    name: 'Ajay Bhardwaj',
    role: 'Developer',
    preferences: { theme: 'light', language: 'en' },
  },
}

You can also display a raw string with a specific language for syntax highlighting:

{
  id: 'schema_info',
  type: Template.STATIC_DATA,
  title: 'Schema Info',
  data: `type Character { id: ID! name: String! }`,
  language: Language.GRAPHQL,
  readOnly: true,
}

STATIC_DATA template


CACHE_VIEWER

Inspects the Apollo Client normalized cache. Displays the full cache contents and allows editing.

Config type:

type CacheViewerConfig = {
  id: string;
  title: string;
  type: Template.CACHE_VIEWER;
  client: ApolloClient<NormalizedCacheObject>;
  readOnly?: boolean;
};

Example:

{
  id: 'apollo_cache',
  type: Template.CACHE_VIEWER,
  title: 'Cache Viewer',
  client: apolloClient,
}

CACHE_VIEWER template


QUERY_EXECUTOR

A free-form GraphQL query editor. Provides input panes for the query string and variables, and displays the response in a separate output pane.

Config type:

type QueryExecutorConfig = {
  id: string;
  title: string;
  type: Template.QUERY_EXECUTOR;
  client: ApolloClient<NormalizedCacheObject>;
  config?: {
    input?: { title?: string };
    variable?: { title?: string };
    output?: { title?: string; readOnly?: boolean };
  };
};

Example:

{
  id: 'query_executor',
  type: Template.QUERY_EXECUTOR,
  title: 'Query Executor',
  client: apolloClient,
  config: {
    input: { title: 'GraphQL Query' },
    variable: { title: 'Variables (JSON)' },
    output: { title: 'Response', readOnly: true },
  },
}

QUERY_EXECUTOR template


MUTATION_EXECUTOR

Similar to QUERY_EXECUTOR but oriented toward mutations. Supports preset mutations that users can select from a dropdown.

Config type:

type MutationExecutorConfig = {
  id: string;
  title: string;
  type: Template.MUTATION_EXECUTOR;
  client: ApolloClient<NormalizedCacheObject>;
  config?: {
    input?: { title?: string };
    variable?: { title?: string };
    output?: { title?: string; readOnly?: boolean };
  };
  mutations?: { id: string; label: string; node: DocumentNode; variables: object }[];
};

Example:

{
  id: 'mutation_executor',
  type: Template.MUTATION_EXECUTOR,
  title: 'Mutation Executor',
  client: apolloClient,
  mutations: [
    {
      id: 'create_location',
      label: 'Create Location (page 1)',
      node: CREATE_LOCATION_MUTATION,
      variables: { page: 1 },
    },
  ],
}

MUTATION_EXECUTOR template


CUSTOM_QUERY

Executes a predefined GraphQL query with a form-driven input. Users fill in form fields, and the component maps form values to query variables.

Config type:

type CustomQueryConfig = {
  id: string;
  title: string;
  type: Template.CUSTOM_QUERY;
  client: ApolloClient<NormalizedCacheObject>;
  query: DocumentNode;
  fieldConfigMap: FieldConfigMap;
  formLayout: FormLayout;
  getVariables: (formValues: FormValues) => object;
  validator?: (formValues: FormValues) => FormErrors;
  initialValues?: FormValues;
  outputConfig?: { readOnly?: boolean };
};

Example:

import { FieldConfigMapBuilder, FormFieldType } from '@explorer02/api-playground';

const fieldConfigMap = new FieldConfigMapBuilder()
  .addField({
    id: 'page',
    label: 'Page No.',
    type: FormFieldType.NUMBER,
    required: true,
    placeholder: 'Enter page (1-42)',
  })
  .build();

{
  id: 'custom_query',
  type: Template.CUSTOM_QUERY,
  title: 'Custom Query',
  client: apolloClient,
  query: FETCH_LOCATIONS,
  fieldConfigMap,
  formLayout: { fields: ['page'] },
  initialValues: { page: 1 },
  validator: (vals) => {
    const errors = {};
    const page = Number(vals.page);
    if (isNaN(page) || page < 1 || page > 42) errors.page = 'Page must be between 1 and 42';
    return errors;
  },
  getVariables: (obj) => ({ page: Number(obj.page) }),
  outputConfig: { readOnly: true },
}

CUSTOM_QUERY template


CUSTOM_MUTATION

Same form-driven approach as CUSTOM_QUERY but for mutations.

Config type:

type CustomMutationConfig = {
  id: string;
  title: string;
  type: Template.CUSTOM_MUTATION;
  client: ApolloClient<NormalizedCacheObject>;
  mutation: DocumentNode;
  fieldConfigMap: FieldConfigMap;
  formLayout: FormLayout;
  getVariables: (formValues: FormValues) => object;
  validator?: (formValues: FormValues) => FormErrors;
  initialValues?: FormValues;
  outputConfig?: { readOnly?: boolean };
};

Example:

{
  id: 'custom_mutation',
  type: Template.CUSTOM_MUTATION,
  title: 'Custom Mutation',
  client: apolloClient,
  mutation: CREATE_LOCATION,
  fieldConfigMap: pageFieldConfig,
  formLayout: { fields: ['page'] },
  initialValues: { page: 4 },
  getVariables: (obj) => ({ page: Number(obj.page) }),
}

CUSTOM_MUTATION template


FETCH_AND_MUTATE

A two-step workflow: first fetch data with a form-driven query, then execute a mutation using the fetched data and form values.

Config type:

type FetchAndMutateConfig = {
  id: string;
  title: string;
  type: Template.FETCH_AND_MUTATE;
  client: ApolloClient<NormalizedCacheObject>;
  fetchConfig: {
    formLayout: FormLayout;
    fieldConfigMap: FieldConfigMap;
    query: DocumentNode;
    getVariables: (formValues: FormValues) => object;
    validator?: (formValues: FormValues) => FormErrors;
    initialValues?: FormValues;
    output?: { title?: string };
    cta?: { label: string };
  };
  mutateConfig: {
    mutation: DocumentNode;
    getVariables: (formValues: FormValues, queryResponse: object) => object;
    validator?: (formValues: FormValues) => FormErrors;
    output?: { title?: string };
  };
};

Example:

{
  id: 'fetch_and_mutate',
  type: Template.FETCH_AND_MUTATE,
  title: 'Fetch And Mutate',
  client: apolloClient,
  fetchConfig: {
    fieldConfigMap: pageFieldConfig,
    formLayout: { fields: ['page'] },
    initialValues: { page: 1 },
    getVariables: (obj) => ({ page: Number(obj.page) }),
    query: FETCH_LOCATIONS,
    cta: { label: 'Fetch Locations' },
    output: { title: 'Fetch Result' },
  },
  mutateConfig: {
    mutation: UPDATE_LOCATION,
    getVariables: (formValues, queryResponse) => ({
      page: Number(formValues.page),
    }),
    output: { title: 'Mutation Result' },
  },
}

FETCH_AND_MUTATE template


NESTED_TEMPLATE

Groups multiple templates under a single sidebar entry with sub-navigation. Accepts any array of non-nested template configs.

Config type:

type NestedTemplateConfig = {
  id: string;
  title: string;
  type: Template.NESTED_TEMPLATE;
  templates: PlainTemplates[]; // any template type except NESTED_TEMPLATE
};

Example:

{
  id: 'nested_executors',
  type: Template.NESTED_TEMPLATE,
  title: 'Grouped Queries',
  templates: [
    {
      id: 'characters',
      type: Template.CUSTOM_QUERY,
      title: 'Characters',
      client: apolloClient,
      query: FETCH_CHARACTERS,
      fieldConfigMap: characterFieldConfig,
      formLayout: { fields: ['page'] },
      initialValues: { page: 1 },
      getVariables: (obj) => ({ page: Number(obj.page) }),
    },
    {
      id: 'episodes',
      type: Template.CUSTOM_QUERY,
      title: 'Episodes',
      client: apolloClient,
      query: FETCH_EPISODES,
      fieldConfigMap: episodeFieldConfig,
      formLayout: { fields: ['page'] },
      initialValues: { page: 1 },
      getVariables: (obj) => ({ page: Number(obj.page) }),
    },
  ],
}

NESTED_TEMPLATE template


CUSTOM

Renders any React component you provide. Use this when none of the built-in templates fit your needs.

Config type:

type CustomTemplateConfig = {
  id: string;
  title: string;
  type: Template.CUSTOM;
  Component: ComponentType;
};

Example:

const AboutPanel = () => (
  <div style={{ padding: '24px' }}>
    <h2>About</h2>
    <p>Custom content goes here.</p>
  </div>
);

{
  id: 'about',
  type: Template.CUSTOM,
  title: 'About',
  Component: AboutPanel,
}

CUSTOM template


SCHEMA_VIEWER

Runs an introspection query against the GraphQL endpoint and displays the full schema.

Config type:

type SchemaViewerConfig = {
  id: string;
  title: string;
  type: Template.SCHEMA_VIEWER;
  client: ApolloClient<NormalizedCacheObject>;
};

Example:

{
  id: 'schema_viewer',
  type: Template.SCHEMA_VIEWER,
  title: 'Schema',
  client: apolloClient,
}

SCHEMA_VIEWER template


REST_API

A REST API client for testing HTTP endpoints. Supports configurable default URL, method, headers, and body.

Config type:

type RestApiConfig = {
  id: string;
  title: string;
  type: Template.REST_API;
  defaultUrl?: string;
  defaultMethod?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
  defaultHeaders?: Record<string, string>;
  defaultBody?: string;
};

Example:

{
  id: 'rest_api',
  type: Template.REST_API,
  title: 'REST API',
  defaultUrl: 'https://jsonplaceholder.typicode.com/posts/1',
  defaultMethod: 'GET',
  defaultHeaders: { 'Content-Type': 'application/json' },
}

REST_API template


SSE

A Server-Sent Events (SSE) client for streaming data from an HTTP endpoint. Displays incoming events in real-time with connection statistics.

Config type:

type SseConfig = {
  id: string;
  title: string;
  type: Template.SSE;
  url?: string;
  headers?: Record<string, string>;
};

Example:

{
  id: 'sse',
  type: Template.SSE,
  title: 'SSE Stream',
  url: 'https://stream.wikimedia.org/v2/stream/recentchange',
}

REST_WEBSOCKET

A raw WebSocket client for sending and receiving messages over a WebSocket connection. Includes a message log and connection status indicator.

Config type:

type RestWebsocketConfig = {
  id: string;
  title: string;
  type: Template.REST_WEBSOCKET;
  url?: string;
};

Example:

{
  id: 'rest_websocket',
  type: Template.REST_WEBSOCKET,
  title: 'WebSocket',
  url: 'wss://ws.postman-echo.com/raw',
}

GQL_SUBSCRIPTION

Executes GraphQL subscriptions over WebSocket using the graphql-ws protocol. Provides editors for the subscription query and variables, and streams incoming messages in real-time.

Config type:

type GqlSubscriptionConfig = {
  id: string;
  title: string;
  type: Template.GQL_SUBSCRIPTION;
  wsUrl?: string;
  query?: string;
  variables?: string;
};

Example:

{
  id: 'gql_subscription',
  type: Template.GQL_SUBSCRIPTION,
  title: 'GQL Subscription',
  wsUrl: 'wss://demo-router.fly.dev/graphql',
  query: `subscription {
  currentTime {
    unixTime
  }
}`,
  variables: '{}',
}

API Reference

Exported Component

| Export | Description | | --------------- | --------------------------------------------- | | APIPlayground | Main component. Accepts APIPlaygroundProps. |

Enums

| Enum | Values | | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Template | STATIC_DATA, CACHE_VIEWER, QUERY_EXECUTOR, MUTATION_EXECUTOR, CUSTOM_QUERY, CUSTOM_MUTATION, FETCH_AND_MUTATE, NESTED_TEMPLATE, CUSTOM, SCHEMA_VIEWER, REST_API, SSE, REST_WEBSOCKET, GQL_SUBSCRIPTION | | Language | JSON, GRAPHQL, JAVASCRIPT, TYPESCRIPT | | FormFieldType | TEXT, NUMBER, JSON |

Exported Types

| Type | Description | | ------------------------ | --------------------------------------- | | APIPlaygroundProps | Props for the APIPlayground component | | TemplateConfig | Union of all template config types | | StaticDataConfig | Config for STATIC_DATA template | | CacheViewerConfig | Config for CACHE_VIEWER template | | QueryExecutorConfig | Config for QUERY_EXECUTOR template | | MutationExecutorConfig | Config for MUTATION_EXECUTOR template | | CustomQueryConfig | Config for CUSTOM_QUERY template | | CustomMutationConfig | Config for CUSTOM_MUTATION template | | FetchAndMutateConfig | Config for FETCH_AND_MUTATE template | | NestedTemplateConfig | Config for NESTED_TEMPLATE template | | CustomTemplateConfig | Config for CUSTOM template | | SchemaViewerConfig | Config for SCHEMA_VIEWER template | | RestApiConfig | Config for REST_API template | | SseConfig | Config for SSE template | | RestWebsocketConfig | Config for REST_WEBSOCKET template | | GqlSubscriptionConfig | Config for GQL_SUBSCRIPTION template |

Utilities

| Export | Description | | ----------------------- | ---------------------------------------------------------------------------------------------------------- | | FieldConfigMapBuilder | Builder class for constructing FieldConfigMap objects. Chain .addField(config) calls, then .build(). |

FieldConfigMapBuilder usage:

import { FieldConfigMapBuilder, FormFieldType } from '@explorer02/api-playground';

const fieldConfigMap = new FieldConfigMapBuilder()
  .addField({
    id: 'name',
    label: 'Name',
    type: FormFieldType.TEXT,
    required: true,
    placeholder: 'Enter name',
  })
  .addField({
    id: 'count',
    label: 'Count',
    type: FormFieldType.NUMBER,
  })
  .addField({
    id: 'metadata',
    label: 'Metadata',
    type: FormFieldType.JSON,
  })
  .build();

Keyboard Shortcuts

| Shortcut | Action | | ---------------- | -------------------------------------------- | | Cmd/Ctrl+Enter | Execute the current query or mutation | | Cmd+D | Select next occurrence (Monaco built-in) | | Cmd+F | Find in editor (Monaco built-in) | | Cmd+H | Find and replace in editor (Monaco built-in) |


Build

yarn build

The build process uses tsup for JavaScript/TypeScript bundling and sass for CSS compilation. Output is written to the dist/ directory with both ESM (.mjs) and CJS (.cjs) formats. Type declarations are emitted to types/.


License

ISC Licensed. Copyright (c) @explorer02.