GraphQL API

Learn about our GraphQL API and how to query and mutate OpsLevel data. You can also use the GraphiQL Explorer to interact with the API on your own OpsLevel account.

Our GraphQL API allows you to easily integrate OpsLevel with your other operational tools. You can enrich your internal tickets, incidents, and other systems with service and team data pulled from OpsLevel.

You can also use our API to automatically keep your OpsLevel info up-to-date by integrating it with real-time information pushed from tools like Terraform, Chef, Circle CI, etc. Historically, we’ve supported a YAML file integration with your git repositories for this same purpose, but our API now gives you more automation options.

What is GraphQL?

If you’ve used APIs before, you’ve probably encountered RESTful APIs. In REST, each resource generally has its own endpoint. For example, if OpsLevel had a REST API, there would be endpoints for services, teams, and users. If you wanted to fetch a list of all Services and their associated Teams, you would have to make many queries: one query to fetch the services, then one query per service to fetch the team for that service.

GraphQL works differently. GraphQL is a query language that lets clients declaratively specify what data they want to retrieve, not how it should be retrieved. With GraphQL, there is only one HTTP request that needs to be made and the response is completely customizable. GraphQL is also type safe, meaning your API client can verify that the data you’re asking for is sound. Visit the following link to see many other additional benefits of GraphQL over REST:

https://www.howtographql.com/basics/1-graphql-is-the-better-rest/

Why is OpsLevel using GraphQL for its API?

The data model for modern operations is incredibly rich and sophisticated. For example, there are dependencies between services themselves, between services and teams, teams and users, services and deployments, and deployments and infrastructure.

GraphQL is extremely well suited for clients to easily navigate this kind of rich data model. As discussed previously, GraphQL allows clients to fetch only the data they want and to do so in a single HTTP request. That leads to less bandwidth used (by only retrieving the necessary data) and less roundtrips (by not having to make a separate request per related resource).

Getting Started with the OpsLevel GraphQL API

Background

OpsLevel’s GraphQL API makes use of two high level types: queries and mutations.

Queries allow you to fetch information from OpsLevel.

Mutations allow you to push information to OpsLevel.

For more information on how to make GraphQL queries and mutations, visit https://graphql.org/learn/queries/.

The GraphiQL Explorer

The easiest way to get started with the the OpsLevel API is with GraphiQL, an interactive environment for exploring our API and its documentation.

Log In For GraphiQL

This explorer will allow you to easily test queries and mutations before integrating our API with your app.

The GraphiQL Explorer consists of three main components:

  • Query Editor pane
  • Query Response pane
  • Documentation Explorer

OpsLevel GraphiQL Explorer Explained

Query Editor

Where you will be writing your GraphQL queries.

Query Response Pane

Where you will see the responses to your GraphQL queries.

Documentation Explorer

GraphQL comes with first class support for documentation. You can interact with our API documentation directly from within GraphiQL.

Note: If you do not see the Documentation Explorer, it may be closed by default and can be opened by pressing the Docs button in the top right corner.

Executing GraphQL Queries from GraphiQL

You can execute your GraphQL queries from GraphiQL by pressing the Play button after writing your query in the Query Editor.

OpsLevel GraphiQL Play Button

Sample Query

To get started, try pasting the following query in the Query Editor pane (the left pane of GraphiQL):

{
  account {
    name
  }
}

Now press the Play button. You should see this result in the Query Response pane (the middle pane of GraphiQL):

{
  "data": {
    "account": {
      "name": "Your Account Name"
    }
  }
}

OpsLevel GraphiQL Explorer

Pagination

OpsLevel limits query results for an object to a maximum of 100 results. If you have more than 100 objects to fetch, you will have to paginate through the result set.

Objects whose name end with ConnectionType, such as ServiceConnectionType, are ones that you can paginate through. Please see GraphQL Pagination for an explanation of what these connection types are, how they relate to pagination, and code examples for how to paginate. An example on using cursor-based pagination is below. (Please note that we do not support offset.)

For example, you can use cursor-based pagination, utilizing after and pageInfo to get the next page of results. With the query below, you can run the query without the after input, and then use the value from endCursor to get the next page of results if hasNextPage returns true.

query pagination_with_services{
  account{
    services(first: 5, after: "NQ"){
      totalCount
      pageInfo{
        hasNextPage
        endCursor
      }
      edges{
        node{
          id
          name
        }
        cursor
      }
    }
  }
}

Returning data and errors on mutations

