Skip to main content

GraphQL Editor

DISCLAIMER: This page is continuously updated with new content.

Pre-requisites

Please read through the following generic GraphQL guide first.

GraphQL basics

What it is

  • Query language for APIs
  • Runtime for fulfilling queries with existing data

Features

  • Ask exactly the data you need
  • Get many resources in single request
  • Single endpoint + type system: organized in terms of types and fields, not endpoints
  • No-version API evolution
  • Integration with own data + code

Pros

  • Speed + no over-fetching/under-fetching (ask and get exactly what you need)
  • Suitable for complex microservice-based systems (unified API)
  • Hierarchical structure
  • Data "shaping"
  • Strong typing
  • No "latest" version (Facebook use case)

Cons

  • Query complexity can be high ⇒ system load (query depth, recursion, etc.)
  • Complex caching (queries can be unpredictable, dynamic)
  • Complex rate-limiting

Thinking in Graphs

With GraphQL, you can model your business domain as a "graph" by defining a schema.

Within the schema, you define:

  • different types of nodes
  • how they connect/relate to each other

Types may reference other types, e.g., a BGP route may reference a prefix or AS path.

You can use GQL over your current business logic (but not implement it in GraphQL).

The idea is that you treat your API as an expressive shared language, expressing "how" clients consume the data (not "what" data). GraphQL enables working with legacy data. The GQL schema should be expanded/iterated gradually and frequently.

Concepts

  • Queries on objects fields, using optional (variable) arguments
  • Directives for forming dynamic composite queries
  • Mutations to modify server-side data
  • Type system: queries/mutations, scalars, enums, interfaces, unions
  • Type language: agnostic (use your favorite!)
  • Queries/mutations validated and executed at run-time by GQL resolvers
  • Introspection capabilities by design

Type System

Example of basic Prefixes type:

type Prefixes {
data_source_count: Int
id: uuid
ip_version: Int
routes(
distinct_on: [routes_select_column!]
limit: Int
offset: Int
order_by: [routes_order_by!]
where: routes_bool_exp
): [routes!]!
}

Example of interface:

interface Identifiable {
id: String!
}

Example of an Autonomous System entity (AutSystem) implementing the example interface:

type AutSystem implements Identifiable {
id: String!
number: Int!
}

Subscriptions

Subscriptions are a GQL feature that allows a server to send data to its clients when a specific event happens. They are typically implemented with WebSockets. The server maintains a steady connection to its subscribed client. Subscriptions break the "Request-Response-Cycle" as follows:

  • Client initially opens up a long-lived connection to the server
  • Client sends a subscription query that specifies which event it is interested in
  • Every time this particular event happens, the server uses the connection to push the event data to the subscribed client(s).

Best Practices

  • Serve over HTTP(S) via single endpoint
GET: https://myapi/graphql?query={object{field}}
POST:
{
"query": "...",
"operationName": "...",
"variables": { "myVariable": "someValue", ... }
}
Response:
{
"data": { ... },
"errors": [ ... ]
}
  • JSON syntax is typical in responses (note that specification does not require it!)
  • Versioning: continuous evolution & add/deprecate objects and fields
  • Nullable/non-nullable types should be explicitly defined
  • Authorization: delegate to business logic layer (not the GQL layer!). Frameworks like Hasura offer appropriate support for this.
  • Pagination: up to API designer (typically cursor-based)
  • Batching & Caching: expose globally unique IDs for clients to use/cache on
  • In general: most things besides the query contexts are kept out of the spec on purpose, providing to the developer/operator freedom to implement their own business logic!

BGPQL: A GQL API for BGP data

Please check the following sections on this topic. For simplicity, we mention here some sample primitives and associations/relationships that are part of this GQL API for BGP data.

Sample primitives:

  • dataSources
  • prefixes
  • autonomousSystems
  • peerings
  • routes

Sample associations/relationships:

  • dataSources → all
  • autonomousSystemsroutes.Origin, routes.Neighbor, peerings.Left, peerings.Right
  • prefixesroutes.prefix

Sample query:

query MyV6Prefixes {
prefixes(
distinct_on: network
where: {
routes: {originAutonomousSystem: {number: {_eq: "50414"}}, data_source_count: {_gte: 10}},
ip_version: {_eq: 6}
} order_by: {network: asc}
) {
network
}
}

