@octokit/graphql vs graphql-tag vs graphql-request vs apollo-client vs urql
GraphQL Client Libraries Comparison
1 Year
@octokit/graphqlgraphql-taggraphql-requestapollo-clienturqlSimilar Packages:
What's GraphQL Client Libraries?

GraphQL client libraries facilitate communication between a client application and a GraphQL server, allowing developers to send queries and mutations in a structured manner. They handle the complexities of managing network requests, caching, and state management, enabling developers to focus on building features rather than dealing with low-level networking details. Each library offers unique features, performance characteristics, and design philosophies that cater to different use cases and preferences in web development.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
@octokit/graphql10,392,69947728.9 kB1319 days agoMIT
graphql-tag6,959,6492,332-1003 years agoMIT
graphql-request4,605,8365,954320 kB334 months agoMIT
apollo-client411,38619,487-5515 years agoMIT
urql279,5868,743135 kB342 days agoMIT
Feature Comparison: @octokit/graphql vs graphql-tag vs graphql-request vs apollo-client vs urql

Ease of Use

  • @octokit/graphql:

    @octokit/graphql is designed to be user-friendly, especially for developers familiar with GitHub's API. It simplifies the process of making requests and handling responses, allowing for quick integration with GitHub services.

  • graphql-tag:

    graphql-tag simplifies the process of writing queries by allowing developers to use template literals. This feature enhances readability and maintainability of code, especially when queries become complex.

  • graphql-request:

    graphql-request is extremely straightforward, allowing developers to make GraphQL requests with minimal setup. Its simplicity makes it ideal for quick prototypes or small applications where overhead should be minimized.

  • apollo-client:

    Apollo Client offers a rich set of features with a steep learning curve. It provides extensive documentation and a powerful developer experience, making it easier to manage complex data requirements in large applications.

  • urql:

    urql is designed with simplicity in mind, providing a straightforward API that is easy to learn. Its modular architecture allows developers to pick and choose features as needed, making it adaptable to various project requirements.

Caching Mechanism

  • @octokit/graphql:

    @octokit/graphql does not implement its own caching mechanism but relies on the underlying HTTP client. This makes it less suitable for applications that require sophisticated caching strategies.

  • graphql-tag:

    graphql-tag itself does not provide caching but is often used with Apollo Client or other libraries that handle caching. It focuses on query definition rather than data management.

  • graphql-request:

    graphql-request does not include built-in caching, which means developers need to implement their own caching strategy if needed. This can be a drawback for larger applications that require efficient data management.

  • apollo-client:

    Apollo Client features an advanced caching mechanism that allows for automatic caching of query results. This significantly improves performance by reducing the number of network requests and providing instant data access from the cache.

  • urql:

    urql offers a flexible caching strategy that can be customized according to the needs of the application. It supports both in-memory caching and more advanced strategies, making it suitable for various use cases.

Integration with Other Tools

  • @octokit/graphql:

    @octokit/graphql is tightly integrated with GitHub's ecosystem, making it the best choice for projects that heavily rely on GitHub services and APIs.

  • graphql-tag:

    graphql-tag is primarily a utility for defining queries and is often used in conjunction with other libraries like Apollo Client. It does not provide integrations on its own but enhances the query writing experience.

  • graphql-request:

    graphql-request is a standalone library and does not have built-in integrations with other tools. However, it can be easily used alongside any JavaScript framework or library, making it versatile for different setups.

  • apollo-client:

    Apollo Client integrates seamlessly with various tools and libraries, including React, Vue, and Angular. Its ecosystem includes Apollo Server and Apollo Studio, providing a comprehensive solution for building GraphQL applications.

  • urql:

    urql is designed to work well with React and other frameworks, offering plugins and extensions for enhanced functionality. Its modular approach allows for easy integration with various tools and libraries.

Community and Support

  • @octokit/graphql:

    @octokit/graphql benefits from the strong GitHub community, providing ample resources and support for developers working with GitHub's APIs.

  • graphql-tag:

    graphql-tag is widely used in conjunction with other libraries, benefiting from the community support of those libraries. Its usage is common in the GraphQL ecosystem, ensuring a good level of community engagement.

  • graphql-request:

    graphql-request has a smaller community compared to others, which may result in fewer resources and support options. However, its simplicity often means less troubleshooting is required.

  • apollo-client:

    Apollo Client has a large and active community, with extensive documentation, tutorials, and support channels available. This makes it easier for developers to find help and resources when needed.

  • urql:

    urql has a growing community and is actively maintained. While it may not be as large as Apollo's, it offers good support and documentation for developers looking to implement GraphQL in their applications.

