Skip to content

GitHub GraphQL API client for browsers and Node

License

Notifications You must be signed in to change notification settings

octokit/graphql.js

Repository files navigation

graphql.js

GitHub GraphQL API client for browsers and Node

@latest Build Status Greenkeeper

Usage

Browsers

Load @octokit/graphql directly from cdn.pika.dev

<script type="module">
  import { endpoint } from "https://cdn.pika.dev/@octokit/graphql";
</script>
Node

Install with npm install @octokit/graphql

const { graphql } = require("@octokit/graphql");
// or: 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`
    }
  }
);

⚠️ 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 { graphql } = require('@octokit/graphql')
const { lastIssues } = 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`
    }
  }
})

Create two new clients and set separate default configs for them.

const graphql1 = require("@octokit/graphql").defaults({
  headers: {
    authorization: `token secret123`
  }
});

const graphql2 = require("@octokit/graphql").defaults({
  headers: {
    authorization: `token foobar`
  }
});

Create two clients, the second inherits config from the first.

const graphql1 = require("@octokit/graphql").defaults({
  headers: {
    authorization: `token secret123`
  }
});

const graphql2 = graphql1.defaults({
  headers: {
    "user-agent": "my-user-agent/v1.2.3"
  }
});

Create a new client with default options and run query

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

Pass query together with headers and variables

const { graphql } = require('@octokit/graphql')
const { lastIssues } = 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

let { graphql } = require("@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
          }
        }
      }
    }
  }
`);

Errors

In case of a GraphQL error, error.message is set to the first error from the response’s errors array. All errors can be accessed at error.errors. error.request has the request options such as query, variables and headers set for easier debugging.

let { graphql } = require("@octokit/graphql");
graphqlt = graphql.defaults({
  headers: {
    authorization: `token secret123`
  }
});
const query = `{
  viewer {
    bioHtml
  }
}`;

try {
  const result = await graphql(query);
} catch (error) {
  // server responds with
  // {
  // 	"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'
}

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

let { graphql } = require("@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

const assert = require("assert");
const fetchMock = require("fetch-mock/es5/server");

const { graphql } = require("@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