Development Seed’s sat-api is an open-source library for creating a RESTful API to search catalogs of geospatial data. Historically, different imagery providers have had their own names for describing the data (metadata) and different APIs for accessing them. This has made the reuse of software difficult, and analysts jobs harder, as each source of data needs to be dealt with individually.

We created the first sat-api to facilitate access to Landsat-8 and Sentinel-2 in a consistent way, allowing reuse of software to search or access it. However, without a standard to follow we made decisions that worked for Landsat-8 and Sentinel-2, but not necessarily other types of geospatial data.

Then, last October after SoTM 2017 in Boulder, the first SpatioTemporal Asset Catalog (STAC)) working group convened, and has since grown, with the latest major release being v0.5. STAC is an initiative to define:

  1. a set of standard metadata fields describing geospatial data
  2. a flat file catalog structure used to describe a group of items (e.g., images) in a catalog
  3. a RESTful API for querying geospatial data

Prior to STAC, users searching for geospatial data had to use a separate approach for every provider and reconcile different formats. With STAC we hope to to get data providers to make STAC flat catalogs or APIs available for their data in order to allow for the reuse of client tools and a better user experience. Some of the major providers of satellite imagery such Planet and Digital Globe have already shown tremendous interest in the effort. Development Seed is also working on providing STAC flat catalogs for Earth on AWS datasets.

For more background on STAC, read Chris Holme’s post introducing STAC, it’s potential, and the first official release.

STAC flavored sat-api

The STAC initiative has come at a good time as we were working on a a new version of sat-api, and it was logical to make sat-api a reference implementation of the spec. We’ve been working at refactoring sat-api and are happy to announce this new version of sat-api, one that is compliant with the STAC spec (+ EO and Collections extensions).

Sat-api is a Node-based library that is deployable on AWS. We also maintain a deployed instance of it located at sat-api.developmentseed.org that contains the entire catalog of Landsat-8 and Sentinel-2 scenes on AWS. Going forward, we will keep sat-api up to date with the latest changes in STAC to make it as compliant as possible. This means there could be breaking changes, so we encourage users to deploy their own version of sat-api if they desire control over updates or need reliability. Users can also deploy their own versions to provide a STAC API to their own new or derived datasets.

Using sat-api

The main search endpoint for a STAC API is /search/stac, and it returns a GeoJSON FeatureCollection of STAC items. Querying the sat-api search endpoint without any parameters will match all items in the catalog and return the first result. The assets field is collapsed and will be discussed below.

{
    "type": "FeatureCollection",
    "properties": {
        "found": 6319206,
        "limit": 1,
        "page": 1
    },
    "features": [
        {
            "type": "Feature",
            "properties": {
                "id": "LC08_L1TP_026009_20150729_20170406_01_T1",
                "c:id": "landsat-8-l1",
                "datetime": "2015-07-29T16:44:13.782Z",
                "eo:cloud_cover": 89,
                "eo:sun_azimuth": 177.64085481,
                "eo:sun_elevation": 36.48367326,
                "landsat:path": 26,
                "landsat:row": 9
            },
            "bbox": [
                -75.29137,
                71.82026,
                -67.5855,
                72.51896
            ],
            "geometry": {
                "type": "Polygon",
                "coordinates": [
                    [
                        [
                            -67.5855,
                            72.51896
                        ],
                        [
                            -72.68982,
                            73.3833
                        ],
                        [
                            -75.29137,
                            71.82026
                        ],
                        [
                            -70.4913,
                            71.01562
                        ],
                        [
                            -67.5855,
                            72.51896
                        ]
                    ]
                ]
            },
            "assets": {...},
            "links": {
                "index": {
                    "href": "http://landsat-pds.s3.amazonaws.com/L8/026/009/LC80260092015210LGN00/index.html"
                },
                "self": {
                    "rel": "self",
                    "href": "https://sat-api.developmentseed.org/search/stac?id=LC08_L1TP_026009_20150729_20170406_01_T1"
                },
                "collection": {
                    "href": "https://sat-api.developmentseed.org/collections/landsat-8-l1/definition"
                }
            }
        }
    ]
}

Collections

The size of a STAC catalog can become very large when used with most satellite imagery datasets. This occurs because metadata fields are often duplicated across the millions of scenes that are available. To prevent this duplication sat-api also implements a STAC extension called Collections. A STAC collection can contain any core or extension metadata that might appear in a STAC item. The difference is that a collection also has a collection field as it’s name, and a STAC item can reference the collection through the collection property and link. The metadata in a STAC collection applies to all items that belong to that collection.

Here is the landsat-8 collection that the item above is a member of.

{
    "type": "FeatureCollection",
    "properties": {
        "found": 1,
        "limit": 1,
        "page": 1
    },
    "features": [
        {
            "type": "Feature",
            "properties": {
                "c:id": "landsat-8-l1",
                "c:name": "Landsat 8 L1",
                "c:description": "Landat 8 imagery radiometrically calibrated and orthorectified using gound points and Digital Elevation Model (DEM) data to correct relief displacement.",
                "provider": "USGS",
                "license": "PDDL-1.0",
                "eo:gsd": 30,
                "eo:platform": "landsat-8",
                "eo:instrument": "OLI_TIRS",
                "eo:off_nadir": 0
            },
            "links": [],
            "eo:bands": {
                "B1": {
                    "common_name": "coastal",
                    "gsd": 30,
                    "center_wavelength": 0.44,
                    "full_width_half_max": 0.02
                },
                "B2": {
                    "common_name": "blue",
                    "gsd": 30,
                    "center_wavelength": 0.48,
                    "full_width_half_max": 0.06
                },
                "B3": {
                    "common_name": "green",
                    "gsd": 30,
                    "center_wavelength": 0.56,
                    "full_width_half_max": 0.06
                },
                "B4": {
                    "common_name": "red",
                    "gsd": 30,
                    "center_wavelength": 0.65,
                    "full_width_half_max": 0.04
                },
                "B5": {
                    "common_name": "nir",
                    "gsd": 30,
                    "center_wavelength": 0.86,
                    "full_width_half_max": 0.03
                },
                "B6": {
                    "common_name": "swir16",
                    "gsd": 30,
                    "center_wavelength": 1.6,
                    "full_width_half_max": 0.08
                },
                "B7": {
                    "common_name": "swir22",
                    "gsd": 30,
                    "center_wavelength": 2.2,
                    "full_width_half_max": 0.2
                },
                "B8": {
                    "common_name": "pan",
                    "gsd": 15,
                    "center_wavelength": 0.59,
                    "full_width_half_max": 0.18
                },
                "B9": {
                    "common_name": "cirrus",
                    "gsd": 30,
                    "center_wavelength": 1.37,
                    "full_width_half_max": 0.02
                },
                "B10": {
                    "common_name": "lwir11",
                    "gsd": 100,
                    "center_wavelength": 10.9,
                    "full_width_half_max": 0.8
                },
                "B11": {
                    "common_name": "lwir12",
                    "gsd": 100,
                    "center_wavelength": 12,
                    "full_width_half_max": 1
                }
            }
        }
    ]
}

Assets

The assets field contains references to the actual data, in this case http URLs.
For each asset there is a key, which is a short unique identifier for the asset. “B1” here refers to the GeoTiff containing band 1, “ANG” is a metadata file contain detailed ephemeris data. For some of the assets, there is also an eo:bands field. This is a list containing references to the eo:bands field (shown above in the landsat-8 collection) that are contained in the file. This is how we can determine that B4 is the red band, B3 green, etc. without referring to outside documentation. In this example, each data file only contains one band, but other data source may contain multiple bands within a single file.

{
    "assets": {
        "ANG": {
            "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/162/032/LC08_L1TP_162032_20180308_20180320_01_T1/LC08_L1TP_162032_20180308_20180320_01_T1_ANG.txt"
        },
        "B1": {
            "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/162/032/LC08_L1TP_162032_20180308_20180320_01_T1/LC08_L1TP_162032_20180308_20180320_01_T1_B1.TIF",
            "eo:bands": ["B1"]
        },
        "B2": {
            "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/162/032/LC08_L1TP_162032_20180308_20180320_01_T1/LC08_L1TP_162032_20180308_20180320_01_T1_B2.TIF",
            "eo:bands": ["B2"]
        },
        "B3": {
            "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/162/032/LC08_L1TP_162032_20180308_20180320_01_T1/LC08_L1TP_162032_20180308_20180320_01_T1_B3.TIF",
            "eo:bands": ["B3"]
        },
        "B4": {
            "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/162/032/LC08_L1TP_162032_20180308_20180320_01_T1/LC08_L1TP_162032_20180308_20180320_01_T1_B4.TIF",
            "eo:bands": ["B4"]
        },
        "B5": {
            "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/162/032/LC08_L1TP_162032_20180308_20180320_01_T1/LC08_L1TP_162032_20180308_20180320_01_T1_B5.TIF",
            "eo:bands": ["B5"]
        },
        "B6": {
            "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/162/032/LC08_L1TP_162032_20180308_20180320_01_T1/LC08_L1TP_162032_20180308_20180320_01_T1_B6.TIF",
            "eo:bands": ["B6"]
        },
        "B7": {
            "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/162/032/LC08_L1TP_162032_20180308_20180320_01_T1/LC08_L1TP_162032_20180308_20180320_01_T1_B7.TIF",
            "eo:bands": ["B7"]
        },
        "B8": {
            "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/162/032/LC08_L1TP_162032_20180308_20180320_01_T1/LC08_L1TP_162032_20180308_20180320_01_T1_B8.TIF",
            "eo:bands": [
                "B8"
            ]
        },
        "B9": {
            "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/162/032/LC08_L1TP_162032_20180308_20180320_01_T1/LC08_L1TP_162032_20180308_20180320_01_T1_B9.TIF",
            "eo:bands": ["B9"]
        },
        "B10": {
            "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/162/032/LC08_L1TP_162032_20180308_20180320_01_T1/LC08_L1TP_162032_20180308_20180320_01_T1_B10.TIF",
            "eo:bands": ["B10"]
        },
        "B11": {
            "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/162/032/LC08_L1TP_162032_20180308_20180320_01_T1/LC08_L1TP_162032_20180308_20180320_01_T1_B11.TIF",
            "eo:bands": ["B11"]
        },
        "BQA": {
            "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/162/032/LC08_L1TP_162032_20180308_20180320_01_T1/LC08_L1TP_162032_20180308_20180320_01_T1_BQA.TIF"
        },
        "MTL": {
            "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/162/032/LC08_L1TP_162032_20180308_20180320_01_T1/LC08_L1TP_162032_20180308_20180320_01_T1_MTL.txt"
        },
        "thumbnail": {
            "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/162/032/LC08_L1TP_162032_20180308_20180320_01_T1/LC08_L1TP_162032_20180308_20180320_01_T1_thumb_large.jpg"
        }
    }
}

What’s next ?

We are currently working on improving the documentation and deploy process of sat-api to make it easier to use and more configurable so users can easily create a sat-api for their own data sources. We are also working on some client tools like sat-search, which will be the topic of my next post.

If you have an interest in contributing to sat-api please stop by the repo. We are actively looking for people to contribute, whether through testing, writing documentation or tutorials, or contributing the code base.

We're a team of engineers and designers working on big projects. We believe in open source and in building for lasting impact.

Learn more