Flexibility and Customization

  • @octokit/graphql:

    @octokit/graphql is focused on GitHub's API and does not offer much flexibility for other GraphQL endpoints. It is designed for a specific use case, which may limit its applicability in broader scenarios.

  • graphql-tag:

    graphql-tag is a utility for writing queries and does not provide flexibility on its own. However, when used with other libraries, it allows for a flexible approach to query management.

  • graphql-request:

    graphql-request is minimalistic and does not impose any structure, allowing developers to use it in any way they see fit. This flexibility is great for small projects but may require more setup for larger applications.

  • apollo-client:

    Apollo Client is highly flexible, allowing developers to customize caching strategies, network interfaces, and more. This flexibility makes it suitable for a wide range of applications, from small to enterprise-level.

  • urql:

    urql emphasizes flexibility, allowing developers to customize their GraphQL client according to their needs. Its modular architecture supports various plugins and extensions, making it adaptable for different use cases.

How to Choose: @octokit/graphql vs graphql-tag vs graphql-request vs apollo-client vs urql
  • @octokit/graphql:

    Choose @octokit/graphql if you are specifically working with GitHub's GraphQL API. It provides a tailored experience with built-in support for authentication and pagination, making it ideal for GitHub-related projects.

  • graphql-tag:

    Use graphql-tag when you want to define your GraphQL queries using template literals. This package is often used in conjunction with other libraries like Apollo Client to parse query strings into a format that can be executed against a GraphQL server.

  • graphql-request:

    Opt for graphql-request if you need a minimalistic and lightweight library for making GraphQL requests. It's perfect for small projects or when you want to keep dependencies to a minimum without sacrificing functionality.

  • apollo-client:

    Select Apollo Client for a comprehensive solution that includes advanced features like caching, state management, and a powerful ecosystem of tools. It's well-suited for complex applications that require a robust data management strategy.

  • urql:

    Choose urql for a flexible and customizable GraphQL client that emphasizes performance and simplicity. It is particularly useful for applications that require fine-tuned control over caching and data fetching strategies.

README for @octokit/graphql

graphql.js

GitHub GraphQL API client for browsers and Node

@latest Build Status

Usage

Browsers

Load @octokit/graphql directly from esm.sh

<script type="module">
  import { graphql } from "https://esm.sh/@octokit/graphql";
</script>
Node

Install with npm install @octokit/graphql

import { graphql } from "@octokit/graphql";

Send a simple query

const { repository } = await graphql(
  `
    {
      repository(owner: "octokit", name: "graphql.js") {
        issues(last: 3) {
          edges {
            node {
              title
            }
          }
        }
      }
    }
  `,
  {
    headers: {
      authorization: `token secret123`,
    },
  },
);

Authentication

The simplest way to authenticate a request is to set the Authorization header, e.g. to a personal access token.

const graphqlWithAuth = graphql.defaults({
  headers: {
    authorization: `token secret123`,
  },
});
const { repository } = await graphqlWithAuth(`
  {
    repository(owner: "octokit", name: "graphql.js") {
      issues(last: 3) {
        edges {
          node {
            title
          }
        }
      }
    }
  }
`);

For more complex authentication strategies such as GitHub Apps or Basic, we recommend the according authentication library exported by @octokit/auth.

const { createAppAuth } = await import("@octokit/auth-app");
const auth = createAppAuth({
  appId: process.env.APP_ID,
  privateKey: process.env.PRIVATE_KEY,
  installationId: 123,
});
const graphqlWithAuth = graphql.defaults({
  request: {
    hook: auth.hook,
  },
});

const { repository } = await graphqlWithAuth(
  `{
    repository(owner: "octokit", name: "graphql.js") {
      issues(last: 3) {
        edges {
          node {
            title
          }
        }
      }
    }
  }`,
);

Variables