Sample response:

{
"data": {
"prefixes": [
{"network": "2a12:bc0::/48"},
{"network": "2a12:bc0:1::/48"},
{"network": "2a12:bc0:2::/48"}
]
}
}

We provide a BGPQL editor based on graphiql.

The Editor contains:

  • an Explorer (leftmost tab), to navigate the API and form queries/mutations/subscriptions with simple point and click.
  • the History (left-inner tab) of your past queries/mutations/subscriptions.
  • a Prettify functionality for syntax beauitification.
  • a Docs link redirecting to our API reference.

You can write the queries/mutations/subscriptions directly (center tab up), input query variables and optionally tune the POST request headers used (center tab down). On the rightmost side you see the resulting JSON data after you run the query/subsctiption/mutation.

BGPQL Raw API Primitives

These can be found here. Note that the accessible primitives differ depending on you role as Viewer (read-only access) or Editor (read+write access). In the current documentation we provide a more user-friendly API description with appropriate examples.

BGPQL Entities

Looking Glass

Ingested state of the system. They correspond to the Looking Glass page contents of the UI.

dataSources

Sources of data; a data service like RIS Live may employ 100s of dataSources. 1-N relationships with: autonomousSystemDataSourceAssociations, prefixDataSourceAssociations, peeringDataSourceAssociations, routeDataSourceAssociations, rpkiROADataSourceAssociations, dataSourceMetadatas. Fields: id, locality (not used), selector, data_service.

Example query/response:

query dataSources {
dataSources {
id
selector
data_service
}
}

{
"data": {
"dataSources": [
{
"id": "e7f752ec-7847-4951-8b34-433a72e30dd6",
"selector": {
"host": "rrc15",
"peer_ip": "187.16.222.156",
"peer_asn": 264479
},
"data_service": "RIS_LIVE"
}
]
}
}

autonomousSystems

The autonomous systems collected by the BGP updates (AS paths in announcements) seen by the system. 1-N relationships with: autonomousSystemDataSourceAssociations, routeOriginAutonomousSystems, routeNeighborAutonomousSystems, peeringLeftAutonomousSystems, peeringRightAutonomousSystems. Fields: id, number, data_source_count, orig_prefixes_diff (args: base_selector_field_name, base_selector_field_value, base_service, comp_selector_field_name, comp_selector_field_value, comp_service).

Example query/response:

query autonomousSystems {
autonomousSystems {
number
data_source_count
id
}
}

{
"data": {
"autonomousSystems": [
{
"number": 20080,
"data_source_count": 3,
"id": "d54e0509-9f64-4123-a879-54e9852a8a48"
}
]
}
}

autonomousSystemDataSourceAssociations

Data source - AS associations. 1-1 relationships with: autonomousSystem, dataSource. Fields: id, data_time.

Example query/response:

query autonomousSystemDataSourceAssociations {
autonomousSystemDataSourceAssociations {
data_time
id
dataSource {
id
}
autonomousSystem {
id
}
}
}

{
"data": {
"autonomousSystemDataSourceAssociations": [
{
"data_time": "2023-02-16T22:20:39.49+00:00",
"id": "2a2c044b-e946-4abe-8b9a-0752b5a583e1",
"dataSource": {
"id": "d1d0af52-3e83-4897-b9a4-4a6d3c79a2bc"
},
"autonomousSystem": {
"id": "596cc059-a99d-4779-9910-0c841645ffb2"
}
}
]
}
}

prefixes

The prefixes collected by the BGP updates seen by the system. 1-N relationships with prefixDataSourceAssociations, routes. Fields: id, configured_prefix_best_match, data_source_count, ip_version (auto-generated), mask_length (auto-generated), network, is_sub_prefix (args: network), is_sub_prefix_multiple (args: networks), as_paths_diff (args: base_service, comp_service, end_asn).

Example query/response:

query Prefixes {
prefixes {
configured_prefix_best_match
data_source_count
id
ip_version
mask_length
network
}
}

{
"data": {
"prefixes": [
{
"configured_prefix_best_match": "",
"data_source_count": 126,
"id": "f8d2a4f8-04ba-4b5f-8312-63b31cfd9a7d",
"ip_version": 6,
"mask_length": 48,
"network": "2a12:bc0::/48"
}
]
}
}

prefixDataSourceAssociations

Data source - prefix associations. 1-1 relationships with: prefix, dataSource. Fields: id, withdrawn, data_time.

Example query/response:

query PrefixDataSourceAssociations {
prefixDataSourceAssociations {
data_time
withdrawn
prefix {
id
}
dataSource {
id
}
}
}

{
"data": {
"prefixDataSourceAssociations": [
{
"data_time": "2023-03-02T06:51:59+00:00",
"withdrawn": false,
"prefix": {
"id": "cf931693-8a38-4d11-8bd5-5c9fc00e067a"
},
"dataSource": {
"id": "e401023b-3328-4804-8ccd-6f892bb8ec44"
}
}
]
}
}

peerings

The autonomous system peerings (AS-level) collected by the BGP updates (AS paths in announcements) seen by the system. Note that for a path of the form AS1 AS2 AS3, with AS3 as the origin AS, we derive two peerings with the following directions: AS3->AS2, AS2->AS1. 1-1 relationships with: autonomousSystem. 1-N relationships with: peeringDataSourceAssociations. Fields: id, data_source_count.

Example query/response:

query Peerings {
peerings {
data_source_count
id
leftAutonomousSystem {
number
}
rightAutonomousSystem {
number
}
}
}

{
"data": {
"peerings": [
{
"data_source_count": 92,
"id": "2d91eb81-4a84-4d57-9868-152549a7f90a",
"leftAutonomousSystem": {
"number": 50414
},
"rightAutonomousSystem": {
"number": 20473
}
}
]
}
}

peeringDataSourceAssociations

Data source - peering associations. 1-1 relationships with: peering, dataSource. Fields: id, data_time.

Example query/response:

query PeeringDataSourceAssociations {
peeringDataSourceAssociations {
id
data_time
peering {
id
}
dataSource {
id
}
}
}

{
"data": {
"peeringDataSourceAssociations": [
{
"id": "5a65fbde-06ae-42f3-b107-753f62adb398",
"data_time": "2023-03-02T03:58:36.84+00:00",
"peering": {
"id": "727733c1-f07d-45e9-a8a3-65f235d8c458"
},
"dataSource": {
"id": "9d7703e5-e5fc-4797-a6cd-b45eee0b7bce"
}
}
]
}
}

routes

The routes correlating prefixes, autonomous systems, paths and other update info collected by the BGP updates seen by the system. 1-1 relationships with: autonomousSystem, prefix. 1-N relationships with: routeDataSourceAssociations. Fields: id, data_source_count, as_path, rpki_status.

Example query/response:

query Routes {
routes {
id
data_source_count
as_path
prefix {
network
}
originAutonomousSystem {
number
}
neighborAutonomousSystem {
number
}
rpki_status
}
}

{
"data": {
"routes": [
{
"id": "394fcad8-720d-4162-8a19-ba169efe4fe4",
"data_source_count": 2,
"as_path": "57695 60068 2914 3356 3908 721 27064 5927",
"prefix": {
"network": "2608:140:c::/48"
},
"originAutonomousSystem": {
"number": 5927
},
"neighborAutonomousSystem": {
"number": 27064
},
"rpki_status": "not-found"
}
]
}
}

routeDataSourceAssociations

Data source - route associations. 1-1 relationships with: route, dataSource. Fields: id, communities, data_time.

Example query/response:

query RouteDataSourceAssociations {
routeDataSourceAssociations {
communities
data_time
id
route {
id
}
dataSource {
id
}
}
}

{
"data": {
"routeDataSourceAssociations": [
{
"communities": [
"25091:41252",
"65300:20144"
],
"data_time": "2023-03-02T09:00:20+00:00",
"id": "96d822e0-17d2-4ea3-878f-aeff84be0050",
"route": {
"id": "ca0b7a85-bce6-4dd0-8c48-75426bbd6638"
},
"dataSource": {
"id": "7d129b0e-a0c3-4829-91cf-57ae283e1d7f"
}
}
]
}
}

rpkiROAs

RPKI ROAs downloaded from RPKI repositories. 1-N relationships with: rpkiROADataSourceAssociations. Fields: id, autonomous_system_number, data_source_count, expiry_time, ip_version (auto-generated), mask_length (auto-generated), max_length, network.

Example query/response:

