ASR ank v2.1(GraphQL/RESTFUL)
GraphQL API:
  will not work in web browsers
UI: https://api.asrank.caida.org/v2/graphiql
script: scripts/asrank-download-asn.py (simple)
scripts/asrank-download.py (complex)
RESTFUL API: https://api.asrank.caida.org/v2/restful/

Table of Contents

Introduction 

AS Rankv2.1 is a GraphQL API interface. GraphQL allows clients to create queries that specify which values they require and contain multiple resources. GraphQL, as a strongly-typed language, allows to know what data is available, in what format and verify responses.

The User Interface (UI) can be found at http://asrank.caida.org. The Application Programming Interface version 2 (APIv2) interface is available at https://api.asrank.caida.org/v2/graphql and GraphiQL, graphic interface, can be found at https://api.asrank.caida.org/v2/graphiql.

We will be operating AS Rank APIv1 (http://as-rank.caida.org/api/v1) until March 1st, 2020, but it will no longer be updated. Current users should migrate to the v2 API before this date. Contact asrank-info@caida.org for migration assistance.

Schema 

Documentation for GraphQL's query language can be found at https://graphql.org/learn/.

AS Rank API: schema

Sample Scripts 

GraphQL works with the standard set of HTTP tools (see 4 simple ways to call a GraphQL API).

  • asrank-download-asn.py is a simple Python script that can be used to download a single ASN. It can also be used as a template to write your own script.
    python3 asrank-download-asn.py 701
                                                
  • asrank-download.py is a more complex Python script that can be used as-is to download all the ASNs, organizations, or ASN links. The following arguments will cause the script to download all the asns, organizations, and asnLinks into their respective files.
    python3 asrank-download.py -v -a asns.jsonl -o organizations.jsonl -l asnLinks.jsonl -u https://api.asrank.caida.org/v2/graphql
                                                
  • curl The following command will download ASN 701's organization name and the number of ASNs in its cone.
    curl -H "Content-Type: application/json" -X POST \
      --data '{ "query": "{ asn(asn:\"701\"){ asn organization { orgName } cone { numberAsns } } }" }' \
      https://api.asrank.caida.org/v2/graphql
                                                

APIs

ASRank API v2.1 supports a RESTFUL and GraphQL API. The RESTFUL does not provide any additional functionality, but a simplified interface to the GraphQL API. It will return the same data as the GraphQL.

RESTFUL API

These are really just calls to the GraphAPI interface. They do not directly talk to the Database.

A list of the supported calls is:

/restful/asns
/restful/asns/:asn(\d+)
/restful/asns/name/:name(.+)
/restful/asnLinks
/restful/asnLinks/:asn0(\d+)
/restful/organizations
/restful/organizations/:organization(.+)

Detailed RESTFUL doc with examples can be found here: restful/doc

GraphQL

For those unfamiliar with GraphQL, it is a bit of a paradigm shift from the use of a RESTful API, in that GraphQL requires the client to specify precisely which values it needs. In the following example, the client wants to know an ASN's transit degree. With a normal RESTful API, the client must retrieve the full record and extract the information it wants. A GraphQL API client must specify that it wants the ASN's transit degree.

GraphQL RESTFUL
# request ASN 3356's degree
query={
   asn(asn:"3356") {
      asnDegree {
         transit
      }
   }
}
data={
   "asn": {
      "asnDegree": {
         "transit": 5255
    }
}
# request ASN 3356's record
/asns/3356?populate=1 
data={
    “clique”: “true”,
    “source”: “ARIN”,
    “org”: {
        “name”: “Level 3 Parent, LLC”,
        “id”: “LPL-141-ARIN”
    },
    “cone”: {
        “prefixes”: 516117,
        “addresses”: 1293145968,
        “asns”: 36019
    },
    “latitude”: “36.0978209554736”,
    “rank”: “1”,
    “country”: “US”,
    “name”: “LEVEL3”,
    “country_name”: “United States”,
    “degree”: {
        “peers”: 95,
        “globals”: 5178,
        “siblings”: 9,
        “customers”: 5083,
        “transits”: 5177
    },
    “longitude”: “-91.335620170744”,
    “id”: “3356”
}

GraphQL supports mixed record queries. The same query can include different record types, and can specify bindings ("joins") between those resources. This approach reduces the number of API queries needed to retrieve related resources.

GraphQLRESTFUL
mixed types mixed and joined typestwo seperate queries
# request ASN 3356's asnName and
# organization LPL-141-ARIN's rank.

query={
   asn(asn:"3356") {
      asnName
      organization {
        orgId
      }
   }
   organization(orgId:"LPL-141-ARIN") {
      rank
   }
}
        
# request ASN 3356's asnName and
# it's organization's rank.

query={
   asn(asn:"3356") {
      asnName
      organization {
         rank
      }
   }
}
        
# request ASN 3356's record
/asns/3356?populate=1
                 
data={
  "name": "LEVEL3",
  "org": {
    "id": "LPL-141-ARIN",
    "name": "Level 3 Parent, LLC"
  },
  "clique": "true",
  "source": "ARIN",
  "cone":
  ...
# request Org LPL-141-ARIN's record
/orgs/LPL-141-ARIN?populate=1
data={
    "name": "Level 3 Parent, LLC",
    "rank": "1",
    "degree": {
      "asn": {
        "transit": 6999,
        "global": 7024
      },
      "org": {
      ...

ASRank API v2.1 (GraphQL) supports AS Customer Cone queries.

See asnCone and asnConeStream scheme at doc's tab on https://api.asrank.caida.org/v2/graphiql

Connection Types

Any type whose name ends in “Connection” is considered by this spec to be a Connection Type. Connection types must be an “Object” as defined in the “Type System” section of the GraphQL Specification.

Connection types must have fields named edges and pageInfo. They may have additional fields related to the connection, as the schema designer sees fit.

A “Connection Type” must contain a field called edges. This field must return a list type that wraps an edge type, where the requirements of an edge type are defined in the “Edge Types” section below

A “Connection Type” must contain a field called pageInfo. This field must return a non‐null PageInfo object, as defined in the “PageInfo” section below.

Edge Types

Edge is the system that GraphQL uses for pagination , it is a slice of a longer list. A type that is returned in list form by a connection type’s edges field is considered by this spec to be an Edge Type. Edge types must be an “Object” as defined in the “Type System” section of the GraphQL Specification.

Edge types must have fields named node and cursor. They may have additional fields related to the edge, as the schema designer sees fit.

An “Edge Type” must contain a field called node. This field must return either a Scalar, Enum, Object, Interface, Union, or a Non‐Null wrapper around one of those types. Notably, this field cannot return a list.

An “Edge Type” must contain a field called cursor. This field must return a type that serializes as a String; this may be a String, a Non‐Null wrapper around a String, a custom scalar that serializes as a String, or a Non‐Null wrapper around a custom scalar that serializes as a String.

Whatever type this field returns will be referred to as the cursor type in the rest of this spec.

PageInfo

The server must provide a type called PageInfo.

PageInfo must contain fields hasPreviousPage and hasNextPage, both of which return non‐null booleans. It must also contain fields startCursor and endCursor, both of which return non‐null opaque strings

AsnCone

AsnCone returns the cone, where asn: is Asn whose cone is returned Query: asnCone(asn:String, dates:[String]): AsnCone

Request AsnCone query exampleResponse example
{
  asnCone(asn: "2", date: "2019-12-01") {
    date
    asn {
      date
      asnName
      rank
    }
    cone {
      numberAsns
    }
    asns {
      totalCount
      pageInfo {
        first
        offset
        status
        hasPreviousPage
        hasNextPage
      }
      edges {
        node {
          date
          asn
          asnName
        }
      }
    }
  }
}
{
  "data": {
    "asnCone": {
      "date": "2019-12-01",
      "asn": {
        "date": "2019-12-01",
        "asnName": "UDEL-DCN",
        "rank": 3452
      },
      "asns": {
        "totalCount": 5,
        "pageInfo": {
          "first": 40,
          "offset": 0,
          "status": "success",
          "hasPreviousPage": false,
          "hasNextPage": false
        },
        "edges": [
          {
            "node": {
              "date": "2019-12-01",
              "asn": "6147",
              "asnName": ""
            }
          },
          {
            "node": {
              "date": "2019-12-01",
              "asn": "204854",
              "asnName": "ACMIPNETWORK-AS"
            }
          }
        ]
      }
    }
  }
}

AsnConesStream

Unlike other queries, stream does not work in units of edges. Rather it attempts to return as much information per page as possible. It will do a depth first walk of the objects requested. With that walk split across multiple pages.

AsnConeStream imitates graphql connection pagination (with a pseudocursor), allowing you to iterate over the list of external objects (cone) and the asns and prefixes objects enclosed in it as one continuous list. Moving the cursor begins with the first cone object, filtered by date or not, sequentially moving to the asns nested object and after completing the asns walk with passing through the nested prefixes object. At each step of the cursor, and the step may not necessarily be equal to one record, the information of the current and next cursor specified in three dimensions is stored in the StreamPageInfo object: index of cone, index of asn and index of prefix. For example, if the cursor was set to a step of 100 elements, then at the end of the passage StreamPageInfo will contain approximately the following information:

    type StreamPageInfo {
        pageCursor: 12,345,
        nextPageCursor: 112,,46
        hasNextPage: true
    }

where:

pageCursor is a line containing digits separated by a comma, in which the first digit is the pointer to the current Cone Id, the second digit is the Asn index in the Asns list belonging to the current Cone (12) and the third empty element signals that the cursor has not yet started navigating the Prefixes nested list , because it did not complete the passage through the Asns object.

nextPageCursor is the pointer to the start of the next cursor pass on Cones, Asns, and Prefixes objects. In this case, we see that the cursor begin its passage from Cone with Id = 12 and object with index 46 in the Prefixes list. A space between two commas indicates that the cursor has already passed all Asns objects.

  • -returning as much of ASN's and it's member as possible in the first page
  • page 1: { asn:1}, members:[2,3,4]}
  • -then returning the remaining members on the second page before starting with ASN 2
  • page 2: { asn:1, members:[5]}, {asn:2, members:[3]}
  • -then returning the remains of ASN 2's members
  • page 3: { asn:2, members:[4,5,6]}

Query: asnConesStream(asns:[String], asnMembers;[String], prefixMembers:[String], pageCursor:String, sort:String, dates:[String]):AsnConeStreamConnection!

Request ConeStream query exampleResponse example
{
  asnConesStream(pageCursor: "") {
    totalCount
    pageInfo {
      pageCursor
      nextPageCursor
      hasNextPage
    }
    pages {
      rank
      asn {
        date
        asn
        asnName
      }
      asns {
        date
        asnName
        rank
        source
        cliqueMember
        seen
        ixp
        longitude
        latitude
      }
      prefixes {
        date
        network
        length
      }
    }
  }
}
{
  "data": {
    "asnConesStream": {
      "totalCount": 1000,
      "pageInfo": {
        "pageCursor": "1,0,0",
        "nextPageCursor": "2,,860",
        "hasNextPage": true
      },
      "pages": [
        {
          "rank": 7603,
          "asn": {
            "date": "2020-02-01",
            "asn": "1",
            "asnName": "LVLT-1"
          },
          "asns": [
            {
              "date": "2020-02-01",
              "asnName": "LVLT-1",
              "rank": 7603,
              "source": "ARIN",
              "cliqueMember": true,
              "seen": true,
              "ixp": null,
              "longitude": -67.8461072038472,
              "latitude": 62.0485273010488
            },
            {
              "date": "2020-02-01",
              "asnName": "",
              "rank": 30443,
              "source": "LACNIC",
              "cliqueMember": true,
              "seen": true,
              "ixp": null,
              "longitude": -46.6295,
              "latitude": -23.5156
            }
          ],
          "prefixes": [
            {
              "date": "2020-02-01",
              "network": "4.31.236.64",
              "length": 29
            },
            {
              "date": "2020-02-01",
              "network": "4.34.12.0",
              "length": 24
            }


            ...

          ]
        }
      ]
    }
  }
}

Historic data

ASRank API v2.1 (GraphQL) supports Historic data queries.

"startDate" and "endDate" are used to define the time interval you want so search in.

Time interval is "inclusive" which means "t BETWEEN starDate AND endDate" is equivalent to "t >= starDate AND t <= endDate".

By default (if no date interval is specified) the latest month data is shown.

Sorting by "date" is supported. The default sorting is by date in ascending order.

Request Historic query exampleResponse example
{
   asns(asns:["701"], dateStart:"2019-10-01", dateEnd:"2020-02-01") {
   edges {
     node {
       asn
       rank
       date
     }
   }
  }
}
{
  "data": {
    "asns": {
      "edges": [
        {
          "node": {
            "asn": "701",
            "rank": 20,
            "date": "2019-10-01"
          }
        },
        {
          "node": {
            "asn": "701",
            "rank": 20,
            "date": "2019-11-01"
          }
        },
        {
          "node": {
            "asn": "701",
            "rank": 20,
            "date": "2019-12-01"
          }
        },
        {
          "node": {
            "asn": "701",
            "rank": 21,
            "date": "2020-01-01"
          }
        },
        {
          "node": {
            "asn": "701",
            "rank": 25,
            "date": "2020-02-01"
          }
        }
      ]
    }
  }
}

Query Examples 

Below are AS Rankv2.1 query examples.

  • Retrieve dataset
    {dataset(date:"20190501"){
      datasetId,
      modifiedAt,
      date,
      ipVersion,
      country{iso, name, capital, continent},
      asnReservedRanges,
      asnAssignedRanges,
      clique,
      asnIxs,
      sources{url,date,name},
      numberAddresses,
      numberPrefixes,
      numberAsns,
      numberAsnsSeen,
      numberOrganizations,
      numberOrganizationsSeen}
    }
    
                                                
  • Retrieve datasets
    {datasets(first:10){
      totalCount,
      pageInfo{status,first,offset,hasPreviousPage,hasNextPage},
      edges{node{
        datasetId,
        modifiedAt,
        date,
        ipVersion,
        country{iso,name},
        asnReservedRanges,
        asnAssignedRanges,
        clique,
        asnIxs,
        sources {url,date,name},
        numberAddresses,
        numberPrefixes,
        numberAsns,
        numberAsnsSeen,
        numberOrganizations,
        numberOrganizationsSeen,
    }}}}
                                                

    RETRIEVE ASNS

    Asn sort params:
    1. asn
    2. asnName
    3. rank
    4. source
    5. cone.numberAsns
    6. cone.numberPrefixes
    7. cone.numberAddresses
    8. asnDegree.peer
    9. asnDegree.customer
    10. asnDegree.transit
    11. asnDegree.sibling
    12. asnDegree.total
    
  • Retrieve asn
    {asn(asn:"3356"){
      asn,
      asnName,
      organization{orgId,orgName},
      asnLinks(first:10){
        totalCount,
        pageInfo{first,offset,status,hasNextPage},
        edges{node{
          asn0{asn,asnName},
          asn1{asn,asnName}
        }
      }
    }}}
                                                
  • Retrieve asns
    {asns(first:40,name:"level",asns:["3356","2929"]){
      totalCount,
      pageInfo{first,offset},
      edges{node{
        asn,
        asnName,
        rank,
        organization{
          orgId,
          orgName,
          rank,
          members{
            numberAsns,
            numberAsnsSeen,
            asns{
              totalCount,
              edges{
                node{asn, asnName}
              }
            }
          },
          asnLinks(first:10){
            totalCount,
            pageInfo{first,offset,status,hasNextPage},
            edges{
              node{
                asn0{asn,asnName},
                asn1{asn,asnName}
        	}
            }
          }
        }
      }
    }}}
                                                

    RETRIEVE ORGANIZATIONS

    Organizations sort params:
    1. orgId
    2. orgName
    3. rank
    4. asnDegree.provider
    5. asnDegree.peer
    6. asnDegree.customer
    7. asnDegree.transit
    8. asnDegree.sibling
    9. asnDegree.total
    10. cone.numberAsns
    11. cone.numberPrefixes
    12. cone.numberAddresses
    

  • Retrieve organization
    {organization(orgId:"LPL-141-ARIN"){
      orgId,
      orgName,
      members{
        numberAsns,
        numberAsnsSeen,
        asns{totalCount,edges{node{asn,asnName}}}
      },
      asnLinks(first:20){
          totalCount,
          pageInfo{status,first,offset,hasPreviousPage,hasNextPage},
          edges{node{
            asn0{asn},
            asn1{asn}}}
        }
    }}
                                                
  • Retrieve organizations
    {organizations(first:20, sort:"rank", dateStart:"20180101", dateEnd:"20191001"){
      totalCount,
      pageInfo{status,first,offset,hasPreviousPage,hasNextPage},
      edges{node{
        orgId,
        orgName,
        rank,
        neighbors(first:20){
          totalCount,
          pageInfo{status,first,offset,hasPreviousPage,hasNextPage},
          edges{node{asn}}
        },
        members{
          numberAsns,
    	numberAsnsSeen,
    	asns{
            totalCount,
    	    pageInfo{status,first,offset,hasPreviousPage,hasNextPage},
    	    edges{node{asn,asnName}}
          }
        },
        asnLinks(first:20){
          totalCount,
          pageInfo{status,first,offset,hasPreviousPage,hasNextPage},
          edges{node{
            asn0{asn},
            asn1{asn}}}
        }
    }}}}
                                                

    RETRIEVE LINKS

    Links sort params:
    1. asn0
    2. asn1
    3. numberPaths
    4. relationship
    5. correctedBy
    

  • Retrieve link
    {asnLink(asn0:"1299",asn1:"3356"){
      asn0{asn,asnName},
      asn1{asn,asnName},
      relationship,
      numberPaths,
      locations{
        totalCount,
        pageInfo{first,offset},
          edges{
            node{
              locId,
              city,
              region,
              country
              population
            }
          }
        }
    }}
                                                
  • Retrieve links

    Please note, asn1 is always the other link when asn is provided
    {asnLinks(first:10,asn:"3356"){
      totalCount,
      pageInfo{first,offset},
      edges{node{
        asn1{asn,asnName},
        numberPaths
          }
    }}}
                                                

    RETRIEVE LOCATIONS

    Links sort params:
    1. locId
    2. city
    3. region
    4. country
    5. continent
    6. population
    
  • Retrieve locations
    {locations(first:10,sort:"-country,region"){
      totalCount,
      pageInfo{status,first,offset,hasPreviousPage,hasNextPage},
      edges{node{
        locId,
        city,
        region,
        country,
        continent,
        latitude,
        longitude,
        population}
      }
    }}