GraphQL and geolocation on Postgres (PostGIS using Hasura)
A primer to building backends for location-aware applications using postgres and GraphQL
In this post, we are going to go over how you can use Postgresql and GraphQL to build location aware applications. We are going to go over a simple use case where we are building a GraphQL backend for an application which shows a list of landmarks around you.
We are going to use the Hasura GraphQL engine for this as it provides out of the box GraphQL APIs over postgres.
Getting started
We will use the Hasura GraphQL engine for instantly getting GraphQL APIs over Postgres. Click on the button below to deploy the GraphQL engine to Heroku’s free tier.
This will deploy the graphql-engine
to Heroku. You might need to create a Heroku account if you don’t have one. The graphql-engine
will be running at https://your-app.herokuapp.com
(replace your-app
with your heroku app name).
API Console
Every Hasura cluster comes with an API Console
that you can use to build the backend for your application.
The API Console is available at https://your-app.herokuapp.com
/console
PostGIS
To store and compute on geo-location data, we are going to use PostGIS
which is a spatial database extender for Postgres
. It adds support for geographical objects on Postgres and also comes with utility functions such as distance, area, union, and intersection.
Enabling PostGIS
Before we begin, we need to enable the PostGIS extension on Postgres. (You’ll need a Postgres instance with PostGIS installed. Heroku Postgres comes with the installation, you just need to create the extension. If you’re using Docker based setup, checkout this docker-compose file)
Head to Data
tab in the Api Console
and click on SQL
in nav bar on the left. And execute the following SQL commands:
Please ensure that you select the Track this
checkbox before running the query so that this change is tracked as a migration.
Creating tables
Say we need 2 tables, for user and landmark location data, with the following definitions:
Run the above SQL in the same SQL
section of the console as shown above, and don't forget to check the Track this
checkbox (this is because we want GraphQL Engine to track this change in the db schema).
We are storing the location of the landmark and the user in a column named location of type GEOGRAPHY(Point)
for each table.
Inserting Data using GraphQL
You can populate the tables we just created with test data using the following mutations and variables:
Fetching list of landmarks around a user
In this example, we want to fetch a list of landmarks that are near a given user, along with the user’s details in the same query. PostGIS’ built-in function, ST_Distance
can be used to implement this use case.
Since our use-case requires an output that isn’t a “subset” of any of the existing tables i.e. the SETOF
table doesn’t exist, let’s first create this table and then create our location search function using the following definitions (once again, we’ll use the Data
-> SQL
section of the Hasura console):
This function fetches user information (for the given input userid
) and a list of landmarks which are less than distance_kms
kilometers away from the user’s location as a JSON field. We can now refer to this function in our GraphQL API and get the corresponding response as shown below:
query:
example response:
Conclusion
PostGIS also comes with a variety of other utility functions which you can use. You can find that list here.