All OpsLevel GraphQL API mutations require you to return some payload. It is represented in the GraphQL Schema documentation by an exclamation mark (!) after the name of all mutations’ payloads.

For instance, in serviceCreate mutation, ServiceCreatePayload is required.

serviceCreate(input: ServiceCreateInput!): ServiceCreatePayload!

If you don’t include a return payload in your mutation, you will get an error. E.g.:

mutation {
  tagDelete(input: { id:"Z2lkOi8vb3BzbGV2ZWwvVGFnLzU" })
}

Here is an example of how the mutation above should be correctly called.

mutation {
  tagDelete(input: { id:"Z2lkOi8vb3BzbGV2ZWwvVGFnLzU" }) {
    deletedTagId
    errors {
      message
    }
  }
}

Dealing with Errors

Always include the errors field in your mutations.

If you’re coming from the REST world, you might be expecting our API to return 4xxs for client errors. But in GraphQL, non-2xx errors only get returned for more serious issues like network failures. For client errors, we will return a 200, with more information about the error in the errors field. You should always include the errors field in your requests so that you can handle errors appropriately.

Here’s an example error response from the serviceUpdate mutation:

{
  "data": {
    "serviceUpdate": {
      "service": null,
      "errors": [
        {
          "message": "This service is locked by a service config file.",
          "path": [
            "locked"
          ]
        }
      ]
    }
  }
}

Integrating OpsLevel API into your own App

1. Create an API Token

In the OpsLevel app, navigate to the API tokens page by pressing the API link in the side menu or by navigating to https://app.opslevel.com/api_tokens.

From this page, press the + Create API Token button.

OpsLevel Create API Token Page

After pressing the + Create API Token button, you will be prompted to add a Token Description. Once you’ve added a description, press the Create API Token button shown below.

OpsLevel Create API Token Modal

After your token has been created, you will be shown a confirmation modal with your new API token.

OpsLevel Token Created Modal

Important: You will only be shown your API token once upon creation. Store it somewhere safe. If you lose this token, it’s irrecoverable by OpsLevel.

Tokens are to be used in the Authorization header of your request as a Bearer or Token.

Note: <token> will be used in place of your actual token in all examples.

2. Make a request with curl

To test that everything is working correctly, copy and paste one of the following curl commands into your terminal and replace <token> with the token generated in the previous section.

GraphQL query

TOKEN= # ... paste in your API token
curl -X POST \
     -H 'Content-Type: application/json' \
     -H 'Accept: application/json' \
     -H "Authorization: Bearer ${TOKEN}" \
     -d '{ "query": "{ account { name } }" }' \
https://api.opslevel.com/graphql

You should receive the following response:

{"data":{"account":{"name":"Your Account Name"}}}

where "Your Account Name" is replaced with your actual account name.

GraphQL mutation

You can also apply a mutation, such as creating a new service, with the following:

TOKEN= # ... paste in your API token
curl -X POST \
     -H 'Content-Type: application/json' \
     -H 'Accept: application/json' \
     -H "Authorization: Bearer ${TOKEN}" \
     -d '{ "query": "mutation {  serviceCreate(input:{name:\"Brand New Service\"}) { service { id name } errors { message path } } }" }' \
https://api.opslevel.com/graphql

3. Make a query with your favourite client library

Underneath it all, GraphQL APIs are built on top of HTTP, so you can use your existing HTTP libraries and tools. GraphQL is widely supported by a variety of languages and frameworks through client plugins, such as Apollo for Javascript and graphql-client for Ruby.

We also have built a golang client which is being developed in tandem with our CLI, Terraform provider and kubectl sync.

For a great list of GraphQL plugins for both server and client applications, refer to https://github.com/github/graphql-client.

GraphQL Examples

Some query and mutation examples are listed below to help you get started with GraphQL.

For more examples, see this repo here: https://github.com/OpsLevel/community-integrations/tree/main/graphql_query_examples

Querying Service Information

Query all services with their team name and manager contact info

{
  account {
    services {
      nodes {
        name
        aliases
        id
        description
        owner {
          name
          manager {
            email
          }
        }
      }
    }
  }
}

Query all services with owner, aliases, tags, tier, and repositories

{
  account {
    services {
      nodes {
        name
        description
        owner {
          name
        }
        aliases
        id
        tags {
          nodes {
            key
            value
          }
        }
        tier {
          alias
          name
        }
        repositories {
          totalCount
          nodes {
            name
            defaultBranch
            private
            url
          }
        }
      }
    }
  }
}

Query services with criteria - Ruby on Rails services

