Skip to main content

This version of GitHub Enterprise Server was discontinued on 2024-12-19. No patch releases will be made, even for critical security issues. For better performance, improved security, and new features, upgrade to the latest version of GitHub Enterprise Server. For help with the upgrade, contact GitHub Enterprise support.

Forming calls with GraphQL

Learn how to authenticate to the GraphQL API, then learn how to create and run queries and mutations.

Authenticating with GraphQL

You can authenticate to the GraphQL API using a personal access token, GitHub App, or OAuth app.

Authenticating with a personal access token

To authenticate with a personal access token, follow the steps in Managing your personal access tokens. The data that you are requesting will dictate which scopes or permissions you will need.

For example, select the "issues:read" permission to read all of the issues in the repositories your token has access to.

All fine-grained personal access tokens include read access to public repositories. To access public repositories with a personal access token (classic), select the "public_repo" scope.

If your token does not have the required scopes or permissions to access a resource, the API will return an error message that states the scopes or permissions your token needs.

Authenticating with a GitHub App

If you want to use the API on behalf of an organization or another user, GitHub recommends that you use a GitHub App. In order to attribute activity to your app, you can make your app authenticate as an app installation. In order to attribute app activity to a user, you can make your app authenticate on behalf of a user. In both cases, you will generate a token that you can use to authenticate to the GraphQL API. For more information, see Registering a GitHub App and About authentication with a GitHub App.

Authenticating with a OAuth app

To authenticate with an OAuth token from an OAuth app, you must first authorize your OAuth app using either a web application flow or device flow. Then, you can use the access token that you received to access the API. For more information, see Creating an OAuth app and Authorizing OAuth apps.

The GraphQL endpoint

The REST API has numerous endpoints. With the GraphQL API, the endpoint remains constant, no matter what operation you perform. For GitHub Enterprise Server, that endpoint is:

http(s)://HOSTNAME/api/graphql

Communicating with GraphQL

Because GraphQL operations consist of multiline JSON, GitHub recommends using the Explorer to make GraphQL calls. You can also use curl or any other HTTP-speaking library.

In REST, HTTP verbs determine the operation performed. In GraphQL, you'll provide a JSON-encoded body whether you're performing a query or a mutation, so the HTTP verb is POST. The exception is an introspection query, which is a simple GET to the endpoint. For more information on GraphQL versus REST, see Migrating from REST to GraphQL.

To query GraphQL in a curl command, make a POST request with a JSON payload. The payload must contain a string called query:

curl -H "Authorization: bearer TOKEN" -X POST -d " \
 { \
   \"query\": \"query { viewer { login }}\" \
 } \
" http(s)://HOSTNAME/api/graphql

Note

The string value of "query" must escape newline characters or the schema will not parse it correctly. For the POST body, use outer double quotes and escaped inner double quotes.

About query and mutation operations

The two types of allowed operations in GitHub's GraphQL API are queries and mutations. Comparing GraphQL to REST, queries operate like GET requests, while mutations operate like POST/PATCH/DELETE. The mutation name determines which modification is executed.

For information about rate limiting, see Rate limits and node limits for the GraphQL API.

Queries and mutations share similar forms, with some important differences.

About queries

GraphQL queries return only the data you specify. To form a query, you must specify fields within fields (also known as nested subfields) until you return only scalars.

Queries are structured like this:

query {
  JSON-OBJECT-TO-RETURN
}

For a real-world example, see Example query.

About mutations

To form a mutation, you must specify three things:

  1. Mutation name. The type of modification you want to perform.
  2. Input object. The data you want to send to the server, composed of input fields. Pass it as an argument to the mutation name.
  3. Payload object. The data you want to return from the server, composed of return fields. Pass it as the body of the mutation name.

Mutations are structured like this:

mutation {
  MUTATION-NAME(input: {MUTATION-NAME-INPUT!}) {
    MUTATION-NAME-PAYLOAD
  }
}

The input object in this example is MutationNameInput, and the payload object is MutationNamePayload.

In the mutations reference, the listed input fields are what you pass as the input object. The listed return fields are what you pass as the payload object.

For a real-world example, see Example mutation.

Working with variables

Variables can make queries more dynamic and powerful, and they can reduce complexity when passing mutation input objects.

Note

If you're using the Explorer, make sure to enter variables in the separate Query Variables pane, and do not include the word variables before the JSON object.

Here's an example query with a single variable:

query($number_of_repos:Int!) {
  viewer {
    name
     repositories(last: $number_of_repos) {
       nodes {
         name
       }
     }
   }
}
variables {
   "number_of_repos": 3
}

There are three steps to using variables:

  1. Define the variable outside the operation in a variables object:

    variables {
       "number_of_repos": 3
    }
    

    The object must be valid JSON. This example shows a simple Int variable type, but it's possible to define more complex variable types, such as input objects. You can also define multiple variables here.

  2. Pass the variable to the operation as an argument:

    query($number_of_repos:Int!){
    

    The argument is a key-value pair, where the key is the name starting with $ (e.g., $number_of_repos), and the value is the type (e.g., Int). Add a ! to indicate whether the type is required. If you've defined multiple variables, include them here as multiple arguments.

  3. Use the variable within the operation:

    repositories(last: $number_of_repos) {
    

    In this example, we substitute the variable for the number of repositories to retrieve. We specify a type in step 2 because GraphQL enforces strong typing.

This process makes the query argument dynamic. We can now simply change the value in the variables object and keep the rest of the query the same.

Using variables as arguments lets you dynamically update values in the variables object without changing the query.

Example query

Let's walk through a more complex query and put this information in context.

The following query looks up the octocat/Hello-World repository, finds the 20 most recent closed issues, and returns each issue's title, URL, and first 5 labels:

query {
  repository(owner:"octocat", name:"Hello-World") {
    issues(last:20, states:CLOSED) {
      edges {
        node {
          title
          url
          labels(first:5) {
            edges {
              node {
                name
              }
            }
          }
        }
      }
    }
  }
}

Looking at the composition line by line:

  • query {

    Because we want to read data from the server, not modify it, query is the root operation. (If you don't specify an operation, query is also the default.)

  • repository(owner:"octocat", name:"Hello-World") {

    To begin the query, we want to find a repository object. The schema validation indicates this object requires an owner and a name argument.

  • issues(last:20, states:CLOSED) {

    To account for all issues in the repository, we call the issues object. (We could query a single issue on a repository, but that would require us to know the number of the issue we want to return and provide it as an argument.)

    Some details about the issues object:

    • The docs tell us this object has the type IssueConnection.
    • Schema validation indicates this object requires a last or first number of results as an argument, so we provide 20.
    • The docs also tell us this object accepts a states argument, which is an IssueState enum that accepts OPEN or CLOSED values. To find only closed issues, we give the states key a value of CLOSED.
  • edges {

    We know issues is a connection because it has the IssueConnection type. To retrieve data about individual issues, we have to access the node via edges.

  • node {

    Here we retrieve the node at the end of the edge. The IssueConnection docs indicate the node at the end of the IssueConnection type is an