Skip to content

Instantly share code, notes, and snippets.

@chriswhong
Last active March 3, 2022 09:01
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save chriswhong/762ceac7fb8a1420e7e7adceb770b707 to your computer and use it in GitHub Desktop.
Save chriswhong/762ceac7fb8a1420e7e7adceb770b707 to your computer and use it in GitHub Desktop.
Using ST_AsMVT() and ST_AsMVTGeom() in express to build a vector tile endpoint
/* GET /tiles/:z/:x/:y.mvt */
/* Retreive a vector tile by tileid */
router.get('/tiles/:z/:x/:y.mvt', async (req, res) => {
const { z, x, y } = req.params;
// calculate the bounding polygon for this tile
const bbox = mercator.bbox(x, y, z, false);
// Query the database, using ST_AsMVTGeom() to clip the geometries
// Wrap the whole query with ST_AsMVT(), which will create a protocol buffer
const SQL = `
SELECT ST_AsMVT(q, 'internal-layer-name', 4096, 'geom')
FROM (
SELECT
somecolumn,
ST_AsMVTGeom(
geom,
ST_MakeEnvelope(${bbox[0]}, ${bbox[1]}, ${bbox[2]}, ${bbox[3]}, 4326),
4096,
256,
false
) geom
FROM sometable c
) q
`;
try {
const tile = await db.one(SQL);
// set the response header content type
res.setHeader('Content-Type', 'application/x-protobuf');
// trigger catch if the vector tile has no data, (return a 204)
if (tile.st_asmvt.length === 0) {
res.status(204);
}
// send the tile!
res.send(tile.st_asmvt);
} catch (e) {
res.status(404).send({
error: e.toString(),
});
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment