Technical Advisors: Working with the Sourcegraph GraphQL API

Intended Audience

This document is mainly geared towards external users of the Sourcegraph GraphQL API, not for internal Sourcegraph developers. Some external users are folks in Technical Success or even customers themselves.

What GraphQL is and isn’t

It is:

  • A query language for APIs
  • Provides exactly what you ask for. No more, no less.
    • This is called over/underfetching data
  • Strongly typed
  • Versionless

It isn’t:

  • A query language for databases
    • It isn’t a language for Graph Databases (like Neo4j)
  • A solution for world hunger…unfortunately

Anatomy of a GraphQL Query/Operation

Anatomy of a GraphQL Query/Operation

Operation Type: Query, Mutation, or Subscription. Describes the type of operation you’re trying to do.

Operation Name: Optional descriptor that identifies the operation, typically for debugging or server-side logging

Variable Definition: Dynamic parts that typically change between requests and can be defined externally or in-line

Variable Type / GraphQL Type: The data structure of the variable or of a type, as defined in the GraphQL Schema

Nullability: Determine whether or not a field or variable is allowed to be null

Fields: Building blocks that represent the data being returned

Arguments: Either pulled in from a Variable Definition or in-line, these specify key-value pairs that affect how a Field is resolved

(Inline) Fragments: Encapsulated pieces of shared query logic

Sourcegraph’s GraphQL Schema & Documentation

Sourcegraph’s GraphQL API is defined by its schema or SDL (Schema Definition Language).

Explore the Sourcegraph GraphQL API documentation here

  • These docs are auto-generated, for more details join #wg-graphql-docs
  • There are some types, fields, and fragments that exist in the API but are undocumented, raise it to that Slack channel

Setting up your GraphQL IDE

Apollo Sandbox is great for navigating through a complex GraphQL schema and has great developer experience for crafting queries

  1. Navigate to Apollo Studio Sandbox and click Open Connection Settings in the top left corner

  1. Under Endpoint input https://demo.sourcegraph.com/.api/graphql and click Save

  1. On the bottom of the IDE, click Headers and create an Authorization header key with the value in the format: token "Your Demo Token"

  1. Now you have easy one-click crafting of your GraphQL queries and Schema reference! 🎉

When you’ve set up your Apollo Sandbox environment successfully, you should have access to the GraphQL schema reference page.

This page is incredibly instrumental in being able to understand and navigate the objects and types that are available in the API.

Simply search for the objects or types you’re looking for to see how to access them.

By searching for a Batch under the Query root type, you can see all objects that are available with “batch” in the name or documentation

Clicking into BatchChange gives me all the fields that are available under that object and also how to access it.

Understanding Fragments

A Fragment is a power filtering mechanism that takes advantage of the strongly typed nature of GraphQL schemas

Consider the below operation:

query Search($query: String!) {
  search(query: $query, version: V3) {
    results {
      results {
        ... on FileMatch {
          ...FileMatchFields
        }
      }
    }
  }
}

fragment FileMatchFields on FileMatch {
  repository {
    name
    url
  }
  file {
    name
    path
    url
  }
}
... on File Match

The above notation takes advantage of the strongly typed nature of GraphQL.

What this means is “of the returned data from the parent, if the type is of FileMatch, return the following fields…”

...FileMatchFields

This fragment notation is a way to improve readability of your GraphQL operation. It is a shorthand way to add fields into an operation. The fragment FileMatchFields on FileMatch later on in the operation body defines the fields that are to be requested.

Understanding Pagination

There are some objects in the API that return lots of data. Sourcegraph utilizes a cursor based pagination pattern somewhat based on the Relay-spec.

Consider the below operation:

//Get the first 10 insights' IDs
query Insights($first: Int, $after: String) {
    insightViews(first: $first, after: $after) {
        pageInfo {
            hasNextPage
            endCursor
        }
        nodes {
            id
        }
    }
}

//Query Variables
{
    "first": 10,
    "after": null
}

Paginated data is accessed through nodes

Pass the nodes.id field into subsequent calls in the $after variable to paginate through data that occurs after that Object. See operation below for an example.

pageInfo and totalCount can tell you how much data is left

//Get the next 5 insights after a specific insight
query Insights($first: Int, $after: String) {
    insightViews(first: $first, after: $after) {
        pageInfo {
            hasNextPage
            endCursor
        }
        nodes {
            id
        }
    }
}

//Query variables
{
    "first": 5,
    "after": "aW5zaWdodF92aWV3OiIyNU9lanpQZUVWZ1ViMk96NzNYdnF4TnVvdUci"
}

endCursor will always return the last ID in your call so you can use that in subsequent calls until hasNextPage is false.

Tips & Tricks

  1. Make use of your browser’s developer tools to determine the GraphQL operation within Sourcegraph’s web app.

  1. Check out the Node documentation to see what parts of the API require pagination

  2. Use the Copy Operation Link when right clicking into Sandbox to collaborate with other folks who have the IDE configured

Example GraphQL Operations

The below operations will use demo.sourcegraph.com. Adjust to your connection details and variables as necessary

File contents from default branch

Get a diff of two Commits

List first 1000 repos

List all files in a repo

List all languages in a repo

All active users this month

Introspection query

Example scripts that utilize the GraphQL API

Ensure you’re part of the Sourcegraph GitHub organization to view these private scripts

Add/Update/Delete Repository Metadata - Python