1
0
mirror of synced 2025-12-23 11:54:18 -05:00
Files
docs/content/graphql/guides/forming-calls-with-graphql.md
jmarlena ed5a109e48 [MERGES AFTER GHAE CB ships] Remove "public repository" wording for GHAE (#18008)
* Empty commit

* updated beta note for GHAE

* more GHAE update + resolve conflict

* more GHAE updates + prepare for screenshots

* Apply suggestions from code review

Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com>

* address remaining review comments

* Revise "About GitHub AE" (#17679)

* add screenshots to the Configuring article

* reworked to have a separate GHAE section

* list numbering

* more work on screenshots and conditions

* add GHAE screenshots in article

* review screenshots in article

* added more screenshots and updated more articles

* screenshot madness

* fix liquid versioning

* refactor the ghae script

* [GHAE CB/Feb 22]: Add article about data residency for GitHub AE (#17847)

* add missing GHAE versioning to article

* move screenshots to GHAE asset directory

* forgot to change the path for these two images

* replace CBB screenshot + add better screenshot

* [GHAE CB/Feb 22]: Document upgrades for GitHub AE (#17848)

* Version article for GitHub AE

* Replace unused variable

* Incorporate reviewer feedback

* Update intro

Co-authored-by: Ethan P <56270045+ethanpalm@users.noreply.github.com>

* [GHAE] Enable IP allow list (#17691)

* Notes for CC

* Updat permission leves chart

* Add updated article to further reading

* Update gated feature callout with GitHub AE

* Version "Managing allowed IP addresses for your organization" for AE

* Update images

* Update "Restricting network traffic to your enterprise" with new procedures

* remove todo note

* Update audited actions

* Update info about Premium Runners

* Use reusable for Premium Runners

* Change "Premium Runners" to "AE hosted runners"

* Incorporate reviewer feedback

* Use correct reusable

* Version reusable correctly

* [Feb 22] GHAE: Code scanning beta (#17830)

* Add "github-ae" to all the frontmatter

* GHAE-ify the reusables

* Add some more changes

* Re-use some content

* 🔪 Semmle links

* Revert change re "--external-repository-token" in the CodeQL runner

* Update CodeQL runner token scopes

* Update two screenshots

* Remove mention of GitHub.com from AE + other fixes

* Apply suggestions from code review

Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>

* Use `product_name` variable instead of `product_location`

* Remove confusing phrase

* [Feb 22] GHAE: Code scanning API and webhook docs (#17883)

* Version API and webhook docs

* Actually add versioning for GHAE

* Fix anchor

* [TEMPORARY] Preview for API endpoints

* Revert API previews

* Update procedure step

Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>

* Update docs for AzureAD Group SCIM support in GHAE (#17892)

* Version out reference to public Pages site for GHAE

* [GHAE CB] SMTP bootstrapping flow (#17888)

* draft

* update with AE conntent

* update with tons of versioning

* remove that  lie

* fill out the rest of these steps

* update with correct versioning

* more edits

* add images

* reversion most of ae article

* fix versioning

* format correctlly

* words matter

* last image

* update with permmissions

* update versioning

* add link

* apply feedback ❤️

* update with differrent spacing

* update with feedback

* more feedback

* Temporary GHAE release notes for consumables beta launch (#17859)

* Create release-notes.md

* Add frontmatter

* Add to index file

* Update github-ae-release-notes.md

* Add release notes from Google Doc

* Update finalized docs links that have been reviewed

* OAuth device flow link update

* version for AE

* few fixes

* Update content/admin/overview/github-ae-release-notes.md

* small edits

* whoops

* commit

* update with different links

* used wrong reusable

* fix more brokenness

* Update repository-references.js

* Update repository-references.js

Co-authored-by: Meg Bird <megbird@github.com>
Co-authored-by: Kevin Heis <heiskr@users.noreply.github.com>

* [GHAE] Audit public repos (#17917)

* verifying what we mean by public

* Apply suggestions from code review

* Update content/developers/apps/installing-github-apps.md

Co-authored-by: Laura Coursen <lecoursen@github.com>

* fixing placememnt of liquid conditional

Co-authored-by: Laura Coursen <lecoursen@github.com>

* GHAE packages beta (#17786)

Co-authored-by: jmarlena <6732600+jmarlena@users.noreply.github.com>
Co-authored-by: Martin Lopes <martin389@github.com>

* Batch #1 of changes

* Batch #2

* getting started article update

* Update GraphQL article

* Only public repository reference

* Just update the link

* Update endpoint title to use "internal"

* fix build error

* placeholder update for updating `public_repo` scope in UI

* Remove unncessary versioning for now

* fix broken links

* Add REST API files

* Remove versioning since the endpoint "title" didn't get updated

* Version out the no scope option

* Evergreen rewrite

Co-Authored-By: Aaron Harpole <507570+aharpole@users.noreply.github.com>

* Add back public key

* Apply suggestions from code review

Co-authored-by: Alex Slepak <ams11@github.com>
Co-authored-by: Aaron Harpole <aharpole@github.com>

* Remove versioning and add evergreen rewrite

* Just the way it was before

* fix confusing legacy bit

* Apply suggestions from code review

Co-authored-by: Alex Slepak <ams11@github.com>

* Apply suggestions from code review

Co-authored-by: Sarah Edwards <skedwards88@github.com>

* Movin' on up

* no versioning needed

* internal gists exist!

* Doesn't need versioning

* Keep this as-is

* Remove screenshots 💥

* Apply suggestions from code review

Co-authored-by: Sarah Edwards <skedwards88@github.com>

* Never updated REST API docs with different endpoint name

* No versioning needed

* Merge conflict fix: Updated this article from main branch

* Apply suggestions from code review

* Revert "Add REST API files"

This reverts commit 1a8ad0adca47daaa1bf9d1b3642c4ec073564996.

* checkout changes from main

* Update OpenAPI Descriptions (#18103)

Co-authored-by: Matt Pollard <mattpollard@users.noreply.github.com>
Co-authored-by: Ethan Palm <56270045+ethanpalm@users.noreply.github.com>
Co-authored-by: mchammer01 <42146119+mchammer01@users.noreply.github.com>
Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com>
Co-authored-by: shati-patel <shati-patel@github.com>
Co-authored-by: Sarah Schneider <sarahs@github.com>
Co-authored-by: skedwards88 <skedwards88@github.com>
Co-authored-by: Sarah Schneider <sarahs@users.noreply.github.com>
Co-authored-by: Melanie Yarbrough <11952755+myarb@users.noreply.github.com>
Co-authored-by: Felicity Chapman <felicitymay@github.com>
Co-authored-by: Laura Coursen <lecoursen@github.com>
Co-authored-by: Meg Bird <megbird@github.com>
Co-authored-by: Kevin Heis <heiskr@users.noreply.github.com>
Co-authored-by: Leona B. Campbell <3880403+runleonarun@users.noreply.github.com>
Co-authored-by: Martin Lopes <martin389@github.com>
Co-authored-by: Aaron Harpole <507570+aharpole@users.noreply.github.com>
Co-authored-by: Alex Slepak <ams11@github.com>
Co-authored-by: Aaron Harpole <aharpole@github.com>
Co-authored-by: github-openapi-bot <69533958+github-openapi-bot@users.noreply.github.com>
2021-03-04 21:31:30 -08:00

16 KiB

title, intro, redirect_from, versions
title intro redirect_from versions
Forming calls with GraphQL Learn how to authenticate to the GraphQL API, then learn how to create and run queries and mutations.
/v4/guides/forming-calls
/graphql/guides/forming-calls
free-pro-team enterprise-server github-ae
* * *

Authenticating with GraphQL

To communicate with the GraphQL server, you'll need an OAuth token with the right scopes.

Follow the steps in "Creating a personal access token" to create a token. The scopes you require depends on the type of data you're trying to request. For example, select the User scopes to request user data. If you need access to repository information, select the appropriate Repository scopes.

{% if currentVersion == "free-pro-team@latest" %}

To match the behavior of the GraphQL Explorer, request the following scopes:

{% else %}

The following scopes are recommended:

{% endif %}

user{% if currentVersion != "github-ae@latest" %}
public_repo{% endif %}
repo
repo_deployment
repo:status
read:repo_hook
read:org
read:public_key
read:gpg_key

The API notifies you if a resource requires a specific scope.

The GraphQL endpoint

The REST API has numerous endpoints; the GraphQL API has a single endpoint:

{% data variables.product.graphql_url_pre %}

The endpoint remains constant no matter what operation you perform.

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 using cURL, make a POST request with a JSON payload. The payload must contain a string called query:

curl -H "Authorization: bearer <em>token</em>" -X POST -d " \
 { \
   \"query\": \"query { viewer { login }}\" \
 } \
" {% data variables.product.graphql_url_code %}

{% tip %}

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.

{% endtip %}

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 "GraphQL resource limitations."

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 objects 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 {
  mutationName(input: {MutationNameInput!}) {
    MutationNamePayload
  }
}

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 %}

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.

{% endnote %}

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.

  1. 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.

  1. 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 Issue object.

  • Now that we know we're retrieving an Issue object, we can look at the docs and specify the fields we want to return:

    title
    url
    labels(first:5) {
      edges {
        node {
          name
        }
      }
    }
    

    Here we specify the title, url, and labels fields of the Issue object.

    The labels field has the type LabelConnection. As with the issues object, because labels is a connection, we must travel its edges to a connected node: the label object. At the node, we can specify the label object fields we want to return, in this case, name.

You may notice that running this query on the Octocat's {% if currentVersion != "github-ae@latest" %}public{% endif %} Hello-World repository won't return many labels. Try running it on one of your own repositories that does use labels, and you'll likely see a difference.

Example mutation

Mutations often require information that you can only find out by performing a query first. This example shows two operations:

  1. A query to get an issue ID.
  2. A mutation to add an emoji reaction to the issue.
query FindIssueID {
  repository(owner:"octocat", name:"Hello-World") {
    issue(number:349) {
      id
    }
  }
}

mutation AddReactionToIssue {
  addReaction(input:{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}) {
    reaction {
      content
    }
    subject {
      id
    }
  }
}

{% tip %}

Although you can include a query and a mutation in the same Explorer window if you give them names (FindIssueID and AddReactionToIssue in this example), the operations will be executed as separate calls to the GraphQL endpoint. It's not possible to perform a query at the same time as a mutation, or vice versa.

{% endtip %}

Let's walk through the example. The task sounds simple: add an emoji reaction to an issue.

So how do we know to begin with a query? We don't, yet.

Because we want to modify data on the server (attach an emoji to an issue), we begin by searching the schema for a helpful mutation. The reference docs show the addReaction mutation, with this description: Adds a reaction to a subject. Perfect!

The docs for the mutation list three input fields:

  • clientMutationId (String)
  • subjectId (ID!)
  • content (ReactionContent!)

The !s indicate that subjectId and content are required fields. A required content makes sense: we want to add a reaction, so we'll need to specify which emoji to use.

But why is subjectId required? It's because the subjectId is the only way to identify which issue in which repository to react to.

This is why we start this example with a query: to get the ID.

Let's examine the query line by line:

  • query FindIssueID {

    Here we're performing a query, and we name it FindIssueID. Note that naming a query is optional; we give it a name here so that we can include it in same Explorer window as the mutation.

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

    We specify the repository by querying the repository object and passing owner and name arguments.

  • issue(number:349) {

    We specify the issue to react to by querying the issue object and passing a number argument.

  • id

    This is where we retrieve the id of https://github.com/octocat/Hello-World/issues/349 to pass as the subjectId.

When we run the query, we get the id: MDU6SXNzdWUyMzEzOTE1NTE=

{% tip %}

Note: The id returned in the query is the value we'll pass as the subjectID in the mutation. Neither the docs nor schema introspection will indicate this relationship; you'll need to understand the concepts behind the names to figure this out.

{% endtip %}

With the ID known, we can proceed with the mutation:

  • mutation AddReactionToIssue {

    Here we're performing a mutation, and we name it AddReactionToIssue. As with queries, naming a mutation is optional; we give it a name here so we can include it in the same Explorer window as the query.

  • addReaction(input:{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}) {

    Let's examine this line:

    • addReaction is the name of the mutation.
    • input is the required argument key. This will always be input for a mutation.
    • {subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY} is the required argument value. This will always be an input object (hence the curly braces) composed of input fields (subjectId and content in this case) for a mutation.

    How do we know which value to use for the content? The addReaction docs tell us the content field has the type ReactionContent, which is an enum because only certain emoji reactions are supported on GitHub issues. These are the allowed values for reactions (note some values differ from their corresponding emoji names):

    {% data reusables.repositories.reaction_list %}

  • The rest of the call is composed of the payload object. This is where we specify the data we want the server to return after we've performed the mutation. These lines come from the addReaction docs, which three possible return fields:

    • clientMutationId (String)
    • reaction (Reaction!)
    • subject (Reactable!)

    In this example, we return the two required fields (reaction and subject), both of which have required subfields (respectively, content and id).

When we run the mutation, this is the response:

{
  "data": {
    "addReaction": {
      "reaction": {
        "content": "HOORAY"
      },
      "subject": {
        "id": "MDU6SXNzdWUyMTc5NTQ0OTc="
      }
    }
  }
}

That's it! Check out your reaction to the issue by hovering over the 🎉 to find your username.

One final note: when you pass multiple fields in an input object, the syntax can get unwieldy. Moving the fields into a variable can help. Here's how you could rewrite the original mutation using a variable:

mutation($myVar:AddReactionInput!) {
  addReaction(input:$myVar) {
    reaction {
      content
    }
    subject {
      id
    }
  }
}
variables {
  "myVar": {
    "subjectId":"MDU6SXNzdWUyMTc5NTQ0OTc=",
    "content":"HOORAY"
  }
}

{% note %}

You may notice that the content field value in the earlier example (where it's used directly in the mutation) does not have quotes around HOORAY, but it does have quotes when used in the variable. There's a reason for this:

  • When you use content directly in the mutation, the schema expects the value to be of type ReactionContent, which is an enum, not a string. Schema validation will throw an error if you add quotes around the enum value, as quotes are reserved for strings.
  • When you use content in a variable, the variables section must be valid JSON, so the quotes are required. Schema validation correctly interprets the ReactionContent type when the variable is passed into the mutation during execution.

For more information on the difference between enums and strings, see the official GraphQL spec.

{% endnote %}

Further reading

There is a lot more you can do when forming GraphQL calls. Here are some places to look next: