This is a deployment of a Koop.js server as part of the Code for Pittsburgh food access map project.
The high-level idea is that we have a bunch of food access location data in a CSV with latlongs, and we have an ArcGIS Online web app to display those data, but we can only use critical AGOL features such as filter widgets if we make our data available in a format akin to an AGOL hosted feature layer. Enter Koop.js: an open-source project from Esri that creates a lightweight web server that ingests geospatial data from a variety of formats and makes it available in a variety of formats, including GeoServices which should meet our needs here.
I tried earlier to deploy a Koop server to Heroku, but was stymied by a mysterious bug that caused the deployed app to crash when the critical query
route was requested, even though that route worked fine in the heroku local
environment. In this repository, I'm setting up a Koop server and deploying it on Google App Engine, whose free quota should be sufficient to let us keep the Koop server up 24/7. We may need to recreate some or all of this work in an official C4P repository, but this is a start and maybe we can just fork it into the C4P GitHub account.
We're going to try a different tack, deploying a Koop server to Google App Engine. I've used Google Cloud Compute Engine before but haven't used App Engine. But App Engine seems to be very Heroku-like, which is what we want.
App Engine has a free quota of 28 instance-hours per day, and because I don't think we'll have more than one instance very often if at all, that should mean it should be effectively permanently free.
Per the Koop quickstart guide, Koop requires Node.js and npm
(which is a part of Node.js). So:
- Install Node.js. I installed version 12.18.3 LTS but I imagine the 14.10.0 Current version would work fine too.
- Verify that Node.js installation was successful by opening a terminal and typing
node -v
and/ornpm -v
. This latter command printed6.14.6
for me. - Type
npm install -g @koopjs/cli
to install the Koop CLI.
- In the parent directory of where you want the app to live (say,
C:\Users\drew\Documents\GitHub
), runkoop new app c4p-koop
. This will create a directory calledc4p-koop
and pre-populate a Git configuration, Node.js dependencies, etc. - If you already created a directory/repository, you can run
koop new app
and partially overwrite that repo with the Koop files, but it's cleaner to let Koop CLI create a fresh directory. - In the
c4p-koop
directory, you can runnpm start
to start the dev server (a quick server that is available locally for rapid development purposes). You can then visit http://localhost:8080/ to see the dev server in action. (Initially, all it does is display "Welcome to Koop!") You can also runkoop serve
and get the same result (I think). - We need the CSV provider, so within the
c4p-koop
directory, runkoop add provider koop-provider-csv
.
The basic idea of Koop is that it ingests data from any of several provider plugins, intermediately converts the data to GeoJSON, then exports data to any of several output plugins. Koop comes with the GeoServices output plugin already installed (because, as far as I can tell, making geospatial data available via the GeoServices API is the primary point of Koop) but we need to install the CSV provider plugin separately.
Helpful documentation here.
- Open
c4p-koop/config/default.json
in a text editor. - Define one or more CSV sources, following the format in the documentation.
- It might be helpful to assign an
idField
in the config file - Koop chirps at me that noidField
was set, but reassures me that it created anOBJECTID
field for me instead.
- Start the Koop dev server via
koop serve
and/ornpm start
(again, not sure whether there's a distinction). - Some trial and error (and some review of the GeoServices specification) yields the following endpoint as a location where the whole dataset will be returned in JSON format compatible with the GeoServices API: http://localhost:8080/koop-provider-csv/food-data/FeatureServer/0/query
- However, this combination of Koop provider (CSV) and output (GeoServices) plugins, by default, returns the first 2000 features only. Our dataset has more than 2000 features (we can tell because
exceededTransferLimit
istrue
), so we need to pass a URL parameter overriding this default limit. The Koop FAQ sheds some light on this - we can useresultRecordCount
to get more than 2000 results. We could just passresultRecordCount=999999
or some other very large number, but this is inelegant. The FAQ doesn't mention it but a lucky guess reveals thatresultRecordCount=-1
causes the endpoint to return all results: http://localhost:8080/koop-provider-csv/food-data/FeatureServer/0/query?resultRecordCount=-1
I drew some of these steps from this tutorial.
- Go to https://console.cloud.google.com/ and create an account if necessary.
- Create a new project (mine is called
c4p-koop
like this repository is). - Enable App Engine for this new project. We have to pick a region to locate the app; anyone can access the app but latency will be lower for people closer to this region. Because we're in Pittsburgh, we'll use
us-east4
, which is in northern Virginia, conveniently nearby. - Install Cloud SDK and run
gcloud init
in a terminal to set up thegcloud
command to work with this app.
The below steps are adapted from this guide.
- By default, Koop listens on a port defined in
config/default.json
. We need to change this to pull the port from the Node.jsprocess
global variable, so we editsrc/index.js
to tell the Koop server to listen atprocess.env.PORT
. (This step is the same as readying Koop for Heroku deployment.) - App Engine uses an
app.yaml
file to specify environment configuration. We create an empty file with this name, then add the lineruntime: nodejs12
. - Commit these changes to your repository. I'm not 100% sure this is necessary before App Engine deployment, but it couldn't hurt.
This guide was helpful.
- From the
c4p-koop
directory, rungcloud app deploy
. This will take a minute or two, but ran successfully on my first attempt. - Visit the live deployed app, either by running
gcloud app browse
in the terminal or by copy-pasting the URL shown during deployment. You'll see "Welcome to Koop!" - Finally, we can append the route we identified earlier to actually receive features from the App Engine deployment of Koop: https://c4p-koop.uk.r.appspot.com/koop-provider-csv/food-data/FeatureServer/0/query?resultRecordCount=-1
Notably, this just works, while deploying an identical app to Heroku crashed mysteriously when the critical query
route was requested. Well done, Google!