How does one return and accept a geolocation type in GraphQL? Something that has a latitude
and longitude
?
Naive Implementation
The naive approach is to create a location type with a latitude and longitude.
This can be returned as field :location, Types::LocationType
in any GraphQL ObjectType
.
To accept a location in a mutation we create an input type with the same properties.
A query can ask for a location.
This needs to be wired to our MongoDB storage. I’m using mongoid-geospatial and saving locations as a Point. The latter can accept latitude and logitude but then stores these as x
and y
. The location type specifies property: :x
and property :y
where appropriate, which is used when converting a Point
into a LocationType
, while the mutation converts input to a hash that is fed into Point.new
automatically.
You can see this code in 33-minutes-server@c1fb00, in which I confused :x
and :y
coordinates of Point
. This was fixed in 33-minutes-server@9fc79d.
Custom GraphQL Scalar Type
The naive approach requires separate input and output types and the knowledge of a location internals (latitude, longitude). Lets elevate a location to a first class scalar type, similar to how dates and times are implemented and call this geo coordinates. I’m using geo_coord that can parse and format geo coordinates according to multiple existing conventions, such as pairs of latitude and longitude or a combination of degrees, minutes and seconds.
We need to implement Point#to_s
used above and convert a Geo::Coord
to a Hash
with latitude and longitude in our mutations to wire this up with mongoid-geospatial.
Note that Point
seems to implement support for latitude and longitude backwards. This is mongoid-geospatial#61.
This is implemented in 33-minutes-server@28f309.
Location Formats
The values passed back-and-forth are much more readable now and our API accepts standard notations (eg. 50.004444, 36.231389
or 50° 0′ 16″ N, 36° 13′ 53″ E
) and returns a location
as a string (eg. 50° 0′ 16″ N, 36° 13′ 53″ E
). This allows for seamless future improvements in the location formats, but burdens the client to parse a complex response.
The first attempt at easing this is to return a location in the simpler lat,lon
format.
We can do better and just return an array, as well as allow multiple kinds of location inputs.
This is implemented in 33-minutes-server@098ff1 and 33-minutes-server@cc159b.