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.
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 thischeckbox 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 usetheData -> SQLsection of the Hasura console):
This function fetches user information (for the given inputuserid) 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.