⚠️ Do not use template literals in the query strings as they make your code vulnerable to query injection attacks (see #2). Use variables instead:

const { repository } = await graphql(
  `
    query lastIssues($owner: String!, $repo: String!, $num: Int = 3) {
      repository(owner: $owner, name: $repo) {
        issues(last: $num) {
          edges {
            node {
              title
            }
          }
        }
      }
    }
  `,
  {
    owner: "octokit",
    repo: "graphql.js",
    headers: {
      authorization: `token secret123`,
    },
  },
);

Pass query together with headers and variables

import { graphql } from("@octokit/graphql");
const { repository } = await graphql({
  query: `query lastIssues($owner: String!, $repo: String!, $num: Int = 3) {
    repository(owner: $owner, name: $repo) {
      issues(last: $num) {
        edges {
          node {
            title
          }
        }
      }
    }
  }`,
  owner: "octokit",
  repo: "graphql.js",
  headers: {
    authorization: `token secret123`,
  },
});

Use with GitHub Enterprise

import { graphql } from "@octokit/graphql";
graphql = graphql.defaults({
  baseUrl: "https://github-enterprise.acme-inc.com/api",
  headers: {
    authorization: `token secret123`,
  },
});
const { repository } = await graphql(`
  {
    repository(owner: "acme-project", name: "acme-repo") {
      issues(last: 3) {
        edges {
          node {
            title
          }
        }
      }
    }
  }
`);

Use custom @octokit/request instance

import { request } from "@octokit/request";
import { withCustomRequest } from "@octokit/graphql";

let requestCounter = 0;
const myRequest = request.defaults({
  headers: {
    authorization: "bearer secret123",
  },
  request: {
    hook(request, options) {
      requestCounter++;
      return request(options);
    },
  },
});
const myGraphql = withCustomRequest(myRequest);
await request("/");
await myGraphql(`
  {
    repository(owner: "acme-project", name: "acme-repo") {
      issues(last: 3) {
        edges {
          node {
            title
          }
        }
      }
    }
  }
`);
// requestCounter is now 2

TypeScript

@octokit/graphql is exposing proper types for its usage with TypeScript projects.

Additional Types

Additionally, GraphQlQueryResponseData has been exposed to users:

import type { GraphQlQueryResponseData } from "@octokit/graphql";

Errors

In case of a GraphQL error, error.message is set to a combined message describing all errors returned by the endpoint. All errors can be accessed at error.errors. error.request has the request options such as query, variables and headers set for easier debugging.

import { graphql, GraphqlResponseError } from "@octokit/graphql";
graphql = graphql.defaults({
  headers: {
    authorization: `token secret123`,
  },
});
const query = `{
  viewer {
    bioHtml
  }
}`;

try {
  const result = await graphql(query);
} catch (error) {
  if (error instanceof GraphqlResponseError) {
    // do something with the error, allowing you to detect a graphql response error,
    // compared to accidentally catching unrelated errors.

    // server responds with an object like the following (as an example)
    // class GraphqlResponseError {
    //  "headers": {
    //    "status": "403",
    //  },
    //  "data": null,
    //  "errors": [{
    //   "message": "Field 'bioHtml' doesn't exist on type 'User'",
    //   "locations": [{
    //    "line": 3,
    //    "column": 5
    //   }]
    //  }]
    // }

    console.log("Request failed:", error.request); // { query, variables: {}, headers: { authorization: 'token secret123' } }
    console.log(error.message); // Field 'bioHtml' doesn't exist on type 'User'
  } else {
    // handle non-GraphQL error
  }
}

Partial responses

A GraphQL query may respond with partial data accompanied by errors. In this case we will throw an error but the partial data will still be accessible through error.data

import { graphql } from "@octokit/graphql";
graphql = graphql.defaults({
  headers: {
    authorization: `token secret123`,
  },
});
const query = `{
  repository(name: "probot", owner: "probot") {
    name
    ref(qualifiedName: "master") {
      target {
        ... on Commit {
          history(first: 25, after: "invalid cursor") {
            nodes {
              message
            }
          }
        }
      }
    }
  }
}`;

try {
  const result = await graphql(query);
} catch (error) {
  // server responds with
  // {
  //   "data": {
  //     "repository": {
  //       "name": "probot",
  //       "ref": null
  //     }
  //   },
  //   "errors": [
  //     {
  //       "type": "INVALID_CURSOR_ARGUMENTS",
  //       "path": [
  //         "repository",
  //         "ref",
  //         "target",
  //         "history"
  //       ],
  //       "locations": [
  //         {
  //           "line": 7,
  //           "column": 11
  //         }
  //       ],
  //       "message": "`invalid cursor` does not appear to be a valid cursor."
  //     }
  //   ]
  // }

  console.log("Request failed:", error.request); // { query, variables: {}, headers: { authorization: 'token secret123' } }
  console.log(error.message); // `invalid cursor` does not appear to be a valid cursor.
  console.log(error.data); // { repository: { name: 'probot', ref: null } }
}

Writing tests

You can pass a replacement for the built-in fetch implementation as request.fetch option. For example, using fetch-mock works great to write tests

import assert from "assert";
import fetchMock from "fetch-mock";

import { graphql } from "@octokit/graphql";

graphql("{ viewer { login } }", {
  headers: {
    authorization: "token secret123",
  },
  request: {
    fetch: fetchMock
      .sandbox()
      .post("https://api.github.com/graphql", (url, options) => {
        assert.strictEqual(options.headers.authorization, "token secret123");
        assert.strictEqual(
          options.body,
          '{"query":"{ viewer { login } }"}',
          "Sends correct query",
        );
        return { data: {} };
      }),
  },
});

License

MIT