Creating a GeoJSON FeatureCollection Type for GraphQL
Using a custom Scalar type to return feature geometry
I recently needed to return a GeoJSON FeatureCollection as a type for a GraphQL Server. I ran into a minor hurdle when trying to return the coordinates as a lon/lat array:
"coordinates": [0, 0]
There is not a standard GraphQL Type to handle this data structure. So you need to create a custom Scalar type.
If you want to save yourself the headache, you can add the graphql-geojson package for JS or the graphql-geojson-go package for Go. If you’d like to do it yourself, here is a brief summary of what I put together.
GeoJSON Schema
Here is a simple GeoJSON FeatureCollection schema that we’ll model for our GraphQL type, aFeatureCollection
with an array of Features
with Point
geometry:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-75, 40]
},
"properties": {
"id": 1
}
}
]
}
If you want to read more about GeoJSON, here is a great blog post and here is the official spec.
GraphQL Schema
We need to build our schema to follow the structure of the above GeoJSON. This example uses GraphQL.js and graphql-tools, but could be applied to any GraphQL spec. If you are not familiar with graphql-tools, here are the docs on generating a schema.
Here is our schema formatted for graphql-tools:
This schema is for a mock transit feed of bus locations. Stepping through our schema:
- From the
Query
we build out the GraphQL types that will map to a GeoJSON FeatureCollection. - The
FeatureCollection
type contains an array of thePointObject
type, these are the features. - Each
PointObject
contains aPointGeometry
andPointProps
for the geometry and properties respectively. - The
PointGeometry
type returns the point coordinates via our customCoordinates
scalar. - The
PointProps
type will return attributes specific to the feature.
Custom Scalar
Before we construct our resolver, we need to create our custom scalar to handle the coordinates array. Here is what it looks like:
What this is doing is returning whatever value is passed into the type. You will see below, we pass in an array of [lon, lat]
and that is exactly what is returned. Thanks to the graphql-geojson repo and Apollo docs for the code.
GraphQL Resolver
Now we can construct our resolver in the graphql-tools format and we’ll be all set. Here are the docs on writing resolvers with graphql-tools.
Here is our full resolver:
Each object in the resolver maps to a type
in our schema. The methods within each object resolve to their corresponding fields as described in the schema above.
GraphQL Request
To make a request that would return a properly constructed GeoJSON Feature Collection, you would submit something like this:
{
transit_feed {
type
features {
type
geometry {
type
coordinates
}
properties {
id
}
}
}
}
I hope you found this brief example helpful. If you’d like to see it in action, here it is as an Apollo Launchpad.