2019-11-19 20:48:29 +08:00
# graphql.js
> GitHub GraphQL API client for browsers and Node
[](https://www.npmjs.com/package/@octokit/graphql)
[](https://travis-ci.com/octokit/graphql.js)
[](https://greenkeeper.io/)
<!-- toc -->
- [Usage ](#usage )
2020-01-20 05:29:54 +08:00
- [Send a simple query ](#send-a-simple-query )
- [Authentication ](#authentication )
- [Variables ](#variables )
- [Pass query together with headers and variables ](#pass-query-together-with-headers-and-variables )
- [Use your own `@octokit/request` instance ](# )
2019-11-19 20:48:29 +08:00
- [Errors ](#errors )
2020-01-20 05:29:54 +08:00
- [Partial responses ](#partial-responses )
2019-11-19 20:48:29 +08:00
- [Writing tests ](#writing-tests )
- [License ](#license )
<!-- tocstop -->
## Usage
2020-01-20 05:29:54 +08:00
< table >
< tbody valign = top align = left >
< tr > < th >
Browsers
< / th > < td width = 100% >
Load `@octokit/graphql` directly from [cdn.pika.dev ](https://cdn.pika.dev )
```html
< script type = "module" >
import { endpoint } from "https://cdn.pika.dev/@octokit/graphql";
< / script >
```
< / td > < / tr >
< tr > < th >
Node
< / th > < td >
Install with < code > npm install @octokit/graphql </ code >
2019-11-19 20:48:29 +08:00
```js
2020-01-20 05:29:54 +08:00
const { graphql } = require("@octokit/graphql");
// or: import { graphql } from "@octokit/graphql";
2019-11-19 20:48:29 +08:00
```
2020-01-20 05:29:54 +08:00
< / td > < / tr >
< / tbody >
< / table >
### Send a simple query
2019-11-19 20:48:29 +08:00
```js
2020-01-20 05:29:54 +08:00
const { repository } = await graphql(
`
{
repository(owner: "octokit", name: "graphql.js") {
issues(last: 3) {
edges {
node {
title
}
2019-11-19 20:48:29 +08:00
}
}
}
}
2020-01-20 05:29:54 +08:00
`,
{
2019-11-19 20:48:29 +08:00
headers: {
authorization: `token secret123`
}
}
2020-01-20 05:29:54 +08:00
);
2019-11-19 20:48:29 +08:00
```
2020-01-20 05:29:54 +08:00
### Authentication
The simplest way to authenticate a request is to set the `Authorization` header, e.g. to a [personal access token ](https://github.com/settings/tokens/ ).
2019-11-19 20:48:29 +08:00
```js
2020-01-20 05:29:54 +08:00
const graphqlWithAuth = graphql.defaults({
2019-11-19 20:48:29 +08:00
headers: {
authorization: `token secret123`
}
2020-01-20 05:29:54 +08:00
});
const { repository } = await graphqlWithAuth(`
{
repository(owner: "octokit", name: "graphql.js") {
issues(last: 3) {
edges {
node {
title
}
}
}
}
2019-11-19 20:48:29 +08:00
}
2020-01-20 05:29:54 +08:00
`);
2019-11-19 20:48:29 +08:00
```
2020-01-20 05:29:54 +08:00
For more complex authentication strategies such as GitHub Apps or Basic, we recommend the according authentication library exported by [`@octokit/auth` ](https://github.com/octokit/auth.js ).
2019-11-19 20:48:29 +08:00
```js
2020-01-20 05:29:54 +08:00
const { createAppAuth } = require("@octokit/auth-app");
const auth = createAppAuth({
id: process.env.APP_ID,
privateKey: process.env.PRIVATE_KEY,
installationId: 123
});
const graphqlWithAuth = graphql.defaults({
request: {
hook: auth.hook
2019-11-19 20:48:29 +08:00
}
2020-01-20 05:29:54 +08:00
});
2019-11-19 20:48:29 +08:00
2020-01-20 05:29:54 +08:00
const { repository } = await graphqlWithAuth(
`{
repository(owner: "octokit", name: "graphql.js") {
issues(last: 3) {
edges {
node {
title
}
}
}
}
}`
);
2019-11-19 20:48:29 +08:00
```
2020-01-20 05:29:54 +08:00
### Variables
⚠️ Do not use [template literals ](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals ) in the query strings as they make your code vulnerable to query injection attacks (see [#2 ](https://github.com/octokit/graphql.js/issues/2 )). Use variables instead:
2019-11-19 20:48:29 +08:00
```js
2020-01-20 05:29:54 +08:00
const { lastIssues } = await graphql(`query lastIssues($owner: String!, $repo: String!, $num: Int = 3) {
repository(owner:$owner, name:$repo) {
issues(last:$num) {
edges {
node {
title
}
2019-11-19 20:48:29 +08:00
}
}
}
2020-01-20 05:29:54 +08:00
}`, {
owner: 'octokit',
repo: 'graphql.js'
headers: {
authorization: `token secret123`
}
2019-11-19 20:48:29 +08:00
}
2020-01-20 05:29:54 +08:00
})
2019-11-19 20:48:29 +08:00
```
2020-01-20 05:29:54 +08:00
### Pass query together with headers and variables
2019-11-19 20:48:29 +08:00
```js
2020-01-20 05:29:54 +08:00
const { graphql } = require('@octokit/graphql')
2019-11-19 20:48:29 +08:00
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`
}
})
```
2020-01-20 05:29:54 +08:00
### Use with GitHub Enterprise
2019-11-19 20:48:29 +08:00
```js
2020-01-20 05:29:54 +08:00
let { graphql } = require("@octokit/graphql");
graphql = graphql.defaults({
baseUrl: "https://github-enterprise.acme-inc.com/api",
2019-11-19 20:48:29 +08:00
headers: {
authorization: `token secret123`
}
2020-01-20 05:29:54 +08:00
});
const { repository } = await graphql(`
{
repository(owner: "acme-project", name: "acme-repo") {
issues(last: 3) {
edges {
node {
title
}
}
}
}
}
`);
```
### Use custom `@octokit/request` instance
```js
const { request } = require("@octokit/request");
const { withCustomRequest } = require("@octokit/graphql");
let requestCounter = 0
const myRequest = request.defaults({
headers: {
authentication: 'token secret123'
},
request: {
hook(request, options) {
requestCounter++
return request(options)
}
}
2019-11-19 20:48:29 +08:00
})
2020-01-20 05:29:54 +08:00
const myGraphql = withCustomRequest(myRequest)
await request('/')
await myGraphql(`
{
repository(owner: "acme-project", name: "acme-repo") {
issues(last: 3) {
edges {
node {
title
}
2019-11-19 20:48:29 +08:00
}
}
}
}
2020-01-20 05:29:54 +08:00
`);
// requestCounter is now 2
2019-11-19 20:48:29 +08:00
```
## 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.
```js
2020-01-20 05:29:54 +08:00
let { graphql } = require("@octokit/graphql");
graphqlt = graphql.defaults({
2019-11-19 20:48:29 +08:00
headers: {
authorization: `token secret123`
}
2020-01-20 05:29:54 +08:00
});
2019-11-19 20:48:29 +08:00
const query = `{
viewer {
bioHtml
}
2020-01-20 05:29:54 +08:00
}`;
2019-11-19 20:48:29 +08:00
try {
2020-01-20 05:29:54 +08:00
const result = await graphql(query);
2019-11-19 20:48:29 +08:00
} catch (error) {
// server responds with
// {
// "data": null,
// "errors": [{
// "message": "Field 'bioHtml' doesn't exist on type 'User'",
// "locations": [{
// "line": 3,
// "column": 5
// }]
// }]
// }
2020-01-20 05:29:54 +08:00
console.log("Request failed:", error.request); // { query, variables: {}, headers: { authorization: 'token secret123' } }
console.log(error.message); // Field 'bioHtml' doesn't exist on type 'User'
2019-11-19 20:48:29 +08:00
}
```
## 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`
```js
2020-01-20 05:29:54 +08:00
let { graphql } = require("@octokit/graphql");
graphql = graphql.defaults({
2019-11-19 20:48:29 +08:00
headers: {
authorization: `token secret123`
}
2020-01-20 05:29:54 +08:00
});
2019-11-19 20:48:29 +08:00
const query = `{
repository(name: "probot", owner: "probot") {
name
ref(qualifiedName: "master") {
target {
... on Commit {
history(first: 25, after: "invalid cursor") {
nodes {
message
}
}
}
}
}
}
2020-01-20 05:29:54 +08:00
}`;
2019-11-19 20:48:29 +08:00
try {
2020-01-20 05:29:54 +08:00
const result = await graphql(query);
2019-11-19 20:48:29 +08:00
} catch (error) {
// server responds with
2020-01-20 05:29:54 +08:00
// {
// "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 } }
2019-11-19 20:48:29 +08:00
}
```
## Writing tests
You can pass a replacement for [the built-in fetch implementation ](https://github.com/bitinn/node-fetch ) as `request.fetch` option. For example, using [fetch-mock ](http://www.wheresrhys.co.uk/fetch-mock/ ) works great to write tests
```js
2020-01-20 05:29:54 +08:00
const assert = require("assert");
const fetchMock = require("fetch-mock/es5/server");
2019-11-19 20:48:29 +08:00
2020-01-20 05:29:54 +08:00
const { graphql } = require("@octokit/graphql");
2019-11-19 20:48:29 +08:00
2020-01-20 05:29:54 +08:00
graphql("{ viewer { login } }", {
2019-11-19 20:48:29 +08:00
headers: {
2020-01-20 05:29:54 +08:00
authorization: "token secret123"
2019-11-19 20:48:29 +08:00
},
request: {
2020-01-20 05:29:54 +08:00
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: {} };
2019-11-19 20:48:29 +08:00
})
}
2020-01-20 05:29:54 +08:00
});
2019-11-19 20:48:29 +08:00
```
## License
[MIT ](LICENSE )