graphql-request

Minimal GraphQL client supporting Node and browsers for scripts or simple a...

README

graphql-request


Minimal GraphQL client supporting Node and browsers for scripts or simple apps

GitHub Action npm version


  - Features
  - Install
  - Usage
  - Community
  - Examples
      - Set endpoint
    - [Passing more options to fetch](#passing-more-options-to-fetch)
    - Error handling
    - [Using require instead of import](#using-require-instead-of-import)
    - [Cookie support for node](#cookie-support-for-node)
    - [Using a custom fetch method](#using-a-custom-fetch-method)
    - File Upload
      - Browser
      - Node
    - Batching
    - Cancellation
    - Middleware
    - ErrorPolicy
      - None (default)
      - Ignore
      - All
  - FAQ
    - [Why do I have to install graphql?](#why-do-i-have-to-install-graphql)
    - [Do I need to wrap my GraphQL documents inside the gql template exported by graphql-request?](#do-i-need-to-wrap-my-graphql-documents-inside-the-gql-template-exported-by-graphql-request)
    - [What's the difference between graphql-request, Apollo and Relay?](#whats-the-difference-between-graphql-request-apollo-and-relay)


Features


- Most simple & lightweight GraphQL client
- Promise-based API (works with async / await)
- TypeScript support
- Isomorphic (works with Node / browsers)

Install


  1. ```sh
  2. npm add graphql-request graphql
  3. ```

Quickstart


Send a GraphQL query with a single line of code. ▶️ Try it out.

  1. ```js
  2. import { request, gql } from 'graphql-request'

  3. const query = gql`
  4.   {
  5.     company {
  6.       ceo
  7.     }
  8.     roadster {
  9.       apoapsis_au
  10.     }
  11.   }
  12. `

  13. request('https://api.spacex.land/graphql/', query).then((data) => console.log(data))
  14. ```

Usage


  1. ```js
  2. import { request, GraphQLClient } from 'graphql-request'

  3. // Run GraphQL queries/mutations using a static function
  4. request(endpoint, query, variables).then((data) => console.log(data))

  5. // ... or create a GraphQL client instance to send requests
  6. const client = new GraphQLClient(endpoint, { headers: {} })
  7. client.request(query, variables).then((data) => console.log(data))
  8. ```

You can also use the single argument function variant:

  1. ```js
  2. request({
  3.   url: endpoint,
  4.   document: query,
  5.   variables: variables,
  6.   requestHeaders: headers,
  7. }).then((data) => console.log(data))
  8. ```

Node Version Support


We only officially support LTS Node versions. We also make an effort to support two additional versions:

1. The latest even Node version if it is not LTS already.
2. The odd Node version directly following the latest even version.

You are free to try using other versions of Node (e.g. 13.x) with graphql-request but at your own risk.

Community


Get typed GraphQL Queries with GraphQL Code Generator


graphql-request@^5 supports TypedDocumentNode, the typed counterpart of graphql's DocumentNode.

Installing and configuring GraphQL Code Generator requires a few steps in order to get end-to-end typed GraphQL operations using the providedgraphql() helper:

  1. ```ts
  2. import request from 'graphql-request'
  3. import { graphql } from './gql/gql'

  4. const getMovieQueryDocument = graphql(/* GraphQL */ `
  5.   query getMovie($title: String!) {
  6.     Movie(title: $title) {
  7.       releaseDate
  8.       actors {
  9.         name
  10.       }
  11.     }
  12.   }
  13. `)

  14. const data = await request(
  15.   'https://api.graph.cool/simple/v1/cixos23120m0n0173veiiwrjr',
  16.   getMovieQueryDocument,
  17.   // variables are type-checked!
  18.   { title: 'Inception' }
  19. )

  20. // `data.Movie` is typed!
  21. ```


Visit GraphQL Code Generator's dedicated guide to get started: https://www.the-guild.dev/graphql/codegen/docs/guides/react-vue.

Examples


Authentication via HTTP header


  1. ```js
  2. import { GraphQLClient, gql } from 'graphql-request'

  3. async function main() {
  4.   const endpoint = 'https://api.graph.cool/simple/v1/cixos23120m0n0173veiiwrjr'

  5.   const graphQLClient = new GraphQLClient(endpoint, {
  6.     headers: {
  7.       authorization: 'Bearer MY_TOKEN',
  8.     },
  9.   })

  10.   const query = gql`
  11.     {
  12.       Movie(title: "Inception") {
  13.         releaseDate
  14.         actors {
  15.           name
  16.         }
  17.       }
  18.     }
  19.   `

  20.   const data = await graphQLClient.request(query)
  21.   console.log(JSON.stringify(data, undefined, 2))
  22. }

  23. main().catch((error) => console.error(error))
  24. ```


Incrementally setting headers


If you want to set headers after the GraphQLClient has been initialised, you can use the setHeader() or setHeaders() functions.

  1. ```js
  2. import { GraphQLClient } from 'graphql-request'

  3. const client = new GraphQLClient(endpoint)

  4. // Set a single header
  5. client.setHeader('authorization', 'Bearer MY_TOKEN')

  6. // Override all existing headers
  7. client.setHeaders({
  8.   authorization: 'Bearer MY_TOKEN',
  9.   anotherheader: 'header_value',
  10. })
  11. ```

Set endpoint


If you want to change the endpoint after the GraphQLClient has been initialised, you can use the setEndpoint() function.

  1. ```js
  2. import { GraphQLClient } from 'graphql-request'

  3. const client = new GraphQLClient(endpoint)

  4. client.setEndpoint(newEndpoint)
  5. ```

passing-headers-in-each-request


It is possible to pass custom headers for each request. request() and rawRequest() accept a header object as the third parameter

  1. ```js
  2. import { GraphQLClient } from 'graphql-request'

  3. const client = new GraphQLClient(endpoint)

  4. const query = gql`
  5.   query getMovie($title: String!) {
  6.     Movie(title: $title) {
  7.       releaseDate
  8.       actors {
  9.         name
  10.       }
  11.     }
  12.   }
  13. `

  14. const variables = {
  15.   title: 'Inception',
  16. }

  17. const requestHeaders = {
  18.   authorization: 'Bearer MY_TOKEN',
  19. }

  20. // Overrides the clients headers with the passed values
  21. const data = await client.request(query, variables, requestHeaders)
  22. ```

Passing dynamic headers to the client


It's possible to recalculate the global client headers dynamically before each request.
To do that, pass a function that returns the headers to the headers property when creating a new GraphQLClient.

  1. ```js
  2. import { GraphQLClient } from 'graphql-request'

  3. const client = new GraphQLClient(endpoint, {
  4.   headers: () => ({ 'X-Sent-At-Time': Date.now() }),
  5. })

  6. const query = gql`
  7.   query getCars {
  8.     cars {
  9.       name
  10.     }
  11.   }
  12. `
  13. // Function saved in the client runs and calculates fresh headers before each request
  14. const data = await client.request(query)
  15. ```

Passing more options to fetch


  1. ```js
  2. import { GraphQLClient, gql } from 'graphql-request'

  3. async function main() {
  4.   const endpoint = 'https://api.graph.cool/simple/v1/cixos23120m0n0173veiiwrjr'

  5.   const graphQLClient = new GraphQLClient(endpoint, {
  6.     credentials: 'include',
  7.     mode: 'cors',
  8.   })

  9.   const query = gql`
  10.     {
  11.       Movie(title: "Inception") {
  12.         releaseDate
  13.         actors {
  14.           name
  15.         }
  16.       }
  17.     }
  18.   `

  19.   const data = await graphQLClient.request(query)
  20.   console.log(JSON.stringify(data, undefined, 2))
  21. }

  22. main().catch((error) => console.error(error))
  23. ```


Custom JSON serializer


If you want to use non-standard JSON types, you can use your own JSON serializer to replace JSON.parse/JSON.stringify used by the GraphQLClient.

An original use case for this feature is BigInt support:

  1. ```js
  2. import JSONbig from 'json-bigint'
  3. import { GraphQLClient, gql } from 'graphql-request'

  4. async function main() {
  5.   const jsonSerializer = JSONbig({ useNativeBigInt: true })
  6.   const graphQLClient = new GraphQLClient(endpoint, { jsonSerializer })
  7.   const data = await graphQLClient.request(
  8.     gql`
  9.       {
  10.         someBigInt
  11.       }
  12.     `
  13.   )
  14.   console.log(typeof data.someBigInt) // if >MAX_SAFE_INTEGER then 'bigint' else 'number'
  15. }
  16. ```

Using GraphQL Document variables


  1. ```js
  2. import { request, gql } from 'graphql-request'

  3. async function main() {
  4.   const endpoint = 'https://api.graph.cool/simple/v1/cixos23120m0n0173veiiwrjr'

  5.   const query = gql`
  6.     query getMovie($title: String!) {
  7.       Movie(title: $title) {
  8.         releaseDate
  9.         actors {
  10.           name
  11.         }
  12.       }
  13.     }
  14.   `

  15.   const variables = {
  16.     title: 'Inception',
  17.   }

  18.   const data = await request(endpoint, query, variables)
  19.   console.log(JSON.stringify(data, undefined, 2))
  20. }

  21. main().catch((error) => console.error(error))
  22. ```

Making a GET request


Queries can be sent as an HTTP GET request:

  1. ```js
  2. import { GraphQLClient, gql } from 'graphql-request'

  3. async function main() {
  4.   const endpoint = 'https://api.graph.cool/simple/v1/cixos23120m0n0173veiiwrjr'

  5.   const graphQLClient = new GraphQLClient(endpoint, {
  6.     method: 'GET',
  7.     jsonSerializer: {
  8.       parse: JSON.parse,
  9.       stringify: JSON.stringify,
  10.     },
  11.   })

  12.   const query = gql`
  13.     query getMovie($title: String!) {
  14.       Movie(title: $title) {
  15.         releaseDate
  16.         actors {
  17.           name
  18.         }
  19.       }
  20.     }
  21.   `

  22.   const variables = {
  23.     title: 'Inception',
  24.   }

  25.   const data = await graphQLClient.request(query, variables)
  26.   console.log(JSON.stringify(data, undefined, 2))
  27. }

  28. main().catch((error) => console.error(error))
  29. ```

GraphQL Mutations


  1. ```js
  2. import { GraphQLClient, gql } from 'graphql-request'

  3. async function main() {
  4.   const endpoint = 'https://api.graph.cool/simple/v1/cixos23120m0n0173veiiwrjr'

  5.   const graphQLClient = new GraphQLClient(endpoint, {
  6.     headers: {
  7.       authorization: 'Bearer MY_TOKEN',
  8.     },
  9.   })

  10.   const mutation = gql`
  11.     mutation AddMovie($title: String!, $releaseDate: Int!) {
  12.       insert_movies_one(object: { title: $title, releaseDate: $releaseDate }) {
  13.         title
  14.         releaseDate
  15.       }
  16.     }
  17.   `

  18.   const variables = {
  19.     title: 'Inception',
  20.     releaseDate: 2010,
  21.   }
  22.   const data = await graphQLClient.request(mutation, variables)

  23.   console.log(JSON.stringify(data, undefined, 2))
  24. }

  25. main().catch((error) => console.error(error))
  26. ```


Error handling


  1. ```js
  2. import { request, gql } from 'graphql-request'

  3. async function main() {
  4.   const endpoint = 'https://api.graph.cool/simple/v1/cixos23120m0n0173veiiwrjr'

  5.   const query = gql`
  6.     {
  7.       Movie(title: "Inception") {
  8.         releaseDate
  9.         actors {
  10.           fullname # "Cannot query field 'fullname' on type 'Actor'. Did you mean 'name'?"
  11.         }
  12.       }
  13.     }
  14.   `

  15.   try {
  16.     const data = await request(endpoint, query)
  17.     console.log(JSON.stringify(data, undefined, 2))
  18.   } catch (error) {
  19.     console.error(JSON.stringify(error, undefined, 2))
  20.     process.exit(1)
  21.   }
  22. }

  23. main().catch((error) => console.error(error))
  24. ```


Using require instead of import


  1. ```js
  2. const { request, gql } = require('graphql-request')

  3. async function main() {
  4.   const endpoint = 'https://api.graph.cool/simple/v1/cixos23120m0n0173veiiwrjr'

  5.   const query = gql`
  6.     {
  7.       Movie(title: "Inception") {
  8.         releaseDate
  9.         actors {
  10.           name
  11.         }
  12.       }
  13.     }
  14.   `

  15.   const data = await request(endpoint, query)
  16.   console.log(JSON.stringify(data, undefined, 2))
  17. }

  18. main().catch((error) => console.error(error))
  19. ```

Cookie support for node


  1. ```sh
  2. npm install fetch-cookie
  3. ```

  1. ```js
  2. require('fetch-cookie/node-fetch')(require('node-fetch'))

  3. import { GraphQLClient, gql } from 'graphql-request'

  4. async function main() {
  5.   const endpoint = 'https://api.graph.cool/simple/v1/cixos23120m0n0173veiiwrjr'

  6.   const graphQLClient = new GraphQLClient(endpoint, {
  7.     headers: {
  8.       authorization: 'Bearer MY_TOKEN',
  9.     },
  10.   })

  11.   const query = gql`
  12.     {
  13.       Movie(title: "Inception") {
  14.         releaseDate
  15.         actors {
  16.           name
  17.         }
  18.       }
  19.     }
  20.   `

  21.   const data = await graphQLClient.rawRequest(query)
  22.   console.log(JSON.stringify(data, undefined, 2))
  23. }

  24. main().catch((error) => console.error(error))
  25. ```


Using a custom fetch method


  1. ```sh
  2. npm install fetch-cookie
  3. ```

  1. ```js
  2. import { GraphQLClient, gql } from 'graphql-request'
  3. import crossFetch from 'cross-fetch'

  4. async function main() {
  5.   const endpoint = 'https://api.graph.cool/simple/v1/cixos23120m0n0173veiiwrjr'

  6.   // a cookie jar scoped to the client object
  7.   const fetch = require('fetch-cookie')(crossFetch)
  8.   const graphQLClient = new GraphQLClient(endpoint, { fetch })

  9.   const query = gql`
  10.     {
  11.       Movie(title: "Inception") {
  12.         releaseDate
  13.         actors {
  14.           name
  15.         }
  16.       }
  17.     }
  18.   `

  19.   const data = await graphQLClient.rawRequest(query)
  20.   console.log(JSON.stringify(data, undefined, 2))
  21. }

  22. main().catch((error) => console.error(error))
  23. ```

Receiving a raw response


The request method will return the data or errors key from the response.
If you need to access the extensions key you can use the rawRequest method:

  1. ```js
  2. import { rawRequest, gql } from 'graphql-request'

  3. async function main() {
  4.   const endpoint = 'https://api.graph.cool/simple/v1/cixos23120m0n0173veiiwrjr'

  5.   const query = gql`
  6.     {
  7.       Movie(title: "Inception") {
  8.         releaseDate
  9.         actors {
  10.           name
  11.         }
  12.       }
  13.     }
  14.   `

  15.   const { data, errors, extensions, headers, status } = await rawRequest(endpoint, query)
  16.   console.log(JSON.stringify({ data, errors, extensions, headers, status }, undefined, 2))
  17. }

  18. main().catch((error) => console.error(error))
  19. ```

File Upload


Browser


  1. ```js
  2. import { request } from 'graphql-request'

  3. const UploadUserAvatar = gql`
  4.   mutation uploadUserAvatar($userId: Int!, $file: Upload!) {
  5.     updateUser(id: $userId, input: { avatar: $file })
  6.   }
  7. `

  8. request('/api/graphql', UploadUserAvatar, {
  9.   userId: 1,
  10.   file: document.querySelector('input#avatar').files[0],
  11. })
  12. ```

Node


  1. ```js
  2. import { createReadStream } from 'fs'
  3. import { request } from 'graphql-request'

  4. const UploadUserAvatar = gql`
  5.   mutation uploadUserAvatar($userId: Int!, $file: Upload!) {
  6.     updateUser(id: $userId, input: { avatar: $file })
  7.   }
  8. `

  9. request('/api/graphql', UploadUserAvatar, {
  10.   userId: 1,
  11.   file: createReadStream('./avatar.img'),
  12. })
  13. ```


Batching


It is possible with graphql-request to use batching via thebatchRequests() function. Example available at examples/batching-requests.ts

  1. ```ts
  2. import { batchRequests } from 'graphql-request'
  3. ;(async function () {
  4.   const endpoint = 'https://api.spacex.land/graphql/'

  5.   const query1 = /* GraphQL */ `
  6.     query ($id: ID!) {
  7.       capsule(id: $id) {
  8.         id
  9.         landings
  10.       }
  11.     }
  12.   `

  13.   const query2 = /* GraphQL */ `
  14.     {
  15.       rockets(limit: 10) {
  16.         active
  17.       }
  18.     }
  19.   `

  20.   const data = await batchRequests(endpoint, [
  21.     { document: query1, variables: { id: 'C105' } },
  22.     { document: query2 },
  23.   ])
  24.   console.log(JSON.stringify(data, undefined, 2))
  25. })().catch((error) => console.error(error))
  26. ```

Cancellation


It is possible to cancel a request using an AbortController signal.

You can define the signal in the GraphQLClient constructor:

  1. ```ts
  2. const abortController = new AbortController()

  3. const client = new GraphQLClient(endpoint, { signal: abortController.signal })
  4. client.request(query)

  5. abortController.abort()
  6. ```

You can also set the signal per request (this will override an existing GraphQLClient signal):

  1. ```ts
  2. const abortController = new AbortController()

  3. const client = new GraphQLClient(endpoint)
  4. client.request({ document: query, signal: abortController.signal })

  5. abortController.abort()
  6. ```

In Node environment, AbortController is supported since version v14.17.0.
For Node.js v12 you can use abort-controller polyfill.

  1. ```
  2. import 'abort-controller/polyfill'

  3. const abortController = new AbortController()
  4. ```

Middleware


It's possible to use a middleware to pre-process any request or handle raw response.

Request middleware example (set actual auth token to each request):

  1. ```ts
  2. function middleware(request: RequestInit) {
  3.   const token = getToken()
  4.   return {
  5.     ...request,
  6.     headers: { ...request.headers, 'x-auth-token': token },
  7.   }
  8. }

  9. const client = new GraphQLClient(endpoint, { requestMiddleware: middleware })
  10. ```

It's also possible to use an async function as a request middleware. The resolved data will be passed to the request:

  1. ```ts
  2. async function middleware(request: RequestInit) {
  3.   const token = await getToken()
  4.   return {
  5.     ...request,
  6.     headers: { ...request.headers, 'x-auth-token': token },
  7.   }
  8. }

  9. const client = new GraphQLClient(endpoint, { requestMiddleware: middleware })
  10. ```

Response middleware example (log request trace id if error caused):

  1. ```ts
  2. function middleware(response: Response<unknown>) {
  3.   if (response.errors) {
  4.     const traceId = response.headers.get('x-b3-traceid') || 'unknown'
  5.     console.error(
  6.       `[${traceId}] Request error:
  7.         status ${response.status}
  8.         details: ${response.errors}`
  9.     )
  10.   }
  11. }

  12. const client = new GraphQLClient(endpoint, { responseMiddleware: middleware })
  13. ```

ErrorPolicy


By default GraphQLClient will throw when an error is received. However, sometimes you still want to resolve the (partial) data you received.
You can define errorPolicy in the GraphQLClient constructor.

  1. ```ts
  2. const client = new GraphQLClient(endpoint, { errorPolicy: 'all' })
  3. ```

None (default)


Allow no errors at all. If you receive a GraphQL error the client will throw.

Ignore


Ignore incoming errors and resolve like no errors occurred

All


Return both the errors and data, only works with rawRequest.

FAQ


Why do I have to install graphql?


graphql-request uses methods exposed by the graphql package to handle some internal logic. On top of that, for TypeScript users, some types are used from the graphql package to provide better typings.

Do I need to wrap my GraphQL documents inside the gql template exported by graphql-request?


No. It is there for convenience so that you can get the tooling support like prettier formatting and IDE syntax highlighting. You can use gql from graphql-tag if you need it for some reason too.

What's the difference between graphql-request, Apollo and Relay?


graphql-request is the most minimal and simplest to use GraphQL client. It's perfect for small scripts or simple apps.

Compared to GraphQL clients like Apollo or Relay, graphql-request doesn't have a built-in cache and has no integrations for frontend frameworks. The goal is to keep the package and API as minimal as possible.