{
  account {
    services(language: "Ruby", framework: "Rails") {
      nodes {
        name
        aliases
        id
        description
        language
        framework
      }
    }
  }
}

Query services with criteria - Tagged with public-facing:true

{
  account {
    services(tag: {key:"public-facing", value:"true"}) {
      nodes {
        name
        aliases
        id
        description
        tags {
          nodes {
            key
            value
          }
        }
      }
    }
  }
}

Query a specific service by its alias

{
  account {
    service(alias: "shopping_cart") {
      name
      aliases
      id
      description
    }
  }
}

Query a specific service by ID

{
  account {
    service(id: "Z2lkOi8vb3BzbGV2ZWwvU2VydmljZS8xMzM") {
      name
      aliases
      description
    }
  }
}

The OpsLevel API offers more queries which can be found in GraphiQL’s Docs tab.

Pushing Service Information

Registering a new service with OpsLevel

mutation {
  serviceCreate(input: {
    name: "New Service",
    tierAlias:"tier_1",
    description:"This is a description for the new service"
    language: "Java",
    framework: "Spring",
    ownerInput: {
      alias: "a-team"
    }
  }) {
    service {
      name
      description
      id
      owner {
        name
      }
      tier {
        alias
        name
      }
    }
    errors {
      message
      path
    }
  }
}

Updating a service

Using the ID of the service
mutation {
  serviceUpdate(input: { id: "Z2lkOi8vb3BzbGV2ZWwvU2VydmljZS8xMzM", name: "Updated Service Name" }) {
    service {
      name
    }
    errors {
      message
      path
    }
  }
}
Using the alias of the service
mutation {
  serviceUpdate(input: { alias: "shopping_cart", name: "Updated Service Name" }) {
    service {
      name
    }
    errors {
      message
      path
    }
  }
}

Deleting a service from OpsLevel

Using the alias of the service
mutation {
  serviceDelete(input: { alias: "shopping_cart" }) {
    deletedServiceId
    errors {
      message
      path
    }
  }
}

The OpsLevel API offers more mutations which are documented in GraphiQL’s Docs tab.

Managing Tags Information

Querying tags for a given Service

Using the ID of the service
{
  account {
    service(id: "Z2lkOi8vb3BzbGV2ZWwvU2VydmljZS8xMzM") {
      name
      tags {
        nodes {
          key
          value
          id
        }
      }
    }
  }
}
Using the alias of the service
{
  account {
    service(alias: "shopping_cart") {
      name
      tags {
        nodes {
          key
          value
          id
        }
      }
    }
  }
}

Assigning tags to a service

The tagAssign mutation is an ‘upsert’-style mutation: if a tag with the same key already exists it will be updated, otherwise a new tag will be created.

This is useful as way to easily push tags into OpsLevel without having to do a query.

Assigning Tags

mutation {
  tagAssign(input: {
    alias: "shopping_cart",
    tags: [
      { key:"database", value:"mysql-5.8" },
      { key:"queue", value:"sidekiq" },
    ]
  }) 
  {
    tags {
      id
      key
      value
    }
    errors {
      message
    }
  }
}

Deleting Tags

To delete a tag, you must query tags for a given service to know the id of the tag.

mutation {
  tagDelete(input: { id:"Z2lkOi8vb3BzbGV2ZWwvVGFnLzU" }) {
    errors {
      message
    }
  }
}

Frequently Asked Questions

What happens if I lose my API token?

For security purposes, API tokens are irrecoverable by OpsLevel. If you lose your API token, you can delete it and create a new one.

Who else uses GraphQL?

GraphQL is gaining popularity rapidly because of the benefits it provides. Companies such as Facebook, Twitter, Shopify, GitHub, GitLab, and many many more use GraphQL today.

What is the API rate limit?

There are two levels of rate limiting in place at OpsLevel:

  1. IP Address Request Limit: No more than 10,000 requests every 5 mins from a single IP Address -- this limit includes OpsLevel requests outside of the GraphQL API.
  2. API Token Request Limit: No more than 250 API requests per minute per API token

If you exceed these limits, you will receive a 429 - Too Many Requests - status code indicating that you are being rate limited. For API Token Request Limits, we provide two request headers to help you avoid or handle being rate limited:

  1. RateLimit-Remaining - The number requests you have remaining before the API Token reaches the 250 request limit
  2. RateLimit-Retry-After - The number of seconds to wait before its safe to retry again because you'll have room left in the budget for that API Token.

What if I have more questions or suggestions?

If you have any questions, suggestions, or just want to chat, reach out to us at [email protected].