query RPKIROAs {
rpkiROAs {
autonomous_system_number
data_source_count
expiry_time
id
ip_version
mask_length
max_length
network
}
}

{
"data": {
"rpkiROAs": [
{
"autonomous_system_number": 16509,
"data_source_count": 1,
"expiry_time": "0001-01-01T00:00:00+00:00",
"id": "645aafc8-423b-4ee4-98b5-5ba65fad4221",
"ip_version": 4,
"mask_length": 24,
"max_length": 24,
"network": "2.255.190.0/24"
}
]
}
}

rpkiROADataSourceAssociations

Data source - RPKI ROA associations. 1-1 relationships with: rpki_roa, dataSource. Fields: id, data_time.

Example query/response:

query RPKIROADataSourceAssociations {
rpkiROADataSourceAssociations {
data_time
id
dataSource {
id
}
rpkiROA {
id
}
}
}

{
"data": {
"rpkiROADataSourceAssociations": [
{
"data_time": "2023-02-09T13:31:51+00:00",
"id": "475ffd6f-93cd-4271-a1be-bb96104d1b8f",
"dataSource": {
"id": "433de726-02b4-4431-9366-bf5d4653d0c9"
},
"rpkiROA": {
"id": "645aafc8-423b-4ee4-98b5-5ba65fad4221"
}
}
]
}
}

dataSourceMetadatas

TBD

Configuration/Setup

Configuration and setup entities for configuring the system. They correspond to the Setup page contents of the UI.

alertReceiverTypes

Read-only available types of alert receivers, with their internal IDs and external labels. Currently available: Email, Slack (via Email). 1-N relationship with alertSubscriptions. Fields: id, label.

Example query/response:

query alertReceiverTypes {
alertReceiverTypes {
id
label
}
}

{
"data": {
"alertReceiverTypes": [
{
"id": "email",
"label": "Email"
},
{
"id": "slack",
"label": "Slack"
}
]
}
}

alertSeverities

Read-only available severities of alerts, with their internal IDs and external labels. Currently available: warning, critical. 1-N relationship with alertSubscriptions. Fields: id, label.

Example query/response:

query alertSeverities {
alertSeverities {
id
label
}
}

{
"data": {
"alertSeverities": [
{
"id": "warning",
"label": "warning"
},
{
"id": "critical",
"label": "critical"
}
]
}
}

alertTypes

Read-only available types of alerts, with their internal IDs and external labels. Currently available: Exact Prefix Hijack, Sub-Prefix Hijack, Route Leak, New Neighbor, Neighbor Leak/Hijack, Squatting, RPKI-Invalid Detection, RPKI-Invalid Announcement, RPKI-Invalid Propagation, RPKI-NotFound Propagation, Bogon (Exact-)Prefix,Bogon (Sub-)Prefix, Bogon AS, AS Path Comparison, Prefix Comparison, Custom. Fields: id, label.

Example query/response:

query alertTypes {
alertTypes {
id
label
}
}

{
"data": {
"alertTypes": [
{
"id": "unexpected_originated_prefixes",
"label": "Route Leak"
},
{
"id": "unexpected_neighbor_prefix",
"label": "Neighbor Leak/Hijack"
},
{
"id": "as_origin_violation_exact",
"label": "Exact Prefix Hijack"
},
{
"id": "as_origin_violation_sub",
"label": "Sub-Prefix Hijack"
},
{
"id": "sub_prefix",
"label": "Possible Sub-prefix Hijack"
},
{
"id": "squatting",
"label": "Squatting"
},
{
"id": "rpki_invalid_detect",
"label": "RPKI-Invalid Detection"
},
{
"id": "rpki_invalid_announce",
"label": "RPKI-Invalid Announcement"
},
{
"id": "rpki_invalid_propagate",
"label": "RPKI-Invalid Propagation"
},
{
"id": "rpki_not_found_propagate",
"label": "RPKI-NotFound Propagation"
},
{
"id": "unexpected_peering",
"label": "New Neighbor"
},
{
"id": "bogon_as",
"label": "Bogon AS"
},
{
"id": "as_path_diffs",
"label": "AS Path Comparison"
},
{
"id": "prefix_diffs",
"label": "Prefix Comparison"
},
{
"id": "custom",
"label": "Custom"
},
{
"id": "bogon_prefix_exact",
"label": "Bogon (Exact-)Prefix"
},
{
"id": "bogon_prefix_sub",
"label": "Bogon (Sub-)Prefix"
}
]
}
}

