API Integration: Where is the ISS ?

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:
- https://api.open-notify.org/ for the ISS position
- https://opencagedata.com/ for the reverse geocoding
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 record
s 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 Lagardère, VP Customer Experience, RAW Labs.
Want to learn more?
- Give RAW a try: Get Started for free!
- Why not follow us on LinkedIn, or Twitter, or join the conversation over at Reddit
- Read our Tutorials and Getting Started docs
- Like code? head on over to GitHub and look at our demo APIs
- Developer? Join us! we are looking for bright minds – at all levels of seniority, in databases, distributed systems, UI/UX.
Learn More

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

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

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