Falsehoods developers believe about GeoJSON
GeoJSON is a lovely, simple format. It’s one of the most important changes in the geospatial world, something that unlocked so much win. A little while ago I wrote a long article about everything about GeoJSON, but want to focus now on a few things that are often forgotten and lead to issues with implementations.
All GeoJSON is wrapped with a FeatureCollection
A lot of GeoJSON implementations will start with the assumption that all GeoJSON input is necessarily in the form of a FeatureCollection, and will optimistically expect features
to be an array on the given object. According to the specification, any GeoJSON object can be a root-level object.
A single bare Point geometry is valid GeoJSON
{ "type": "Point", "coordinates": [2, 30] }
And so is a single Feature object
{ "type": "Feature", "properties": { "hello": "Tom" }, "geometry": null }
To quickly band-aid libraries that expect FeatureCollections but advertise ‘GeoJSON support’, I wrote geojson-normalize.
Every feature has a geometry
Usually features in GeoJSON are a combination of geometry and properties: a shape and facts about it.
{ "type": "Feature",
"properties": {
"foo": "bar"
},
"geometry": {
"type": "Point",
"coordinates": [2, 30]
}
}
This causes a lot of developers to write code that looks for the type of a feature’s geometry, like
var featureGeometryType = feature.geometry.type;
This is a bug! In both the GeoJSON spec and IETF spec, the geometry
member of a feature can be null
. Features don’t need to have geometry.
All GeoJSON is WGS84
UPDATE: The IETF Standard, RFC 7946, has been approved, and this is now a… truehood? All GeoJSON data is now WGS84.
In the previous GeoJSON specification, projected data was supported in GeoJSON. It no longer is. Here is what it looked like:
{ "type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [2, 42]
},
"crs": {
"type": "name",
"properties": {
"name": "EPSG:28191"
} } }
Footnote tangent
Accessing feature.geometry.type
in GeoJSON is risky, since you’re trying to look two layers into an object, and the second layer, feature.geometry
, can be null. From using optionals, maybe types, and existential operators in Swift, Elm, and CoffeeScript, this JavaScript gotcha seems more and more preventable.
In Swift, for instance, you could write this idiomatic code that sidesteps the null (nil) issue:
if let geometryType = feature.geometry?.type {
print("The geometry is a \(geometryType)")
} else {
print("No geometry object.")
}
In Elm, you could write
getGeometryType feature =
case feature of
Just value ->
value.type
Nothing ->
Nothing
Fantasy Land gets us partially the way. There’s also an interesting discussion about the existential operator in JavaScript.
Footnote footnotes
- The land illustration above is also available as a standalone page for the EO1.
- Thanks to Jonathan Roberts for the map-drawing hints.