Tom MacWright

tom@macwright.com

Falsehoods developers believe about GeoJSON

blurred

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