2019-08-06 17:37:58 -04:00
# graphql.js
> GitHub GraphQL API client for browsers and Node
[](https://www.npmjs.com/package/@octokit/graphql )
2020-05-15 15:25:57 -04:00
[](https://github.com/octokit/graphql.js/actions?query=workflow%3ATest+branch%3Amaster)
2019-08-06 17:37:58 -04:00
[](https://greenkeeper.io/)
<!-- toc -->
- [Usage ](#usage )
2020-05-15 15:25:57 -04: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 with GitHub Enterprise ](#use-with-github-enterprise )
- [Use custom `@octokit/request` instance ](#use-custom-octokitrequest-instance )
2019-08-06 17:37:58 -04:00
- [Errors ](#errors )
2020-05-15 15:25:57 -04:00
- [Partial responses ](#partial-responses )
2019-08-06 17:37:58 -04:00
- [Writing tests ](#writing-tests )
- [License ](#license )
<!-- tocstop -->
## Usage
2020-05-15 15:25:57 -04: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-08-06 17:37:58 -04:00
``` js
2020-05-15 15:25:57 -04:00
const { graphql } = require ( "@octokit/graphql" ) ;
// or: import { graphql } from "@octokit/graphql";
```
</td></tr>
</tbody>
</table>
### Send a simple query
``` js
const { repository } = await graphql (
`
{
repository(owner: "octokit", name: "graphql.js") {
issues(last: 3) {
edges {
node {
title
}
}
2019-08-06 17:37:58 -04:00
}
}
}
2020-05-15 15:25:57 -04:00
` ,
{
headers : {
authorization : ` token secret123 ` ,
} ,
2019-08-06 17:37:58 -04:00
}
2020-05-15 15:25:57 -04:00
) ;
2019-08-06 17:37:58 -04:00
```
2020-05-15 15:25:57 -04: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-08-06 17:37:58 -04:00
``` js
2020-05-15 15:25:57 -04:00
const graphqlWithAuth = graphql . defaults ( {
headers : {
authorization : ` token secret123 ` ,
} ,
} ) ;
const { repository } = await graphqlWithAuth ( `
{
repository(owner: "octokit", name: "graphql.js") {
issues(last: 3) {
2019-08-06 17:37:58 -04:00
edges {
node {
title
}
}
}
}
}
2020-05-15 15:25:57 -04:00
` ) ;
2019-08-06 17:37:58 -04:00
```
2020-05-15 15:25:57 -04: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-08-06 17:37:58 -04:00
``` js
2020-05-15 15:25:57 -04: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-08-06 17:37:58 -04:00
2020-05-15 15:25:57 -04:00
const { repository } = await graphqlWithAuth (
` {
repository(owner: "octokit", name: "graphql.js") {
issues(last: 3) {
edges {
node {
title
}
}
}
}
} `
) ;
2019-08-06 17:37:58 -04:00
```
2020-05-15 15:25:57 -04:00
### Variables
2019-08-06 17:37:58 -04:00
2020-05-15 15:25:57 -04:00
⚠️ 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-08-06 17:37:58 -04:00
``` js
2020-05-15 15:25:57 -04: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-08-06 17:37:58 -04:00
}
}
}
2020-05-15 15:25:57 -04:00
} ` , {
owner : 'octokit' ,
repo : 'graphql.js'
headers : {
authorization : ` token secret123 `
}
2019-08-06 17:37:58 -04:00
}
2020-05-15 15:25:57 -04:00
} )
2019-08-06 17:37:58 -04:00
```
2020-05-15 15:25:57 -04:00
### Pass query together with headers and variables
2019-08-06 17:37:58 -04:00
``` js
2020-05-15 15:25:57 -04:00
const { graphql } = require ( '@octokit/graphql' )
2019-08-06 17:37:58 -04: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-05-15 15:25:57 -04:00
### Use with GitHub Enterprise
2019-08-06 17:37:58 -04:00
``` js
2020-05-15 15:25:57 -04:00
let { graphql } = require ( "@octokit/graphql" ) ;
graphql = graphql . defaults ( {
baseUrl : "https://github-enterprise.acme-inc.com/api" ,
2019-08-06 17:37:58 -04:00
headers : {
2020-05-15 15:25:57 -04:00
authorization : ` token secret123 ` ,
} ,
} ) ;
const { repository } = await graphql ( `
{
repository(owner: "acme-project", name: "acme-repo") {
issues(last: 3) {
edges {
node {
title
}
}
}
}
2019-08-06 17:37:58 -04:00
}
2020-05-15 15:25:57 -04:00
` ) ;
```
### 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 ) ;
} ,
} ,
} ) ;
const myGraphql = withCustomRequest ( myRequest ) ;
await request ( "/" ) ;
await myGraphql ( `
{
repository(owner: "acme-project", name: "acme-repo") {
issues(last: 3) {
edges {
node {
title
}
2019-08-06 17:37:58 -04:00
}
}
}
}
2020-05-15 15:25:57 -04:00
` ) ;
// requestCounter is now 2
2019-08-06 17:37:58 -04: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-05-15 15:25:57 -04:00
let { graphql } = require ( "@octokit/graphql" ) ;
graphqlt = graphql . defaults ( {
2019-08-06 17:37:58 -04:00
headers : {
2020-05-15 15:25:57 -04:00
authorization : ` token secret123 ` ,
} ,
} ) ;
2019-08-06 17:37:58 -04:00
const query = ` {
viewer {
bioHtml
}
2020-05-15 15:25:57 -04:00
} ` ;
2019-08-06 17:37:58 -04:00
try {
2020-05-15 15:25:57 -04:00
const result = await graphql ( query ) ;
2019-08-06 17:37:58 -04:00
} catch ( error ) {
// server responds with
// {
// "data": null,
// "errors": [{
// "message": "Field 'bioHtml' doesn't exist on type 'User'",
// "locations": [{
// "line": 3,
// "column": 5
// }]
// }]
// }
2020-05-15 15:25:57 -04: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-08-06 17:37:58 -04: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-05-15 15:25:57 -04:00
let { graphql } = require ( "@octokit/graphql" ) ;
graphql = graphql . defaults ( {
2019-08-06 17:37:58 -04:00
headers : {
2020-05-15 15:25:57 -04:00
authorization : ` token secret123 ` ,
} ,
} ) ;
2019-08-06 17:37:58 -04:00
const query = ` {
repository(name: "probot", owner: "probot") {
name
ref(qualifiedName: "master") {
target {
... on Commit {
history(first: 25, after: "invalid cursor") {
nodes {
message
}
}
}
}
}
}
2020-05-15 15:25:57 -04:00
} ` ;
2019-08-06 17:37:58 -04:00
try {
2020-05-15 15:25:57 -04:00
const result = await graphql ( query ) ;
2019-08-06 17:37:58 -04:00
} catch ( error ) {
// server responds with
2020-05-15 15:25:57 -04: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-08-06 17:37:58 -04: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-05-15 15:25:57 -04:00
const assert = require ( "assert" ) ;
const fetchMock = require ( "fetch-mock/es5/server" ) ;
2019-08-06 17:37:58 -04:00
2020-05-15 15:25:57 -04:00
const { graphql } = require ( "@octokit/graphql" ) ;
2019-08-06 17:37:58 -04:00
2020-05-15 15:25:57 -04:00
graphql ( "{ viewer { login } }" , {
2019-08-06 17:37:58 -04:00
headers : {
2020-05-15 15:25:57 -04:00
authorization : "token secret123" ,
2019-08-06 17:37:58 -04:00
} ,
request : {
2020-05-15 15:25:57 -04: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-08-06 17:37:58 -04:00
```
## License
[MIT ](LICENSE )