BLOG

API Integration: Where is the ISS ?

January 21, 2022
   
Tutorial
Posted by Georges Lagardère

API Integration with RAW

In this post we will show some cool integration to combine APIs with RAW, simply, with our API = SQL + YAML + GIT approach. The goal is to build an API showing the nearest location on Earth to the International Space Station.

To this end, we will use two existing APIs as inputs:

API endpoint

Here is our new API ( Go ahead, click it 🙂 )

https://api.raw-labs.com/examples/1/public/ISS/isslocation

As you can see it returns a simple string, however it could also return data in a structured format, and there are other endpoints in our GitHub demo repository so you can take a look there for more.

Let’s see how to build it in RAW….

Getting the ISS position

Here is the simple API call to get the ISS location, right now:

http://api.open-notify.org/iss-now.json

Go ahead, click it – you will get an answer similar to this JSON output:

{
  "iss_position": {
    "longitude": "53.7588",
    "latitude": "44.5899"
  },
  "timestamp": 1642520785,
  "message": "success"
}

This is great, but it doesn’t really tell you where it is in the world. We need to take the latitude and longitude and perform reverse geocoding to find a named location. First up, we need to extract the latitude and longitude from this JSON record, and we can do this by using the following RAW command read_json():

read_json("http://api.open-notify.org/iss-now.json").iss_position.latitude

This will read the URL at the location above, as JSON, and then return the latitude in the form of a simple string like “51.5213”, same for the longitude. You can see here that using RAW is very simple and intuitive, with nothing to be set up in order to retrieve this data.

Reverse Geocoding

There are many geocoding APIs, for this example we have chosen https://opencagedata.com

If you register on their website they provide you with an API key and you can use the reverse geocoding function for free for up to 2,500 calls per day. The API call to get the location from coordinates is below:

https://api.opencagedata.com/geocode/v1/json?key=API_KEY&q=LATITUDE,LONGITUDE

This API returns a JSON record documented here. But for our simple example we need just one field, called: formatted – a well formatted version of the place name. This string is contained in the results field inside a nested structure, below, after being simplified:

{
  "results" : [
     {
      "formatted" : string
     }
  ]
}

To receive this field into RAW we will create the following typealias in RAW SQL which is used to parse the returned JSON, we will call this reverse_geocode, and use it in the same read_json() function as earlier, that reads the URL from the web. But in this example we are dictating the shape of the data we want back:

typealias reverse_geocode := 
  record(results: collection( record(formatted: string )))

read_json[reverse_geocode]("https://api.opencagedata.com/....")

Now we can implement a reverse geocoding function like this, passing in the API Key to the URL, passing in lat and lon as parameters, and forming the URL dynamically:

api_key := "<your_api_key>"

typealias reverse_geocode := 
  record(results: collection( record(formatted: string )))

getlocation(lat:double, lon:double) := {
  read_json[reverse_geocode]( "https://api.opencagedata.com/geocode/v1/json?key="      
                               + api_key + "&q=" + lat + "%2C" + lon)
}

Processing the Reverse Geocoding results

As an example, if you call getlocation(45.91, 103.94) you will get back:

{
  "results" : [
     {
      "formatted" : "Sant, Mongolia"
     }
  ]
}

In RAW, this is a record of a collection, named: results, which in turn is a record of strings, named: formatted.

You can think of it like { } is a record and [ ] is a collection. As this is a record, we can use the same “.” notation on the returned record and access the results this way:

api_key := "<your_api_key>"

typealias reverse_geocode := 
  record(results: collection( record(formatted: string )))

getlocation(lat:double, lon:double) := {
  read_json[reverse_geocode]( "https://api.opencagedata.com/geocode/v1/json?key=" + 
                               api_key + "&q=" + lat + "%2C" + lon).results
}

…which would return the collection of records containing strings:

[
  {
  "formatted" : "Sant, Mongolia"
  }
]

And we can retrieve the first record (there’s only one actually…) by using the cfirst() function, which returns the first item in a collection:

api_key := "<your_api_key>"

typealias reverse_geocode := 
  record(results: collection( record(formatted: string )))

getlocation(lat:double, lon:double) := {
  cfirst(read_json[reverse_geocode]( "https://api.opencagedata.com/geocode/v1/json?key=" 
     + api_key + "&q=" + lat + "%2C" + lon).results)
}

This will return the simple key/value string:

"formatted": "Sant, Mongolia"

Putting things together

Let’s create a function isslocation() which retrieves the ISS position and passes it to the getlocation() one:

api_key := "<your_api_key>"

typealias reverse_geocode := 
  record(results: collection( record(formatted: string )))

getlocation(lat:double, lon:double) := {
    cfirst(read_json[reverse_geocode("https://api.opencagedata.com/geocode/v1/json?key=" 
          + api_key + "&q=" + lat + "%2C" + lon).results)
}

isslocation() := {

    iss := read_json("http://api.open-notify.org/iss-now.json");

    getlocation(cast(iss.iss_position.latitude as double), 
                cast(iss.iss_position.longitude as double) )
}

Because the iss.iss_position.latitude and iss.iss_position.longitude fields are strings we need to convert them into double floating point values before we pass them to the getlocation() function. This is achieved with a cast() function.

Now we have our function isslocation() it is a simple matter of saving this as a file and committing to Git Repository, along with a simple YAML file, below, that allows the query to be executed by RAW:

raw: 0.9
endpoint: GET
metadata:
  title: Get location closest from ISS position
  description: Get closest location from the lat/lon ISS position based on opencagedata.com
  tags:
    - geocoding
code: rql
codeFile: code.rql
declaration: isslocation
format: json
security:
  public: true
computeClass: normal
enabled: true

And that’s it. We are done. RAW automatically syncs with the Git Repository, checks the code and deploys the API automatically. The API is ready.

Go click it again 🙂

https://api.raw-labs.com/examples/1/public/ISS/isslocation

Video demo

To see this in practice you can watch our YouTube video below. To develop RAW Data Products such as this one, we use Microsoft VSCode, with an extension that RAW provides to allow a full IDE experience (i.e. query, results and various helpers) whilst working with GitHub system too.

Summary

We have shown how to integrate two APIs and produce a new API that can easily be published on our platform. The RAW query language has many extensions to allow powerful query of diverse structures, along with sophisticated manipulation of results too. It’s very easy to get going too!

The source code for this example can be found here on GitHub.

Georges Lagardere Sales Director RAW Labs

Georges Lagardère, VP Customer Experience, RAW Labs.


Want to learn more?

Learn More

Blog

Hello world, meet RAW

here we show how to use RAW Data Product Platform to create a simple Hello World output

Blog

Tutorial 1. First flight with RAW

First Tutorial with RAW where we take reader through a first query, first API and passing parameters to that API

Blog

Reference Data Standard Library

Standard Libraries are a commonly known construct in programming. Same for data; we show how to use RAW to surface and standardise data into APIs