alertSubscriptions

Configured alert rule GQL subscriptions. 1-1 relationship with alertReceiverType, alertSeverity, alertType. Fields: id, name, type, severity, description, query, vars, fire_alert_regex, receiver_type,receiver_endpoint, activation_time.

Example query/response:

query alertSubscriptions {
alertSubscriptions {
id
fire_alert_regex
description
activation_time
name
query
receiver_endpoint
receiver_type
severity
type
vars
}
}

{
"data": {
"alertSubscriptions": [
{
"id": "ecb0b70a-466f-49bd-b41a-5dd9542d7317",
"fire_alert_regex": "^.*prefixes.*\\[.*network.*$",
"description": "Unexpected prefixes in the list of prefixes that are announced by configured ASes",
"activation_time": "2023-02-17T15:10:00.351226+00:00",
"name": "B-Root USC ISI Route Leak",
"query": "subscription RouteLeak($asn: bigint!, $prefixes: [cidr!] = [], $ds_thres: Int!) {prefixes(where: {routes: {originAutonomousSystem: {number: {_eq: $asn}}}, network: {_nin: $prefixes}, data_source_count: {_gte: $ds_thres} } order_by: {network: asc}) {network }}",
"receiver_endpoint": "[email protected]",
"receiver_type": "email",
"severity": "critical",
"type": "unexpected_originated_prefixes",
"vars": {
"asn": "394353",
"ds_thres": "1",
"prefixes": [
"192.228.79.0/24",
"199.9.14.0/23",
"199.9.14.0/24",
"199.9.15.0/24",
"2001:500:200::/44",
"2001:500:200::/48",
"2001:500:201::/48",
"2001:500:204::/48",
"2001:500:205::/48",
"2001:500:206::/48",
"2001:500:207::/48",
"2001:500:208::/48",
"2001:500:209::/48",
"2001:500:84::/48"
]
}
}
]
}
}

configuredAutonomousSystems

Read-only configured AS filters, populated by writable manuallyConfiguredAutonomousSystems. Fields: number, data_service (not used).

Example query/response:

query configuredAutonomousSystems {
configuredAutonomousSystems {
number
}
}

{
"data": {
"configuredAutonomousSystems": [
{
"number": 50414
}
]
}
}

configuredPrefixes

Read-only configured prefix filters, populated by writable manuallyConfiguredPrefixes. Fields: network, ip_version (auto-generated), mask_length (auto-generated), data_service (not used).

Example query/response:

query configuredPrefixes {
configuredPrefixes {
ip_version
mask_length
network
}
}

{
"data": {
"configuredPrefixes": [
{
"ip_version": 4,
"mask_length": 24,
"network": "192.203.230.0/24"
}
]
}
}

configuredDataServices

Configured data services. Fields: configuration (not used), id, data_service, data_source_selector_fields (not used), enabled, filter_on_autonomous_system, filter_on_data_source (not used), filter_on_prefix.

Example query/response:

query configuredDataServices {
configuredDataServices {
id
filter_on_prefix
filter_on_autonomous_system
enabled
data_service
}
}

{
"data": {
"configuredDataServices": [
{
"id": "5615dc61-a5c3-4447-8909-f48b51abd97a",
"filter_on_prefix": "any",
"filter_on_autonomous_system": "origin",
"enabled": true,
"data_service": "RPKI"
},
{
"id": "b9612cdd-80d5-40e8-be91-3ed93ce788e9",
"filter_on_prefix": "any",
"filter_on_autonomous_system": "origin",
"enabled": true,
"data_service": "BGP_ROUTER"
},
{
"id": "d4d6deb5-a705-4368-a4e7-b0b03fe075a1",
"filter_on_prefix": "any",
"filter_on_autonomous_system": "origin",
"enabled": true,
"data_service": "CODEBGP_MONITOR"
},
{
"id": "20991c99-ba10-4395-bb11-87f1a5a377fc",
"filter_on_prefix": "any",
"filter_on_autonomous_system": "origin",
"enabled": true,
"data_service": "RIS_LIVE"
}
]
}
}

configuredDataSources

