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 🙏

© 2025 – Pkg Stats / Ryan Hefner

fetch-gql

v1.2.1

Published

Zero-dependency, typed, simplistic and monadic-ish GraphQL client

Downloads

14

Readme

Fetch GraphQL data

A zero-dependency, typed GraphQL client library built on top of fetch that provides monadic-ish responses for the tiny extra but of safety.

Same, but with bullets:

  • zero-dependencies, built entirely on top of fetch
  • execute GraphQL queries and mutations with type-safe variables and responses
  • handle responses explicitly in a monadic-ish way for the extra runtime safety

Install

The package is hosted at npm

npm install --save fetch-gql

Usage

Basic usage

The most basic usage example is to create a GraphQL client instance, define some query/mutation types, execute them and handle the response.

import createClient from 'fetch-gql'

const client = createClient({
  url: '<your-graphql-endpoint-url>'
})

type GetUserQuery = { user: { id: number; username: string } }
type GetUserQueryVariables = { id: number }
const getUserQuery = `
  query getUser(id: Int!) {
    user(id: $id) {
      id
      username
    }
  }
`

const response = await client.query<GetUserQuery, GetUserQueryVariables>({
  query: getUserQuery,
  variables: { id: 1 } // type checked agains GetUserQueryVariables
})

response.match({
  ok: data => { // data is of type GetUserQuery
    const { user } = data
    console.log(user.id, user.username)
  },
  err: errors => { // errors is of type GraphQLError[]
    // handle errors
  }
})

For details on the .match() and the rest of the response-handling API check out the explicit response handling point.

Custom error types

The GraphQL spec defines a default error shape that looks like this in a JSON response:

{
  "errors": [
    {
      "message": "Name for character with ID 1002 could not be fetched.",
      "locations": [{ "line": 6, "column": 7 }],
      "path": ["hero", "heroFriends", 1, "name"]
    }
  ]
}

Accordingly, fetch-gql defines a default GraphQL error type which looks like this:

type GraphQLError = {
  message: string
  locations: { line: number; column: number }[]
  path: (string | number)[]
}

But what if your server returns a custom error type? Whether your server follows the GraphQL error spec guidelines of utilising an extensions field which is a map of additional error details, or it returns a fully customized error type - fetch-gql has you covered!

When creating a new GraphQL client you can provide the error type that you expect to be returned from the server. The client will then provide type-safety when handling errors!

import createClient, { GraphQLError } from 'fetch-gql'

type ServerErrorCode =
  | 'auth/wrong-password'
  | 'api/not-found'
  | 'api/duplicate-key'

// If the server follows the spec guidelines
// simply extend the default error type with
// a custom typed _extensions_ field
type ExtendedGraphQLError = GraphQLError & {
  extensions: {
    code: ServerErrorCode
  }
}

// If the server returns a fully customized error type
// simply define the expected error type
type CustomGraphQLError = {
  message: string
  code: ServerErrorCode
}

const guidelinesClient = createClient<ExtendedGraphQLError>({ /* client config */ })
const response = await guidelinesClient.query<Query, QueryVariables>({ /* query config */ })
response.err(errors => { }) // errors is of type ExtendedGraphQLError[]

const customErrorClient = createClient<CustomGraphQLError>({ /* client config */ })
const response = await customErrorClient.query({ /* query config */ })
response.err(errors => { }) // errors is of type CustomGraphQLError[]

Explicit response handling

In order to provide an extra bit of safety, fetch-gql exposes a monadic-ish API for handling the response of the GraphQL query or mutation. If you are not acquinted with that style of programming don't worry it's really simple and easy to use.

Each query/mutation executed via the client returns a response of type GraphQLResponse<TData, TError> where TData is the type of the data returned on a successful request and TError is the type of an error returned on a non-successful request. fetch-gql provides the following API for handling both cases:

const response = await client.query({ /* query config */ })

// get a boolean indicating whether the response contains data
response.isOk

// get a boolean indicating whether the response contains error(s)
response.isErr

// execute the provided function when the response contains data,
// providing said data as an argument
// if the response does not contain data the function is not executed
response.ok(data => { })

// execute the provided function when the response contains error(s),
// providing said error(s) as an argument
// if the response does not contain error(s) the function is not executed
response.err(errors => { })

// groups the .ok() and .err() in a single endpoint
response.match({
  ok: data => { },
  err: errors => { }
})

// maps the response data, when available, to another shape _T_ and
// returns a new GraphQLResponse<T, TError> object
// if the response does not contain data the original is returned
response.mapOk(data => { })
// you can then chain one of the other functions described in this section
response.mapOk(data => { })
  .match({ ok: data => { }, err: errors => { } })

// maps the response error(s), when available, to another shape _T_ and
// returns a new GraphQLResponse<TData, T> object
// if the response does not contain error(s) the original is returned
response.mapErr(errors => { })
// you can then chain any of the other functions described in this section
response.mapErrors(errors => { })
  .match({ ok: data => { }, err: errors => { } })

Todo

  • [ ] link sample projects (git submodules?)
  • [ ] add tests
  • [ ] add nice documentation (with docusaurus?)

Contribution

Suggestions, insights, bug reports and code contributions are all welcome. File an issue or open a pull request - thank you!