3DEP Elevation Source for Mapbox

I've been looking into the Microsoft Planetary Computer (MSPC) APIs lately, which include the STAC API (an API for querying and retrieving STAC elements in the catalog) and Data API (an API with lots of helper endpoints for STAC Item metadata and rendering). As I'm more or less familiar with STAC APIs, I've been specifically intrigued by the Data API.

This API includes endpoints for preview generation. For example, this preview, which uses the API as the image source:

The API also has a handy endpoint for generating a map for any STAC Item in the catalog.

There is a whole section in the API for generating and consuming mosaics, as well. I shared an example of consuming a mosaic of the USGS 3DEP Lidar Digital Surface Model dataset as an elevation source in Mapbox GL JS, and will explain the "elbow grease" I found necessary to make it happen:

The first step in consuming any mosaic from MSPC is to register a search, which (I assume) triggers the generation of a tilejson document for later. You do so by sending a POST request to the register endpoint, which will respond with a value for the searchid. You can then use the searchid in any of the various tiles endpoints in the Data API.

Ideally, we could simply make requests to one of the tiles endpoints within our client (in this case, Mapbox GL JS) to retrieve terrain tiles. Unfortunately, Mapbox terrain tiles must be in either terrarium or mapbox encoding, which I don't think are available directly from the API, although I could be wrong.

There are a multitude of parameters available within the tiles endpoints, which may allow encoding the tiles, but I found creating a proxy API the faster route to glory. You can find an example FastAPI implementation here, which accepts xyz tile coordinates, requests the necessary tile from MSPC, applies Terrarium encoding, and returns the encoded tile.

We can then hit the proxy API from the client. I've made a sample client here, just substitute your Mapbox token and API url.

That's it! It's a lot to digest, but have a look at the code and see if you can make sense of it. Let me know on Twitter or Mastodon how it goes!