[NOT USED] Read-only configured data source filters, populated by writable manuallyConfiguredDataSources. Fields: data_service, selector.

manuallyConfiguredAutonomousSystems

Manually configured AS filters. Fields: id, number, reject (not used).

Example query/response:

query manuallyConfiguredAutonomousSystems {
manuallyConfiguredAutonomousSystems {
id
number
}
}

{
"data": {
"manuallyConfiguredAutonomousSystems": [
{
"id": "d8809422-e1a0-4d41-a752-0473e954ff34",
"number": 50414
}
]
}
}

manuallyConfiguredPrefixes

Manually configured prefix filters. Fields: id, ip_version (auto-generated), mask_length (auto-generated), network, reject (not used).

Example query/response:

query manuallyConfiguredPrefixes {
manuallyConfiguredPrefixes {
ip_version
mask_length
network
id
}
}

{
"data": {
"manuallyConfiguredPrefixes": [
{
"ip_version": 4,
"mask_length": 24,
"network": "212.46.55.0/24",
"id": "e37f385a-6ada-4b81-872c-b69010277412"
}
]
}
}

manuallyConfiguredDataSources

[NOT USED] Manually configured data source filters. Fields: id, reject, data_service, selector.

Filtering via where

Queries/subscriptions/mutations can target specific data by using where filters. Example:

subscription NeighborsToWhichPrefixIsAnnounced($asns: [bigint!] = [], $prefix: cidr!) {
routes(
where: {originAutonomousSystem: {number: {_in: $asns}}, prefix: {network: {_eq: $prefix}}}
) {
originAutonomousSystem {
number
}
neighborAutonomousSystem {
number
}
routeDataSourceAssociations {
communities_string
}
}
}

You can also form more complex BGPQL queries that are parameterized accordingly, as follows.

What prefixes from that AS are visible from my AS?

subscription PrefixesFromOriginASNVisibleFromASN($originASNRegex: String!, $visibleFromASNRegex: String!) {
prefixes(
where: {routes: {_and: [{as_path: {_regex: $originASNRegex}}, {as_path: {_regex: $visibleFromASNRegex}}]}}
order_by: {network: asc}
) {
network
}
}

Sample variables:

{"originASNRegex":"( |^)2149$","visibleFromASNRegex":"( |^)3557( |$)"}

Which prefixes leak visibly from my AS?

subscription LeakedPrefixesMyASNOriginates($asn: bigint!, $prefixes: [cidr!] = [], $ds_thres: Int!) {
prefixes(where: {routes: {originAutonomousSystem: {number: {_eq: $asn}}}, network: {_nin: $prefixes}, data_source_count: {_gte: $ds_thres} } order_by: {network: asc}) {
network
}
}

Sample variables:

{asn: 65001, prefixes: ["139.91.0.0/16"], ds_thres: 1}

What are the RPKI-invalids my AS propagates?

subscription RPKIInvalidPrefixesPropagatedByMyASNs($asn_regex: String, $rpki_status: String!) {
routes(
order_by: {as_path: asc, prefix: {network: asc}}
where: {as_path: {_iregex: $asn_regex}, rpki_status: {_eq: $rpki_status}}
) {
prefix {
network
}
as_path
}
}

Sample variables:

{asn_regex: "( 8522 )|(^8522 )|( 8522$)|(^8522$)", rpki_status: "invalid"}

Which paths towards my prefixes contain ASes that should not be present?

subscription ASPathPresence($prefixes: [String!] = [], $asn_present_regex: String!) {
routes(
where: {prefix: {configured_prefix_best_match: {_in: $prefixes}}, as_path: {_iregex: $asn_present_regex}}
order_by: {as_path: asc, prefix: {network: asc}}
) {
prefix {
network
}
as_path
}
}

Sample variables:

{prefixes: ["139.91.0.0/16"],asn_present_regex:( 8522 )|(^8522 )|( 8522$)|(^8522$)"}

Aggregates

Aggregate functions on entities.

Format: <entity>Aggregate.

Fields: nodes (with sub-fields same as <entity> ), aggregate (with functions such as count, min, max, avg, etc.)

Example query/response:

query dataSourcesAggregate {
dataSourcesAggregate {
aggregate {
count
}
}
}

{
"data": {
"dataSourcesAggregate": {
"aggregate": {
"count": 5752
}
}
}
}