diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 61812ea6..b01579b8 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,6 +8,10 @@ updates: directory: "/stac" schedule: interval: "weekly" + - package-ecosystem: "cargo" + directory: "/pgstac" + schedule: + interval: "weekly" - package-ecosystem: "cargo" directory: "/stac-api" schedule: @@ -20,6 +24,10 @@ updates: directory: "/stac-cli" schedule: interval: "weekly" + - package-ecosystem: "cargo" + directory: "/stac-server" + schedule: + interval: "weekly" - package-ecosystem: "cargo" directory: "/stac-validate" schedule: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c175f86a..d55f1221 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,10 @@ jobs: - "-p stac -p stac-api -F geo" - "-p stac-async" - "-p stac-cli --no-default-features" + - "-p stac-server --no-default-features" + - "-p stac-server --no-default-features axum" + - "-p stac-server --no-default-features memory-item-search" + - "-p stac-server" - "-p stac-validate" steps: - uses: actions/checkout@v4 @@ -115,3 +119,45 @@ jobs: sudo apt-get install libgdal-dev - name: Doc run: cargo doc --all-features + validate-stac-server: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Rust cache + uses: Swatinem/rust-cache@v2 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + cache: "pip" + - name: Install stac-api-validator + run: pip install -r scripts/requirements.txt + - name: Validate + run: scripts/validate-stac-server + validate-stac-server-pgstac: + runs-on: ubuntu-latest + services: + pgstac: + image: ghcr.io/stac-utils/pgstac:v0.8.5 + env: + POSTGRES_USER: username + POSTGRES_PASSWORD: password + POSTGRES_DB: postgis + PGUSER: username + PGPASSWORD: password + PGDATABASE: postgis + ports: + - 5432:5432 + steps: + - uses: actions/checkout@v4 + - name: Set up Rust cache + uses: Swatinem/rust-cache@v2 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + cache: "pip" + - name: Install stac-api-validator + run: pip install -r scripts/requirements.txt + - name: Validate + run: scripts/validate-stac-server --pgstac diff --git a/Cargo.toml b/Cargo.toml index b65e50ee..ec37e9c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "stac-api", "stac-async", "stac-cli", + "stac-server", "stac-validate", ] default-members = [ @@ -13,5 +14,6 @@ default-members = [ "stac-api", "stac-async", "stac-cli", + "stac-server", "stac-validate", ] diff --git a/README.md b/README.md index dea143c1..7a7567e3 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Command Line Interface (CLI) and Rust libraries for the [SpatioTemporal Asset Ca - Use [stac-cli](./stac-cli/README.md) to query a STAC API, create and validate STAC items, and do other awesome stuff on the command line. - Use the core [stac](./stac/README.md) library to incorporate STAC data structures (`Item`, `Catalog`, and `Collection`) in another Rust application. - Use [stac-async](./stac-async/README.md) to build an application that uses async Rust via [tokio](https://tokio.rs/). +- Use [stac-server](./stac-server/README.md) to serve a STAC API ## Crates @@ -18,10 +19,11 @@ This monorepo contains several crates: | ----- | ---- | --------- | | [stac](./stac/README.md) | Core data structures and synchronous I/O | [![docs.rs](https://img.shields.io/docsrs/stac?style=flat-square)](https://docs.rs/stac/latest/stac/)
[![Crates.io](https://img.shields.io/crates/v/stac?style=flat-square)](https://crates.io/crates/stac) | | [pgstac](./pgstac/README.md) | Bindings for [pgstac](https://github.com/stac-utils/pgstac) | [![docs.rs](https://img.shields.io/docsrs/pgstac?style=flat-square)](https://docs.rs/pgstac/latest/pgstac/)
[![Crates.io](https://img.shields.io/crates/v/pgstac?style=flat-square)](https://crates.io/crates/pgstac) | -| [stac-validate](./stac-validate/README.md) | Validate STAC data structures with [jsonschema](https://json-schema.org/) | [![docs.rs](https://img.shields.io/docsrs/stac-validate?style=flat-square)](https://docs.rs/stac-validate/latest/stac-validate/)
[![Crates.io](https://img.shields.io/crates/v/stac-validate?style=flat-square)](https://crates.io/crates/stac-validate) | | [stac-api](./stac-api/README.md) | Data structures for the [STAC API](https://github.com/radiantearth/stac-api-spec) specification | [![docs.rs](https://img.shields.io/docsrs/stac-api?style=flat-square)](https://docs.rs/stac-api/latest/stac_api/)
[![Crates.io](https://img.shields.io/crates/v/stac-api?style=flat-square)](https://crates.io/crates/stac-api) | | [stac-async](./stac-async/README.md) | Asynchronous I/O with [tokio](https://tokio.rs/) | [![docs.rs](https://img.shields.io/docsrs/stac-async?style=flat-square)](https://docs.rs/stac-async/latest/stac_async/)
[![Crates.io](https://img.shields.io/crates/v/stac-async?style=flat-square)](https://crates.io/crates/stac-async) | | [stac-cli](./stac-cli/README.md)| Command line interface | [![docs.rs](https://img.shields.io/docsrs/stac-cli?style=flat-square)](https://docs.rs/stac-cli/latest/stac_cli/)
[![Crates.io](https://img.shields.io/crates/v/stac-cli?style=flat-square)](https://crates.io/crates/stac-cli) | +| [stac-server](./stac-server/README.md)| STAC API server with multiple backends | [![docs.rs](https://img.shields.io/docsrs/stac-server?style=flat-square)](https://docs.rs/stac-server/latest/stac_server/)
[![Crates.io](https://img.shields.io/crates/v/stac-server?style=flat-square)](https://crates.io/crates/stac-server) | +| [stac-validate](./stac-validate/README.md) | Validate STAC data structures with [jsonschema](https://json-schema.org/) | [![docs.rs](https://img.shields.io/docsrs/stac-validate?style=flat-square)](https://docs.rs/stac-validate/latest/stac-validate/)
[![Crates.io](https://img.shields.io/crates/v/stac-validate?style=flat-square)](https://crates.io/crates/stac-validate) | ## Development diff --git a/scripts/requirements.in b/scripts/requirements.in new file mode 100644 index 00000000..e5e79181 --- /dev/null +++ b/scripts/requirements.in @@ -0,0 +1 @@ +stac-api-validator @ git+https://github.com/stac-utils/stac-api-validator@24dd3f27174e5c85f28a44c84ad584a2d344e6cc diff --git a/scripts/requirements.txt b/scripts/requirements.txt new file mode 100644 index 00000000..71a8f3e2 --- /dev/null +++ b/scripts/requirements.txt @@ -0,0 +1,80 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile scripts/requirements.in +attrs==23.2.0 + # via + # jsonschema + # referencing +certifi==2024.2.2 + # via + # requests + # stac-api-validator +charset-normalizer==3.3.2 + # via requests +click==8.1.7 + # via + # stac-api-validator + # stac-check + # stac-validator +deepdiff==6.7.1 + # via stac-api-validator +idna==3.7 + # via requests +jsonschema==4.21.1 + # via + # pystac + # stac-api-validator + # stac-check + # stac-validator +jsonschema-specifications==2023.12.1 + # via jsonschema +more-itertools==8.14.0 + # via stac-api-validator +numpy==1.26.4 + # via shapely +ordered-set==4.1.0 + # via deepdiff +orjson==3.10.1 + # via pystac +pystac==1.10.0 + # via + # pystac-client + # stac-api-validator +pystac-client==0.7.7 + # via stac-api-validator +python-dateutil==2.9.0.post0 + # via + # pystac + # pystac-client +python-dotenv==1.0.1 + # via stac-check +pyyaml==6.0.1 + # via + # stac-api-validator + # stac-check +referencing==0.35.0 + # via + # jsonschema + # jsonschema-specifications +requests==2.31.0 + # via + # pystac-client + # stac-api-validator + # stac-check + # stac-validator +rpds-py==0.18.0 + # via + # jsonschema + # referencing +shapely==2.0.4 + # via stac-api-validator +six==1.16.0 + # via python-dateutil +stac-api-validator @ git+https://github.com/stac-utils/stac-api-validator@24dd3f27174e5c85f28a44c84ad584a2d344e6cc +stac-check==1.3.3 + # via stac-api-validator +stac-validator==3.3.2 + # via + # stac-api-validator + # stac-check +urllib3==2.2.1 + # via requests diff --git a/scripts/validate-stac-server b/scripts/validate-stac-server new file mode 100755 index 00000000..71424e14 --- /dev/null +++ b/scripts/validate-stac-server @@ -0,0 +1,34 @@ +#!/usr/bin/env sh + +set -e + +args="stac-server/data/sentinel-2/*" +build_args="--no-default-features" + +if [ $# -eq 1 ]; then + if [ "$1" = "--pgstac" ]; then + args="$args --pgstac postgres://username:password@localhost/postgis" + build_args="$build_args -F pgstac" + else + echo "Unknown argument: $1" + exit 1 + fi +fi + +cargo build -p stac-cli $build_args +cargo run $build_args -- serve $args & +server_pid=$! +echo "server_pid=$server_pid" +set +e +scripts/wait-for-it.sh localhost:7822 && \ + stac-api-validator \ + --root-url http://localhost:7822 \ + --conformance core \ + --conformance features \ + --conformance item-search \ + --collection sentinel-2-c1-l2a \ + --geometry '{"type":"Point","coordinates":[-105.07,40.08]}' +status=$? +set -e +kill $server_pid +exit $status diff --git a/scripts/wait-for-it.sh b/scripts/wait-for-it.sh new file mode 100755 index 00000000..8fa2a7d6 --- /dev/null +++ b/scripts/wait-for-it.sh @@ -0,0 +1,184 @@ +#!/usr/bin/env bash +# Use this script to test if a given TCP host/port are available +# https://github.com/vishnubob/wait-for-it/blob/81b1373f17855a4dc21156cfe1694c31d7d1792e/wait-for-it.sh + +WAITFORIT_cmdname=${0##*/} + +echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } + +usage() +{ + cat << USAGE >&2 +Usage: + $WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args] + -h HOST | --host=HOST Host or IP under test + -p PORT | --port=PORT TCP port under test + Alternatively, you specify the host and port as host:port + -s | --strict Only execute subcommand if the test succeeds + -q | --quiet Don't output any status messages + -t TIMEOUT | --timeout=TIMEOUT + Timeout in seconds, zero for no timeout + -- COMMAND ARGS Execute command with args after the test finishes +USAGE + exit 1 +} + +wait_for() +{ + if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then + echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" + else + echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout" + fi + WAITFORIT_start_ts=$(date +%s) + while : + do + if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then + nc -z $WAITFORIT_HOST $WAITFORIT_PORT + WAITFORIT_result=$? + else + (echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1 + WAITFORIT_result=$? + fi + if [[ $WAITFORIT_result -eq 0 ]]; then + WAITFORIT_end_ts=$(date +%s) + echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds" + break + fi + sleep 1 + done + return $WAITFORIT_result +} + +wait_for_wrapper() +{ + # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 + if [[ $WAITFORIT_QUIET -eq 1 ]]; then + timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & + else + timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & + fi + WAITFORIT_PID=$! + trap "kill -INT -$WAITFORIT_PID" INT + wait $WAITFORIT_PID + WAITFORIT_RESULT=$? + if [[ $WAITFORIT_RESULT -ne 0 ]]; then + echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" + fi + return $WAITFORIT_RESULT +} + +# process arguments +while [[ $# -gt 0 ]] +do + case "$1" in + *:* ) + WAITFORIT_hostport=(${1//:/ }) + WAITFORIT_HOST=${WAITFORIT_hostport[0]} + WAITFORIT_PORT=${WAITFORIT_hostport[1]} + shift 1 + ;; + --child) + WAITFORIT_CHILD=1 + shift 1 + ;; + -q | --quiet) + WAITFORIT_QUIET=1 + shift 1 + ;; + -s | --strict) + WAITFORIT_STRICT=1 + shift 1 + ;; + -h) + WAITFORIT_HOST="$2" + if [[ $WAITFORIT_HOST == "" ]]; then break; fi + shift 2 + ;; + --host=*) + WAITFORIT_HOST="${1#*=}" + shift 1 + ;; + -p) + WAITFORIT_PORT="$2" + if [[ $WAITFORIT_PORT == "" ]]; then break; fi + shift 2 + ;; + --port=*) + WAITFORIT_PORT="${1#*=}" + shift 1 + ;; + -t) + WAITFORIT_TIMEOUT="$2" + if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi + shift 2 + ;; + --timeout=*) + WAITFORIT_TIMEOUT="${1#*=}" + shift 1 + ;; + --) + shift + WAITFORIT_CLI=("$@") + break + ;; + --help) + usage + ;; + *) + echoerr "Unknown argument: $1" + usage + ;; + esac +done + +if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then + echoerr "Error: you need to provide a host and port to test." + usage +fi + +WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15} +WAITFORIT_STRICT=${WAITFORIT_STRICT:-0} +WAITFORIT_CHILD=${WAITFORIT_CHILD:-0} +WAITFORIT_QUIET=${WAITFORIT_QUIET:-0} + +# Check to see if timeout is from busybox? +WAITFORIT_TIMEOUT_PATH=$(type -p timeout) +WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH) + +WAITFORIT_BUSYTIMEFLAG="" +if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then + WAITFORIT_ISBUSY=1 + # Check if busybox timeout uses -t flag + # (recent Alpine versions don't support -t anymore) + if timeout &>/dev/stdout | grep -q -e '-t '; then + WAITFORIT_BUSYTIMEFLAG="-t" + fi +else + WAITFORIT_ISBUSY=0 +fi + +if [[ $WAITFORIT_CHILD -gt 0 ]]; then + wait_for + WAITFORIT_RESULT=$? + exit $WAITFORIT_RESULT +else + if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then + wait_for_wrapper + WAITFORIT_RESULT=$? + else + wait_for + WAITFORIT_RESULT=$? + fi +fi + +if [[ $WAITFORIT_CLI != "" ]]; then + if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then + echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess" + exit $WAITFORIT_RESULT + fi + exec "${WAITFORIT_CLI[@]}" +else + exit $WAITFORIT_RESULT +fi + diff --git a/stac-api/CHANGELOG.md b/stac-api/CHANGELOG.md index 829559f3..13c6a7c6 100644 --- a/stac-api/CHANGELOG.md +++ b/stac-api/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - `Conformance` builder functions ([#247](https://github.com/stac-utils/stac-rs/pull/247)) - Un-serialized pagination members to `ItemCollection` ([#247](https://github.com/stac-utils/stac-rs/pull/247)) - `stac::Fields` for `Search` and `Items` ([#247](https://github.com/stac-utils/stac-rs/pull/247)) +- `Items::valid` and `Search::valid` ([#244](https://github.com/stac-utils/stac-rs/pull/244)) ### Changed @@ -19,6 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Removed - `schemars` feature ([#245](https://github.com/stac-utils/stac-rs/pull/245)) +- `Search::validate` ([#244](https://github.com/stac-utils/stac-rs/pull/244)) ## [0.3.3] - 2024-04-07 diff --git a/stac-api/Cargo.toml b/stac-api/Cargo.toml index 6703f10a..3125e5bc 100644 --- a/stac-api/Cargo.toml +++ b/stac-api/Cargo.toml @@ -14,6 +14,7 @@ categories = ["science", "data-structures", "web-programming"] geo = ["dep:geo", "stac/geo"] [dependencies] +chrono = "0.4" geo = { version = "0.28", optional = true } geojson = "0.24" serde = "1" diff --git a/stac-api/src/error.rs b/stac-api/src/error.rs index 0b3e903a..affcf159 100644 --- a/stac-api/src/error.rs +++ b/stac-api/src/error.rs @@ -1,4 +1,5 @@ use crate::Search; +use chrono::{DateTime, FixedOffset}; use serde_json::{Map, Value}; use thiserror::Error; @@ -16,14 +17,26 @@ pub enum Error { #[error("cannot convert cql2-json to strings")] CannotConvertCql2JsonToString(Map), + /// [chrono::ParseError] + #[error(transparent)] + ChronoParse(#[from] chrono::ParseError), + /// [geojson::Error] #[error(transparent)] GeoJson(#[from] geojson::Error), + /// An empty datetime interval. + #[error("empty datetime interval")] + EmptyDatetimeInterval, + /// Some functionality requires a certain optional feature to be enabled. #[error("feature not enabled: {0}")] FeatureNotEnabled(&'static str), + /// Invalid bounding box. + #[error("invalid bbox ({0:?}): {1}")] + InvalidBbox(Vec, &'static str), + /// [std::num::ParseIntError] #[error(transparent)] ParseIntError(#[from] std::num::ParseIntError), @@ -48,6 +61,10 @@ pub enum Error { #[error(transparent)] Stac(#[from] stac::Error), + /// The start time is after the end time. + #[error("start ({0}) is after end ({1})")] + StartIsAfterEnd(DateTime, DateTime), + /// [std::num::TryFromIntError] #[error(transparent)] TryFromInt(#[from] std::num::TryFromIntError), diff --git a/stac-api/src/items.rs b/stac-api/src/items.rs index a7d81c90..08369d73 100644 --- a/stac-api/src/items.rs +++ b/stac-api/src/items.rs @@ -1,4 +1,5 @@ use crate::{Error, Fields, Filter, Result, Search, Sortby}; +use chrono::{DateTime, FixedOffset}; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use stac::Item; @@ -100,6 +101,62 @@ pub struct GetItems { } impl Items { + /// Runs a set of validity checks on this query and returns an error if it is invalid. + /// + /// Returns the items, unchanged, if it is valid. + /// + /// # Examples + /// + /// ``` + /// use stac_api::Items; + /// + /// let items = Items::default().valid().unwrap(); + /// ``` + pub fn valid(self) -> Result { + if let Some(bbox) = self.bbox.as_ref() { + if bbox.len() == 4 { + if bbox[1] > bbox[3] { + return Err(Error::InvalidBbox( + bbox.clone(), + "min latitude is greater than max latitude", + )); + } + } else if bbox.len() == 6 { + if bbox[1] > bbox[4] { + return Err(Error::InvalidBbox( + bbox.clone(), + "min latitude is greater than max latitude", + )); + } + } else { + return Err(Error::InvalidBbox( + bbox.clone(), + "invalid number of coordinates", + )); + } + } + if let Some(datetime) = self.datetime.as_deref() { + if let Some((start, end)) = datetime.split_once('/') { + let (start, end) = ( + maybe_parse_from_rfc3339(start)?, + maybe_parse_from_rfc3339(end)?, + ); + if let Some(start) = start { + if let Some(end) = end { + if end < start { + return Err(Error::StartIsAfterEnd(start, end)); + } + } + } else if end.is_none() { + return Err(Error::EmptyDatetimeInterval); + } + } else { + let _ = maybe_parse_from_rfc3339(datetime)?; + } + } + Ok(self) + } + /// Returns true if this items structure matches the given item. /// /// # Examples @@ -350,6 +407,16 @@ impl stac::Fields for Items { } } +fn maybe_parse_from_rfc3339(s: &str) -> Result>> { + if s.is_empty() || s == ".." { + Ok(None) + } else { + DateTime::parse_from_rfc3339(s) + .map(Some) + .map_err(Error::from) + } +} + #[cfg(test)] mod tests { use super::{GetItems, Items}; diff --git a/stac-api/src/search.rs b/stac-api/src/search.rs index 3a482fd3..b7a27fe2 100644 --- a/stac-api/src/search.rs +++ b/stac-api/src/search.rs @@ -77,9 +77,9 @@ impl Search { self } - /// Validates this search. + /// Returns an error if this search is invalid, e.g. if both bbox and intersects are specified. /// - /// E.g. the search is invalid if both bbox and intersects are specified. + /// Returns the search unchanged if it is valid. /// /// # Examples /// @@ -89,15 +89,16 @@ impl Search { /// /// let mut search = Search::default(); /// search.items.bbox = Some(vec![-180.0, -90.0, 180.0, 80.0]); - /// search.validate().unwrap(); + /// search = search.valid().unwrap(); /// search.intersects = Some(Geometry::new(Value::Point(vec![0.0, 0.0]))); - /// let _ = search.validate().unwrap_err(); + /// search.valid().unwrap_err(); /// ``` - pub fn validate(&self) -> Result<()> { + pub fn valid(mut self) -> Result { + self.items = self.items.valid()?; if self.items.bbox.is_some() & self.intersects.is_some() { Err(Error::SearchHasBboxAndIntersects(self.clone())) } else { - Ok(()) + Ok(self) } } diff --git a/stac-cli/CHANGELOG.md b/stac-cli/CHANGELOG.md index df22c834..2f29b64f 100644 --- a/stac-cli/CHANGELOG.md +++ b/stac-cli/CHANGELOG.md @@ -7,6 +7,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Added + +- `stac serve` ([#244](https://github.com/stac-utils/stac-rs/pull/244)) + ## [0.0.8] - 2024-04-22 ### Added diff --git a/stac-cli/Cargo.toml b/stac-cli/Cargo.toml index 170c10e5..1a4417be 100644 --- a/stac-cli/Cargo.toml +++ b/stac-cli/Cargo.toml @@ -11,19 +11,25 @@ keywords = ["geospatial", "stac", "metadata", "geo", "raster"] categories = ["science", "data-structures"] [features] -default = ["gdal"] +default = ["gdal", "pgstac"] gdal = ["stac/gdal"] +pgstac = ["dep:pgstac", "stac-server/pgstac"] [dependencies] +axum = "0.7" clap = { version = "4", features = ["derive"] } console = "0.15" indicatif = "0.17" +pgstac = { version = "0.0.6", path = "../pgstac", optional = true } reqwest = "0.12" serde = "1" serde_json = "1" stac = { version = "0.6", path = "../stac" } stac-api = { version = "0.3", path = "../stac-api" } stac-async = { version = "0.5", path = "../stac-async" } +stac-server = { version = "0.1", path = "../stac-server", features = [ + "memory-item-search", +] } stac-validate = { version = "0.1", path = "../stac-validate" } thiserror = "1" tokio = { version = "1.23", features = ["macros", "rt-multi-thread"] } diff --git a/stac-cli/src/args.rs b/stac-cli/src/args.rs index e1bbbc7f..732d13ee 100644 --- a/stac-cli/src/args.rs +++ b/stac-cli/src/args.rs @@ -5,8 +5,10 @@ use serde_json::json; use stac::{item::Builder, Asset, Value}; use stac_api::{GetItems, GetSearch, Item, ItemCollection}; use stac_async::ApiClient; +use stac_server::{Api, Backend, MemoryBackend}; use stac_validate::Validate; use std::path::Path; +use tokio::net::TcpListener; use tokio_stream::StreamExt; use url::Url; @@ -77,6 +79,7 @@ impl Args { ) .await } + Serve { href, pgstac } => self.serve(&href, pgstac.as_deref()).await, Sort { href } => self.sort(href.as_deref()).await, Validate { href } => self.validate(href.as_deref()).await, }; @@ -224,6 +227,41 @@ impl Args { Ok(()) } + #[allow(unused_variables)] // for `pgstac` if we don't compile with it + async fn serve(&self, hrefs: &[String], pgstac: Option<&str>) -> Result<()> { + let root = "http://127.0.0.1:7822"; + let addr = "127.0.0.1:7822"; + if let Some(pgstac) = pgstac { + #[cfg(feature = "pgstac")] + { + let mut backend = stac_server::PgstacBackend::new_from_stringlike(pgstac).await?; + if !hrefs.is_empty() { + backend.add_from_hrefs(hrefs).await?; + } + let api = Api::new(backend, root)?; + let router = stac_server::routes::from_api(api); + let listener = TcpListener::bind(addr).await.unwrap(); + println!("Serving a STAC API at {} using a pgstac backend", root); + axum::serve(listener, router).await.unwrap(); + } + #[cfg(not(feature = "pgstac"))] + return Err(Error::Custom(format!( + "stac-cli is not compiled with pgstac support" + ))); + } else { + let mut backend = MemoryBackend::new(); + if !hrefs.is_empty() { + backend.add_from_hrefs(hrefs).await?; + } + let api = Api::new(backend, root)?; + let router = stac_server::routes::from_api(api); + let listener = TcpListener::bind(addr).await.unwrap(); + println!("Serving a STAC API at {} using a memory backend", root); + axum::serve(listener, router).await.unwrap(); + }; + Ok(()) + } + async fn sort(&self, href: Option<&str>) -> Result<()> { let value: Value = self.read_href(href).await?; self.println(value) diff --git a/stac-cli/src/error.rs b/stac-cli/src/error.rs index fee7041e..fac5815d 100644 --- a/stac-cli/src/error.rs +++ b/stac-cli/src/error.rs @@ -21,6 +21,9 @@ pub enum Error { #[error(transparent)] StacAsync(#[from] stac_async::Error), + #[error(transparent)] + StacServer(#[from] stac_server::Error), + #[error(transparent)] StacValidate(#[from] stac_validate::Error), diff --git a/stac-cli/src/subcommand.rs b/stac-cli/src/subcommand.rs index 66b317e5..a53fea69 100644 --- a/stac-cli/src/subcommand.rs +++ b/stac-cli/src/subcommand.rs @@ -103,6 +103,20 @@ pub enum Subcommand { stream: bool, }, + /// Serves a STAC API. + /// + /// By default, uses a basic memory backend, which is not suitable for + /// production. To use the pgstac backend, pass the pgstac connection string + /// to the `--pgstac` argument. + Serve { + /// Hrefs of STAC collections and items to load before starting the server. + href: Vec, + + /// The pgstac connection string. + #[arg(long)] + pgstac: Option, + }, + /// Sorts the fields of STAC object. Sort { /// The href of the STAC object. diff --git a/stac-server/CHANGELOG.md b/stac-server/CHANGELOG.md new file mode 100644 index 00000000..24503400 --- /dev/null +++ b/stac-server/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased diff --git a/stac-server/Cargo.toml b/stac-server/Cargo.toml new file mode 100644 index 00000000..545e7165 --- /dev/null +++ b/stac-server/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "stac-server" +version = "0.1.0" +edition = "2021" + +[features] +default = ["axum", "memory-item-search"] +axum = ["dep:axum"] +memory-item-search = ["stac-api/geo"] +pgstac = ["dep:pgstac", "dep:bb8", "dep:bb8-postgres", "dep:tokio-postgres"] + +[dependencies] +async-trait = "0.1" +axum = { version = "0.7", optional = true } +bb8 = { version = "0.8", optional = true } +bb8-postgres = { version = "0.8", optional = true } +http = "1" +pgstac = { version = "0.0.6", path = "../pgstac", optional = true } +serde = "1" +serde_json = "1" +serde_urlencoded = "0.7" +stac = { version = "0.6", path = "../stac" } +stac-api = { version = "0.3", path = "../stac-api" } +stac-async = { version = "0.5", path = "../stac-async" } +thiserror = "1" +tokio-postgres = { version = "0.7", optional = true } +url = "2" + +[dev-dependencies] +serde_json = "1" +stac-validate = { version = "0.1", path = "../stac-validate" } +tokio = { version = "1.37", features = ["macros"] } +tokio-test = "0.4" +tower = "0.4" diff --git a/stac-server/README.md b/stac-server/README.md new file mode 100644 index 00000000..30938d5d --- /dev/null +++ b/stac-server/README.md @@ -0,0 +1,82 @@ +# stac-server + +[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/stac-utils/stac-rs/ci.yml?branch=main&style=for-the-badge)](https://github.com/stac-utils/stac-rs/actions/workflows/ci.yml) +[![docs.rs](https://img.shields.io/docsrs/stac-server?style=for-the-badge)](https://docs.rs/stac-server/latest/stac_server/) +[![Crates.io](https://img.shields.io/crates/v/stac-server?style=for-the-badge)](https://crates.io/crates/stac-server) +![Crates.io](https://img.shields.io/crates/l/stac-server?style=for-the-badge) +[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg?style=for-the-badge)](./CODE_OF_CONDUCT) + +A [STAC API](https://github.com/radiantearth/stac-api-spec) server with multiple backends. + +## Usage + +To run a server from the command-line, use [stac-cli](../stac-cli/README.md). +Any arguments will be interpreted as hrefs to STAC collections, items, and item collections, and will be loaded into the server on startup. + +```shell +stac serve collection.json items.json +``` + +To use the [pgstac](https://github.com/stac-utils/pgstac) backend: + +```shell +stac serve --pgstac postgresql://username:password@localhost:5432/postgis +``` + +### Library + +To use this library in another application: + +```toml +[dependencies] +stac-server = "0.1" +``` + +### Deploying + +There is currently no infrastructure-as-code for deploying **stac-server**. +We hope to provide this support in the future. + +### Features + +**stac-server** has three features, two of which are enabled by default. + +#### axum + +The `axum` feature is on by default and enables routing and serving using [axum](https://github.com/tokio-rs/axum). +If you want to use the `Api` functionality with a different web framework, you can depend on this library and disable the `axum` feature. + +#### memory-item-search + +In order to search with the naïve memory backend, we need the `geo` feature on the **stac** crate. +If you aren't using the memory backend, you can disable the `memory-item-search` feature, which is enabled by default. + +#### pgstac + +In order to use the [pgstac](https://github.com/stac-utils/pgstac), you need to enable the `pgstac` feature. + +## Backends + +This table lists the provided backends and their supported conformance classes and extensions: + +| Capability | Memory backend | Pgstac backend | +| -- | -- | -- | +| [STAC API - Core](https://github.com/radiantearth/stac-api-spec/blob/release/v1.0.0/core) | ✅ | ✅ | +| [STAC API - Features](https://github.com/radiantearth/stac-api-spec/blob/release/v1.0.0/ogcapi-features) | ✅ | ✅ | +| [STAC API - Item Search](https://github.com/radiantearth/stac-api-spec/blob/release/v1.0.0/item-search) | ✅ | ✅ | +| [Aggregation extension](https://github.com/stac-api-extensions/aggregation) | ✖️ | ✖️ | +| [Browseable extension](https://github.com/stac-api-extensions/browseable) | ✖️ | ✖️ | +| [Children extension](https://github.com/stac-api-extensions/children) | ✖️ | ✖️ | +| [Collection search extension](https://github.com/stac-api-extensions/collection-search) | ✖️ | ✖️ | +| [Collection transaction extension](https://github.com/stac-api-extensions/collection-transaction) | ✖️ | ✖️ | +| [Fields extension](https://github.com/stac-api-extensions/fields) | ✖️ | ✖️ | +| [Filter extension](https://github.com/stac-api-extensions/filter) | ✖️ | ✖️ | +| [Free-text search extension](https://github.com/stac-api-extensions/freetext-search) | ✖️ | ✖️ | +| [Language (I18N) extension](https://github.com/stac-api-extensions/language) | ✖️ | ✖️ | +| [Query extension](https://github.com/stac-api-extensions/query) | ✖️ | ✖️ | +| [Sort extension](https://github.com/stac-api-extensions/sort) | ✖️ | ✖️ | +| [Transaction extension](https://github.com/stac-api-extensions/transaction) | ✖️ | ✖️ | + +## Other info + +This crate is part of the [stac-rs](https://github.com/stac-utils/stac-rs) monorepo, see its README for contributing and license information. diff --git a/stac-server/data/joplin/collection.json b/stac-server/data/joplin/collection.json new file mode 100644 index 00000000..992e64b9 --- /dev/null +++ b/stac-server/data/joplin/collection.json @@ -0,0 +1,34 @@ +{ + "id": "joplin", + "description": "This imagery was acquired by the NOAA Remote Sensing Division to support NOAA national security and emergency response requirements. In addition, it will be used for ongoing research efforts for testing and developing standards for airborne digital imagery. Individual images have been combined into a larger mosaic and tiled for distribution. The approximate ground sample distance (GSD) for each pixel is 35 cm (1.14 feet).", + "stac_version": "1.0.0", + "license": "public-domain", + "links": [ + { + "rel": "license", + "href": "https://creativecommons.org/licenses/publicdomain/", + "title": "public domain" + } + ], + "type": "Collection", + "extent": { + "spatial": { + "bbox": [ + [ + -94.6911621, + 37.0332547, + -94.402771, + 37.1077651 + ] + ] + }, + "temporal": { + "interval": [ + [ + "2000-02-01T00:00:00Z", + "2000-02-12T00:00:00Z" + ] + ] + } + } +} diff --git a/stac-server/data/joplin/feature.geojson b/stac-server/data/joplin/feature.geojson new file mode 100644 index 00000000..47db3190 --- /dev/null +++ b/stac-server/data/joplin/feature.geojson @@ -0,0 +1,59 @@ +{ + "id": "f2cca2a3-288b-4518-8a3e-a4492bb60b08", + "type": "Feature", + "collection": "joplin", + "links": [], + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -94.6884155, + 37.0595608 + ], + [ + -94.6884155, + 37.0332547 + ], + [ + -94.6554565, + 37.0332547 + ], + [ + -94.6554565, + 37.0595608 + ], + [ + -94.6884155, + 37.0595608 + ] + ] + ] + }, + "properties": { + "proj:epsg": 3857, + "orientation": "nadir", + "height": 2500, + "width": 2500, + "datetime": "2000-02-02T00:00:00Z", + "gsd": 0.5971642834779395 + }, + "assets": { + "COG": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "href": "https://arturo-stac-api-test-data.s3.amazonaws.com/joplin/images/may24C350000e4102500n.tif", + "title": "NOAA STORM COG" + } + }, + "bbox": [ + -94.6884155, + 37.0332547, + -94.6554565, + 37.0595608 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/projection/v1.0.0/schema.json" + ], + "stac_version": "1.0.0" +} \ No newline at end of file diff --git a/stac-server/data/sentinel-2/collection.json b/stac-server/data/sentinel-2/collection.json new file mode 100644 index 00000000..445115e5 --- /dev/null +++ b/stac-server/data/sentinel-2/collection.json @@ -0,0 +1,925 @@ +{ + "type": "Collection", + "id": "sentinel-2-c1-l2a", + "title": "Sentinel-2 Collection 1 Level-2A", + "description": "Sentinel-2 Collection 1 L2A, data from the Multispectral Instrument (MSI) onboard Sentinel-2", + "stac_version": "1.0.0", + "links": [ + { + "rel": "self", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "cite-as", + "href": "https://doi.org/10.5270/S2_-742ikth", + "title": "Copernicus Sentinel-2 MSI Level-2A (L2A) Bottom-of-Atmosphere Radiance" + }, + { + "rel": "license", + "href": "https://sentinel.esa.int/documents/247904/690755/Sentinel_Data_Legal_Notice", + "title": "proprietary" + }, + { + "rel": "parent", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1" + }, + { + "rel": "root", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1" + }, + { + "rel": "items", + "type": "application/geo+json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items" + }, + { + "rel": "http://www.opengis.net/def/rel/ogc/1.0/queryables", + "type": "application/schema+json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/queryables" + }, + { + "rel": "aggregate", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/aggregate", + "method": "GET" + }, + { + "rel": "aggregations", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/aggregations" + } + ], + "stac_extensions": [ + "https://stac-extensions.github.io/item-assets/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json", + "https://stac-extensions.github.io/scientific/v1.0.0/schema.json", + "https://stac-extensions.github.io/raster/v1.1.0/schema.json", + "https://stac-extensions.github.io/eo/v1.0.0/schema.json" + ], + "item_assets": { + "red": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red - 10m", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 600000, + 0, + -10, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "roles": [ + "data", + "reflectance" + ] + }, + "green": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Green - 10m", + "eo:bands": [ + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 600000, + 0, + -10, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "roles": [ + "data", + "reflectance" + ] + }, + "blue": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Blue - 10m", + "eo:bands": [ + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 600000, + 0, + -10, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "roles": [ + "data", + "reflectance" + ] + }, + "visual": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color image", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 600000, + 0, + -10, + 4000000 + ], + "roles": [ + "visual" + ] + }, + "nir": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 1 - 10m", + "eo:bands": [ + { + "name": "B08", + "common_name": "nir", + "center_wavelength": 0.842, + "full_width_half_max": 0.145 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 600000, + 0, + -10, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "roles": [ + "data", + "reflectance" + ] + }, + "swir22": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 2.2μm - 20m", + "eo:bands": [ + { + "name": "B12", + "common_name": "swir22", + "center_wavelength": 2.19, + "full_width_half_max": 0.242 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 600000, + 0, + -20, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "roles": [ + "data", + "reflectance" + ] + }, + "rededge2": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 2 - 20m", + "eo:bands": [ + { + "name": "B06", + "common_name": "rededge", + "center_wavelength": 0.74, + "full_width_half_max": 0.018 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 600000, + 0, + -20, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "roles": [ + "data", + "reflectance" + ] + }, + "rededge3": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 3 - 20m", + "eo:bands": [ + { + "name": "B07", + "common_name": "rededge", + "center_wavelength": 0.783, + "full_width_half_max": 0.028 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 600000, + 0, + -20, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "roles": [ + "data", + "reflectance" + ] + }, + "rededge1": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 1 - 20m", + "eo:bands": [ + { + "name": "B05", + "common_name": "rededge", + "center_wavelength": 0.704, + "full_width_half_max": 0.019 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 600000, + 0, + -20, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "roles": [ + "data", + "reflectance" + ] + }, + "swir16": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 1.6μm - 20m", + "eo:bands": [ + { + "name": "B11", + "common_name": "swir16", + "center_wavelength": 1.61, + "full_width_half_max": 0.143 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 600000, + 0, + -20, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "roles": [ + "data", + "reflectance" + ] + }, + "wvp": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Water Vapour (WVP)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 600000, + 0, + -20, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "unit": "cm", + "scale": 0.001, + "offset": 0 + } + ], + "roles": [ + "data" + ] + }, + "nir08": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 2 - 20m", + "eo:bands": [ + { + "name": "B8A", + "common_name": "nir08", + "center_wavelength": 0.865, + "full_width_half_max": 0.033 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 600000, + 0, + -20, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "roles": [ + "data", + "reflectance" + ] + }, + "scl": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Scene classification map (SCL)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 600000, + 0, + -20, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "roles": [ + "data" + ] + }, + "aot": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Aerosol optical thickness (AOT)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 600000, + 0, + -20, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.001, + "offset": 0 + } + ], + "roles": [ + "data" + ] + }, + "coastal": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Coastal - 60m", + "eo:bands": [ + { + "name": "B01", + "common_name": "coastal", + "center_wavelength": 0.443, + "full_width_half_max": 0.027 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 600000, + 0, + -60, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "roles": [ + "data", + "reflectance" + ] + }, + "nir09": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 3 - 60m", + "eo:bands": [ + { + "name": "B09", + "common_name": "nir09", + "center_wavelength": 0.945, + "full_width_half_max": 0.026 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 600000, + 0, + -60, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "roles": [ + "data", + "reflectance" + ] + }, + "cloud": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Cloud Probabilities", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 600000, + 0, + -20, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "roles": [ + "data", + "cloud" + ] + }, + "snow": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Snow Probabilities", + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 600000, + 0, + -20, + 4000000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "roles": [ + "data", + "snow-ice" + ] + }, + "preview": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color preview", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "roles": [ + "overview" + ] + }, + "granule_metadata": { + "type": "application/xml", + "roles": [ + "metadata" + ] + }, + "tileinfo_metadata": { + "type": "application/json", + "roles": [ + "metadata" + ] + }, + "product_metadata": { + "type": "application/xml", + "roles": [ + "metadata" + ] + }, + "thumbnail": { + "type": "image/jpeg", + "title": "Thumbnail of preview image", + "roles": [ + "thumbnail" + ] + } + }, + "extent": { + "spatial": { + "bbox": [ + [ + -180, + -90, + 180, + 90 + ] + ] + }, + "temporal": { + "interval": [ + [ + "2015-06-27T10:25:31.456000Z", + null + ] + ] + } + }, + "license": "proprietary", + "keywords": [ + "sentinel", + "earth observation", + "esa" + ], + "providers": [ + { + "name": "ESA", + "roles": [ + "producer" + ], + "url": "https://earth.esa.int/web/guest/home" + }, + { + "name": "Sinergise", + "roles": [ + "processor" + ], + "url": "https://registry.opendata.aws/sentinel-2/" + }, + { + "name": "AWS", + "roles": [ + "host" + ], + "url": "http://sentinel-pds.s3-website.eu-central-1.amazonaws.com/" + }, + { + "name": "Element 84", + "roles": [ + "processor" + ], + "url": "https://element84.com" + } + ], + "summaries": { + "platform": [ + "sentinel-2a", + "sentinel-2b" + ], + "constellation": [ + "sentinel-2" + ], + "instruments": [ + "msi" + ], + "gsd": [ + 10, + 20, + 60 + ], + "view:off_nadir": [ + 0 + ], + "sci:doi": [ + "10.5270/s2_-znk9xsj" + ], + "eo:bands": [ + { + "name": "coastal", + "common_name": "coastal", + "description": "Coastal aerosol (band 1)", + "center_wavelength": 0.443, + "full_width_half_max": 0.027 + }, + { + "name": "blue", + "common_name": "blue", + "description": "Blue (band 2)", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + }, + { + "name": "green", + "common_name": "green", + "description": "Green (band 3)", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "red", + "common_name": "red", + "description": "Red (band 4)", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "rededge1", + "common_name": "rededge", + "description": "Red edge 1 (band 5)", + "center_wavelength": 0.704, + "full_width_half_max": 0.019 + }, + { + "name": "rededge2", + "common_name": "rededge", + "description": "Red edge 2 (band 6)", + "center_wavelength": 0.74, + "full_width_half_max": 0.018 + }, + { + "name": "rededge3", + "common_name": "rededge", + "description": "Red edge 3 (band 7)", + "center_wavelength": 0.783, + "full_width_half_max": 0.028 + }, + { + "name": "nir", + "common_name": "nir", + "description": "NIR 1 (band 8)", + "center_wavelength": 0.842, + "full_width_half_max": 0.145 + }, + { + "name": "nir08", + "common_name": "nir08", + "description": "NIR 2 (band 8A)", + "center_wavelength": 0.865, + "full_width_half_max": 0.033 + }, + { + "name": "nir09", + "common_name": "nir09", + "description": "NIR 3 (band 9)", + "center_wavelength": 0.945, + "full_width_half_max": 0.026 + }, + { + "name": "cirrus", + "common_name": "cirrus", + "description": "Cirrus (band 10)", + "center_wavelength": 1.3735, + "full_width_half_max": 0.075 + }, + { + "name": "swir16", + "common_name": "swir16", + "description": "SWIR 1 (band 11)", + "center_wavelength": 1.61, + "full_width_half_max": 0.143 + }, + { + "name": "swir22", + "common_name": "swir22", + "description": "SWIR 2 (band 12)", + "center_wavelength": 2.19, + "full_width_half_max": 0.242 + } + ] + } +} diff --git a/stac-server/data/sentinel-2/item-collection.json b/stac-server/data/sentinel-2/item-collection.json new file mode 100644 index 00000000..d3f4f39a --- /dev/null +++ b/stac-server/data/sentinel-2/item-collection.json @@ -0,0 +1,9085 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "stac_version": "1.0.0", + "id": "S2A_T13TDE_20240422T174753_L2A", + "properties": { + "created": "2024-04-23T03:23:58.819Z", + "platform": "sentinel-2a", + "constellation": "sentinel-2", + "instruments": [ + "msi" + ], + "eo:cloud_cover": 81.344962, + "proj:epsg": 32613, + "proj:centroid": { + "lat": 40.08454, + "lon": -105.06593 + }, + "mgrs:utm_zone": 13, + "mgrs:latitude_band": "T", + "mgrs:grid_square": "DE", + "grid:code": "MGRS-13TDE", + "view:azimuth": 106.16013343214507, + "view:incidence_angle": 10.590625427503369, + "view:sun_azimuth": 147.022486789901, + "view:sun_elevation": 58.6500999367225, + "s2:tile_id": "S2A_OPER_MSI_L2A_TL_2APS_20240423T004950_A046141_T13TDE_N05.10", + "s2:degraded_msi_data_percentage": 0.1066, + "s2:nodata_pixel_percentage": 73.465753, + "s2:saturated_defective_pixel_percentage": 0, + "s2:dark_features_percentage": 0.01648, + "s2:cloud_shadow_percentage": 5.086122, + "s2:vegetation_percentage": 1.514433, + "s2:not_vegetated_percentage": 10.500763, + "s2:water_percentage": 0.333431, + "s2:unclassified_percentage": 1.203809, + "s2:medium_proba_clouds_percentage": 12.000591, + "s2:high_proba_clouds_percentage": 68.495774, + "s2:thin_cirrus_percentage": 0.848596, + "s2:snow_ice_percentage": 0, + "s2:product_type": "S2MSI2A", + "s2:processing_baseline": "05.10", + "s2:product_uri": "S2A_MSIL2A_20240422T173911_N0510_R098_T13TDE_20240423T004950.SAFE", + "s2:generation_time": "2024-04-23T00:49:50.000000Z", + "s2:datatake_id": "GS2A_20240422T173911_046141_N05.10", + "s2:datatake_type": "INS-NOBS", + "s2:datastrip_id": "S2A_OPER_MSI_L2A_DS_2APS_20240423T004950_S20240422T174753_N05.10", + "s2:reflectance_conversion_factor": 0.991736406172245, + "datetime": "2024-04-22T17:53:02.036000Z", + "earthsearch:payload_id": "roda-sentinel-2-c1-l2a/workflow-sentinel-2-c1-l2a-to-stac/6b9d723d411b1e167dcf89b4c48cb881", + "storage:platform": "AWS", + "storage:region": "us-west-2", + "storage:requester_pays": false, + "processing:software": { + "sentinel-2-c1-l2a-to-stac": "v2024.02.01" + }, + "updated": "2024-04-23T03:23:58.819Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -105.07684234637634, + 40.65082193999616 + ], + [ + -105.37299987881823, + 39.66101702745275 + ], + [ + -104.88623172845638, + 39.661560248682505 + ], + [ + -104.88456877606482, + 40.65078981397619 + ], + [ + -105.07684234637634, + 40.65082193999616 + ] + ] + ] + }, + "links": [ + { + "rel": "self", + "type": "application/geo+json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2A_T13TDE_20240422T174753_L2A" + }, + { + "rel": "canonical", + "href": "s3://e84-earth-search-sentinel-data/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/S2A_T13TDE_20240422T174753_L2A.json", + "type": "application/json" + }, + { + "rel": "via", + "href": "s3://sentinel-s2-l2a/tiles/13/T/DE/2024/4/22/0/metadata.xml", + "type": "application/xml", + "title": "Granule Metadata in Sinergize RODA Archive" + }, + { + "rel": "parent", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "collection", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "root", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1" + }, + { + "rel": "thumbnail", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2A_T13TDE_20240422T174753_L2A/thumbnail" + } + ], + "assets": { + "red": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/B04.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red - 10m", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12200e483d24491874006d1e3d34a1f0b98acd6b11e409b0c8855268ef4206b5d13f", + "file:size": 50135369, + "roles": [ + "data", + "reflectance" + ] + }, + "green": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/B03.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Green - 10m", + "eo:bands": [ + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12207e69b57e15c1e7f9e45a2eb10de1cb2e0cd81876233105f40c4e889399bb0927", + "file:size": 49970992, + "roles": [ + "data", + "reflectance" + ] + }, + "blue": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/B02.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Blue - 10m", + "eo:bands": [ + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220e56ab03d18bcea34810acf54f386b28e81fee0612ac430f45b8d9587aee4bf56", + "file:size": 50877103, + "roles": [ + "data", + "reflectance" + ] + }, + "visual": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/TCI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color image", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 10 + }, + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 10 + }, + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 10 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "file:checksum": "122069aca68dca88fd4c2f57e9c6b98f1429182613dcf42a96ecaec4a0d32e5426ea", + "file:size": 30379347, + "roles": [ + "visual" + ] + }, + "nir": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/B08.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 1 - 10m", + "eo:bands": [ + { + "name": "B08", + "common_name": "nir", + "center_wavelength": 0.842, + "full_width_half_max": 0.145 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12201ac1b37d469e40df5d8790de0b4710717a76d12616cb54c7d43bfac23cf51412", + "file:size": 49643930, + "roles": [ + "data", + "reflectance" + ] + }, + "swir22": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/B12.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 2.2μm - 20m", + "eo:bands": [ + { + "name": "B12", + "common_name": "swir22", + "center_wavelength": 2.19, + "full_width_half_max": 0.242 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220f9b10bbe9d22e91159324a2cf765da31efb0bfca5440af692b006a03d7f8cc1f", + "file:size": 14110370, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge2": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/B06.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 2 - 20m", + "eo:bands": [ + { + "name": "B06", + "common_name": "rededge", + "center_wavelength": 0.74, + "full_width_half_max": 0.018 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220c257f9126f2d5962b5205f71277d0c9e250b3ddd14e5f29ed717e8bfdd5f2710", + "file:size": 15030153, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge3": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/B07.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 3 - 20m", + "eo:bands": [ + { + "name": "B07", + "common_name": "rededge", + "center_wavelength": 0.783, + "full_width_half_max": 0.028 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220101b42ec7b536a9822b3cedc0fc45f99399da54d8191213018cdeea8fdfe9715", + "file:size": 15057544, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge1": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/B05.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 1 - 20m", + "eo:bands": [ + { + "name": "B05", + "common_name": "rededge", + "center_wavelength": 0.704, + "full_width_half_max": 0.019 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220a1eb4b33fc70e5329bfed2a5920d453da03c5a4fea75033cbe2a9f737df5269d", + "file:size": 14955811, + "roles": [ + "data", + "reflectance" + ] + }, + "swir16": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/B11.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 1.6μm - 20m", + "eo:bands": [ + { + "name": "B11", + "common_name": "swir16", + "center_wavelength": 1.61, + "full_width_half_max": 0.143 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12207a0b774236d8376b7e957957582a69ee0832a683480f44e21dd18e9ec90620bf", + "file:size": 14198146, + "roles": [ + "data", + "reflectance" + ] + }, + "wvp": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/WVP.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Water Vapour (WVP)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "unit": "cm", + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "1220d28f7ed409085c49ba1c2f918ac71c6e65b9c8465c56fde3570a926893d497a2", + "file:size": 1982443, + "roles": [ + "data" + ] + }, + "nir08": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/B8A.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 2 - 20m", + "eo:bands": [ + { + "name": "B8A", + "common_name": "nir08", + "center_wavelength": 0.865, + "full_width_half_max": 0.033 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12207f44c3c11a4b9d18f03cf94bedf0028884347c3ba14899c30198514704d98621", + "file:size": 15175157, + "roles": [ + "data", + "reflectance" + ] + }, + "scl": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/SCL.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Scene classification map (SCL)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "12200e95144752a86b56d38274d4d54de152c45ff9b37b2124ab15be8e3daadd8238", + "file:size": 565221, + "roles": [ + "data" + ] + }, + "aot": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/AOT.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Aerosol optical thickness (AOT)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "1220876940066bb6fb07602c097357970cc93a1905f4da42dfe7e193fc74b0444d90", + "file:size": 458211, + "roles": [ + "data" + ] + }, + "coastal": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/B01.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Coastal - 60m", + "eo:bands": [ + { + "name": "B01", + "common_name": "coastal", + "center_wavelength": 0.443, + "full_width_half_max": 0.027 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12208888b299d7443511de187f3abb5a2166f2bd63761905a0750e7143d6f82a96c3", + "file:size": 1817791, + "roles": [ + "data", + "reflectance" + ] + }, + "nir09": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/B09.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 3 - 60m", + "eo:bands": [ + { + "name": "B09", + "common_name": "nir09", + "center_wavelength": 0.945, + "full_width_half_max": 0.026 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122011e8c311c51a73ee521e2c9e0416c74ef169b1c1241fcad3a382de6cfb5a6180", + "file:size": 1814339, + "roles": [ + "data", + "reflectance" + ] + }, + "cloud": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/CLD_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Cloud Probabilities", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "122005e05a606d632f74e2404b9637b451af6c1e20d9bba27ae21c1804cceb8f1108", + "file:size": 1834314, + "roles": [ + "data", + "cloud" + ] + }, + "snow": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/SNW_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Snow Probabilities", + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "1220e0d5ba85fd01fe2f07839223d994ebb49f247df263bf4fc47d167e625492394f", + "file:size": 59426, + "roles": [ + "data", + "snow-ice" + ] + }, + "preview": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/L2A_PVI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color preview", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "file:checksum": "12207d8484466bff37d95c4e854d21ef1dafc2615973e9dd3309a8267951d4072a66", + "file:size": 41110, + "roles": [ + "overview" + ] + }, + "granule_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/metadata.xml", + "type": "application/xml", + "file:checksum": "1220ad712c5d3e41c9577b9bc20d8c5a84fd769ea91880fc4ba15bf5ec40cc5c9c36", + "file:size": 193775, + "roles": [ + "metadata" + ] + }, + "tileinfo_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/tileInfo.json", + "type": "application/json", + "file:checksum": "1220e332fe300389881e82a6685489f704bec519c5d5354fb3d959f75ce413bae9a8", + "file:size": 1516, + "roles": [ + "metadata" + ] + }, + "product_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/product_metadata.xml", + "type": "application/xml", + "file:checksum": "122003f04b7d1e696131e1fdb5768a271223649f52323999145387cb89e4018a6ab0", + "file:size": 55126, + "roles": [ + "metadata" + ] + }, + "thumbnail": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240422T174753_L2A/L2A_PVI.jpg", + "type": "image/jpeg", + "title": "Thumbnail of preview image", + "file:checksum": "1220511b9c906bbbbbf116a3970154c8673ebe07964f9518cda014a3d40d96bb3d4f", + "file:size": 10518, + "roles": [ + "thumbnail" + ] + } + }, + "bbox": [ + -105.373, + 39.661017, + -104.884569, + 40.650822 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.1.0/schema.json", + "https://stac-extensions.github.io/file/v2.1.0/schema.json", + "https://stac-extensions.github.io/grid/v1.1.0/schema.json", + "https://stac-extensions.github.io/mgrs/v1.0.0/schema.json", + "https://stac-extensions.github.io/processing/v1.1.0/schema.json", + "https://stac-extensions.github.io/projection/v1.1.0/schema.json", + "https://stac-extensions.github.io/raster/v1.1.0/schema.json", + "https://stac-extensions.github.io/sentinel-2/v1.0.0/schema.json", + "https://stac-extensions.github.io/storage/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "collection": "sentinel-2-c1-l2a" + }, + { + "type": "Feature", + "stac_version": "1.0.0", + "id": "S2B_T13TDE_20240420T175329_L2A", + "properties": { + "created": "2024-04-21T03:10:22.921Z", + "platform": "sentinel-2b", + "constellation": "sentinel-2", + "instruments": [ + "msi" + ], + "eo:cloud_cover": 95.406204, + "proj:epsg": 32613, + "proj:centroid": { + "lat": 40.15442, + "lon": -105.53002 + }, + "mgrs:utm_zone": 13, + "mgrs:latitude_band": "T", + "mgrs:grid_square": "DE", + "grid:code": "MGRS-13TDE", + "view:azimuth": 235.01021855606453, + "view:incidence_angle": 3.669035762099652, + "view:sun_azimuth": 151.665123064488, + "view:sun_elevation": 58.9649053792403, + "s2:tile_id": "S2B_OPER_MSI_L2A_TL_2BPS_20240420T214349_A037204_T13TDE_N05.10", + "s2:degraded_msi_data_percentage": 0.0757, + "s2:nodata_pixel_percentage": 0, + "s2:saturated_defective_pixel_percentage": 0, + "s2:dark_features_percentage": 0.000435, + "s2:cloud_shadow_percentage": 4.09422, + "s2:vegetation_percentage": 0, + "s2:not_vegetated_percentage": 0.069791, + "s2:water_percentage": 0.048175, + "s2:unclassified_percentage": 0.003401, + "s2:medium_proba_clouds_percentage": 28.55317, + "s2:high_proba_clouds_percentage": 66.853034, + "s2:thin_cirrus_percentage": 0, + "s2:snow_ice_percentage": 0.377772, + "s2:product_type": "S2MSI2A", + "s2:processing_baseline": "05.10", + "s2:product_uri": "S2B_MSIL2A_20240420T174909_N0510_R141_T13TDE_20240420T214349.SAFE", + "s2:generation_time": "2024-04-20T21:43:49.000000Z", + "s2:datatake_id": "GS2B_20240420T174909_037204_N05.10", + "s2:datatake_type": "INS-NOBS", + "s2:datastrip_id": "S2B_OPER_MSI_L2A_DS_2BPS_20240420T214349_S20240420T175329_N05.10", + "s2:reflectance_conversion_factor": 0.992839248825627, + "datetime": "2024-04-20T18:02:56.089000Z", + "earthsearch:payload_id": "roda-sentinel-2-c1-l2a/workflow-sentinel-2-c1-l2a-to-stac/e3a33320ad1dc4fa73adb275a308d932", + "storage:platform": "AWS", + "storage:region": "us-west-2", + "storage:requester_pays": false, + "processing:software": { + "sentinel-2-c1-l2a-to-stac": "v2024.02.01" + }, + "updated": "2024-04-21T03:10:22.921Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -106.18316062292897, + 40.64478591807637 + ], + [ + -106.1661201925584, + 39.65576169772817 + ], + [ + -104.88623172845638, + 39.661560248682505 + ], + [ + -104.88456877606482, + 40.65078981397619 + ], + [ + -106.18316062292897, + 40.64478591807637 + ] + ] + ] + }, + "links": [ + { + "rel": "self", + "type": "application/geo+json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2B_T13TDE_20240420T175329_L2A" + }, + { + "rel": "canonical", + "href": "s3://e84-earth-search-sentinel-data/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/S2B_T13TDE_20240420T175329_L2A.json", + "type": "application/json" + }, + { + "rel": "via", + "href": "s3://sentinel-s2-l2a/tiles/13/T/DE/2024/4/20/0/metadata.xml", + "type": "application/xml", + "title": "Granule Metadata in Sinergize RODA Archive" + }, + { + "rel": "parent", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "collection", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "root", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1" + }, + { + "rel": "thumbnail", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2B_T13TDE_20240420T175329_L2A/thumbnail" + } + ], + "assets": { + "red": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/B04.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red - 10m", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220a0fe84477391ed5bf73fc20847fae3ce51e8319745c3c110896da8d34882e4bb", + "file:size": 158149487, + "roles": [ + "data", + "reflectance" + ] + }, + "green": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/B03.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Green - 10m", + "eo:bands": [ + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220a365a3165154c3bdcfdaaf4ba2376291924b440e17bc82f2d0f57f80d0cd0ea7", + "file:size": 157489161, + "roles": [ + "data", + "reflectance" + ] + }, + "blue": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/B02.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Blue - 10m", + "eo:bands": [ + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220133f7d66cfb20404d26b252f8efa39fd0876bb6199325f37ede9976030d601d8", + "file:size": 158054713, + "roles": [ + "data", + "reflectance" + ] + }, + "visual": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/TCI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color image", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 10 + }, + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 10 + }, + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 10 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "file:checksum": "1220c03494612ac37145dee45716532c5db4f315ce2b21fe9358c823a07829e8ee9a", + "file:size": 8917902, + "roles": [ + "visual" + ] + }, + "nir": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/B08.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 1 - 10m", + "eo:bands": [ + { + "name": "B08", + "common_name": "nir", + "center_wavelength": 0.842, + "full_width_half_max": 0.145 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220d610e8ff9b097e98df97de60e9d84b434f13ddd05bb16f872b51f65e429b551d", + "file:size": 159254479, + "roles": [ + "data", + "reflectance" + ] + }, + "swir22": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/B12.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 2.2μm - 20m", + "eo:bands": [ + { + "name": "B12", + "common_name": "swir22", + "center_wavelength": 2.19, + "full_width_half_max": 0.242 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220281a41e1a169e1f4aceefe31a0a060a0362799dc9c97cc4243655e8edd0f9524", + "file:size": 54303704, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge2": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/B06.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 2 - 20m", + "eo:bands": [ + { + "name": "B06", + "common_name": "rededge", + "center_wavelength": 0.74, + "full_width_half_max": 0.018 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220813b5cd768820f002bae2a9e040a22e988a78d0c254e159a722121d9a9616fbc", + "file:size": 55675397, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge3": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/B07.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 3 - 20m", + "eo:bands": [ + { + "name": "B07", + "common_name": "rededge", + "center_wavelength": 0.783, + "full_width_half_max": 0.028 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220fece6448712c71464f9d50af6005110d818107605f8ab05c261a47b88cc662d6", + "file:size": 55536891, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge1": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/B05.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 1 - 20m", + "eo:bands": [ + { + "name": "B05", + "common_name": "rededge", + "center_wavelength": 0.704, + "full_width_half_max": 0.019 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12207f197c6b4aa6d08b691854ee7d5dbde3a06fba8993fb849033259607f3742b20", + "file:size": 55732209, + "roles": [ + "data", + "reflectance" + ] + }, + "swir16": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/B11.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 1.6μm - 20m", + "eo:bands": [ + { + "name": "B11", + "common_name": "swir16", + "center_wavelength": 1.61, + "full_width_half_max": 0.143 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220f58f44a2438ae01b98aed5077d9efdd25b29f9ac844787d50d19eb0f9bdc5c57", + "file:size": 54094832, + "roles": [ + "data", + "reflectance" + ] + }, + "wvp": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/WVP.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Water Vapour (WVP)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "unit": "cm", + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "122023d7573177d102694c108f0a3cb55d2646fde9a4fef93bfc92ba0884672f0022", + "file:size": 498697, + "roles": [ + "data" + ] + }, + "nir08": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/B8A.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 2 - 20m", + "eo:bands": [ + { + "name": "B8A", + "common_name": "nir08", + "center_wavelength": 0.865, + "full_width_half_max": 0.033 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122060b19c1c3fe77736bc9fa7aa2945d0a29abf898eff1bda6d7e50536247e369a1", + "file:size": 56036422, + "roles": [ + "data", + "reflectance" + ] + }, + "scl": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/SCL.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Scene classification map (SCL)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "1220cc3160fe52534364f3cc07c434064c7fd35a1a114e25f2ca241bb0659aa0affe", + "file:size": 861469, + "roles": [ + "data" + ] + }, + "aot": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/AOT.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Aerosol optical thickness (AOT)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "1220655ffc86f0b0b74a2a6444fa364f81d9fa79e9c140eaf3f9f61310b41d4301f2", + "file:size": 3067489, + "roles": [ + "data" + ] + }, + "coastal": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/B01.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Coastal - 60m", + "eo:bands": [ + { + "name": "B01", + "common_name": "coastal", + "center_wavelength": 0.443, + "full_width_half_max": 0.027 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220869aa2690fb06c591735b48364e2122c4fc59148af56ded8689d65eab7335aac", + "file:size": 6491662, + "roles": [ + "data", + "reflectance" + ] + }, + "nir09": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/B09.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 3 - 60m", + "eo:bands": [ + { + "name": "B09", + "common_name": "nir09", + "center_wavelength": 0.945, + "full_width_half_max": 0.026 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12205025bc792ab6cbd77e71d2724cb2cf50bd6eaa525b770bc6597691cb952c9d28", + "file:size": 6527152, + "roles": [ + "data", + "reflectance" + ] + }, + "cloud": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/CLD_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Cloud Probabilities", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "1220b2431925d79fd00538e33aa98b417513391f59c0cb18a92388b217b7dbb810a9", + "file:size": 1340534, + "roles": [ + "data", + "cloud" + ] + }, + "snow": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/SNW_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Snow Probabilities", + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "122093af4aae941b47243795e59b5be43daa6facd17a8e5e8ecfb578ec52972cc048", + "file:size": 1661279, + "roles": [ + "data", + "snow-ice" + ] + }, + "preview": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/L2A_PVI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color preview", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "file:checksum": "12206395e6cf647e6cf48a67af38414e8341672c5c728ad5c41bbf52a168c21d1dcb", + "file:size": 16090, + "roles": [ + "overview" + ] + }, + "granule_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/metadata.xml", + "type": "application/xml", + "file:checksum": "1220b9ac8cfec4f198849ffd85cd4a50d84b47eb941863aa551ea408e485e34e672c", + "file:size": 626449, + "roles": [ + "metadata" + ] + }, + "tileinfo_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/tileInfo.json", + "type": "application/json", + "file:checksum": "1220e3d7d79007f5ff0422c1a25a55db2ef618ab90bfb48699263795a5ec187619e9", + "file:size": 1491, + "roles": [ + "metadata" + ] + }, + "product_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/product_metadata.xml", + "type": "application/xml", + "file:checksum": "1220e2db3f07ac8f88ffa601cf766e538a9bea99f3445545ae67ecab7abd2092f54a", + "file:size": 54338, + "roles": [ + "metadata" + ] + }, + "thumbnail": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240420T175329_L2A/L2A_PVI.jpg", + "type": "image/jpeg", + "title": "Thumbnail of preview image", + "file:checksum": "1220063c337f82e66ccfad61f0cd2bed087674b95b2bd09c47776e1f811f032073c0", + "file:size": 5329, + "roles": [ + "thumbnail" + ] + } + }, + "bbox": [ + -106.183161, + 39.655762, + -104.884569, + 40.65079 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.1.0/schema.json", + "https://stac-extensions.github.io/file/v2.1.0/schema.json", + "https://stac-extensions.github.io/grid/v1.1.0/schema.json", + "https://stac-extensions.github.io/mgrs/v1.0.0/schema.json", + "https://stac-extensions.github.io/processing/v1.1.0/schema.json", + "https://stac-extensions.github.io/projection/v1.1.0/schema.json", + "https://stac-extensions.github.io/raster/v1.1.0/schema.json", + "https://stac-extensions.github.io/sentinel-2/v1.0.0/schema.json", + "https://stac-extensions.github.io/storage/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "collection": "sentinel-2-c1-l2a" + }, + { + "type": "Feature", + "stac_version": "1.0.0", + "id": "S2B_T13TDE_20240417T174407_L2A", + "properties": { + "created": "2024-04-18T00:50:02.006Z", + "platform": "sentinel-2b", + "constellation": "sentinel-2", + "instruments": [ + "msi" + ], + "eo:cloud_cover": 79.612255, + "proj:epsg": 32613, + "proj:centroid": { + "lat": 40.0834, + "lon": -105.06412 + }, + "mgrs:utm_zone": 13, + "mgrs:latitude_band": "T", + "mgrs:grid_square": "DE", + "grid:code": "MGRS-13TDE", + "view:azimuth": 106.79857961359232, + "view:incidence_angle": 10.588876686411432, + "view:sun_azimuth": 147.92162972317, + "view:sun_elevation": 56.9932760967701, + "s2:tile_id": "S2B_OPER_MSI_L2A_TL_2BPS_20240417T220957_A037161_T13TDE_N05.10", + "s2:degraded_msi_data_percentage": 0.0971, + "s2:nodata_pixel_percentage": 73.774505, + "s2:saturated_defective_pixel_percentage": 0, + "s2:dark_features_percentage": 0.007983, + "s2:cloud_shadow_percentage": 7.869551, + "s2:vegetation_percentage": 1.205065, + "s2:not_vegetated_percentage": 10.025657, + "s2:water_percentage": 0.314357, + "s2:unclassified_percentage": 0.965135, + "s2:medium_proba_clouds_percentage": 13.568662, + "s2:high_proba_clouds_percentage": 65.947366, + "s2:thin_cirrus_percentage": 0.096225, + "s2:snow_ice_percentage": 0, + "s2:product_type": "S2MSI2A", + "s2:processing_baseline": "05.10", + "s2:product_uri": "S2B_MSIL2A_20240417T173909_N0510_R098_T13TDE_20240417T220957.SAFE", + "s2:generation_time": "2024-04-17T22:09:57.000000Z", + "s2:datatake_id": "GS2B_20240417T173909_037161_N05.10", + "s2:datatake_type": "INS-NOBS", + "s2:datastrip_id": "S2B_OPER_MSI_L2A_DS_2BPS_20240417T220957_S20240417T174407_N05.10", + "s2:reflectance_conversion_factor": 0.994522042652322, + "datetime": "2024-04-17T17:53:00.118000Z", + "earthsearch:payload_id": "roda-sentinel-2-c1-l2a/workflow-sentinel-2-c1-l2a-to-stac/166c117613d911418f21d103a0c80119", + "storage:platform": "AWS", + "storage:region": "us-west-2", + "storage:requester_pays": false, + "processing:software": { + "sentinel-2-c1-l2a-to-stac": "v2024.02.01" + }, + "updated": "2024-04-18T00:50:02.006Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -105.07222914448856, + 40.650824917635575 + ], + [ + -105.36950241694164, + 39.661028206876416 + ], + [ + -104.88623172845638, + 39.661560248682505 + ], + [ + -104.88456877606482, + 40.65078981397619 + ], + [ + -105.07222914448856, + 40.650824917635575 + ] + ] + ] + }, + "links": [ + { + "rel": "self", + "type": "application/geo+json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2B_T13TDE_20240417T174407_L2A" + }, + { + "rel": "canonical", + "href": "s3://e84-earth-search-sentinel-data/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/S2B_T13TDE_20240417T174407_L2A.json", + "type": "application/json" + }, + { + "rel": "via", + "href": "s3://sentinel-s2-l2a/tiles/13/T/DE/2024/4/17/0/metadata.xml", + "type": "application/xml", + "title": "Granule Metadata in Sinergize RODA Archive" + }, + { + "rel": "parent", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "collection", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "root", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1" + }, + { + "rel": "thumbnail", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2B_T13TDE_20240417T174407_L2A/thumbnail" + } + ], + "assets": { + "red": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/B04.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red - 10m", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12200195dc868be81c6e9438009c581f4b27a8f88c08dc5656d0705e3be1da4796f0", + "file:size": 54692248, + "roles": [ + "data", + "reflectance" + ] + }, + "green": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/B03.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Green - 10m", + "eo:bands": [ + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122017672a32b390caa67dffbf4266b504e0a953727cea0b229d8a49907fa8969a1b", + "file:size": 54736035, + "roles": [ + "data", + "reflectance" + ] + }, + "blue": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/B02.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Blue - 10m", + "eo:bands": [ + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220740424662131dc61dd654264b40044d0e78cd96df2e83c8d6122e0673e7d1f75", + "file:size": 55230871, + "roles": [ + "data", + "reflectance" + ] + }, + "visual": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/TCI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color image", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 10 + }, + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 10 + }, + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 10 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "file:checksum": "1220cd194cbf4c7c7acceb8fe1dcceec2bebb4fe9bf3d063b394830cebabd99f5dca", + "file:size": 34734762, + "roles": [ + "visual" + ] + }, + "nir": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/B08.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 1 - 10m", + "eo:bands": [ + { + "name": "B08", + "common_name": "nir", + "center_wavelength": 0.842, + "full_width_half_max": 0.145 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122027ff22c7b293cc31662cb942d0655a50ea978a9585a92426f4335fd9c07f52a1", + "file:size": 53855273, + "roles": [ + "data", + "reflectance" + ] + }, + "swir22": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/B12.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 2.2μm - 20m", + "eo:bands": [ + { + "name": "B12", + "common_name": "swir22", + "center_wavelength": 2.19, + "full_width_half_max": 0.242 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220acf5417c7fa907602cb5a40b4b35fb5257f57f8c88e0987458705f700bc3f8f8", + "file:size": 15991146, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge2": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/B06.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 2 - 20m", + "eo:bands": [ + { + "name": "B06", + "common_name": "rededge", + "center_wavelength": 0.74, + "full_width_half_max": 0.018 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122082b0db381d2c1ac35073ff71a236f41538b3330310e6ce51035a2071b280b057", + "file:size": 16259861, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge3": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/B07.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 3 - 20m", + "eo:bands": [ + { + "name": "B07", + "common_name": "rededge", + "center_wavelength": 0.783, + "full_width_half_max": 0.028 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220855b7283bd4e8d01803b16302e590542b33b47efa5838cada9ecd9fa2aeaabe4", + "file:size": 16244303, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge1": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/B05.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 1 - 20m", + "eo:bands": [ + { + "name": "B05", + "common_name": "rededge", + "center_wavelength": 0.704, + "full_width_half_max": 0.019 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12203380a533d459903353f80c525892abe4e5941722bdf6d716c6f287d8d6d5bc71", + "file:size": 16292265, + "roles": [ + "data", + "reflectance" + ] + }, + "swir16": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/B11.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 1.6μm - 20m", + "eo:bands": [ + { + "name": "B11", + "common_name": "swir16", + "center_wavelength": 1.61, + "full_width_half_max": 0.143 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220fd6e2501d977b19be921e701aae6a438f0f6c2aa7fca18089aa969f2435d5ffb", + "file:size": 15939073, + "roles": [ + "data", + "reflectance" + ] + }, + "wvp": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/WVP.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Water Vapour (WVP)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "unit": "cm", + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "122042708dac04cc462e57ac73d80c3a4e95e8f0dcdc094bcafbdd504f4450dd071e", + "file:size": 1931588, + "roles": [ + "data" + ] + }, + "nir08": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/B8A.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 2 - 20m", + "eo:bands": [ + { + "name": "B8A", + "common_name": "nir08", + "center_wavelength": 0.865, + "full_width_half_max": 0.033 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220d09d99ac8accf42f8908c7d60e2e08fb1e4374c46d9cd1829f3ca41de1039e6c", + "file:size": 16233003, + "roles": [ + "data", + "reflectance" + ] + }, + "scl": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/SCL.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Scene classification map (SCL)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "1220724944e024e4e7b1f2a15466f9f0d1a4b6e313f469bfe70a4a8c960f684a033d", + "file:size": 702625, + "roles": [ + "data" + ] + }, + "aot": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/AOT.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Aerosol optical thickness (AOT)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "1220f09418ad965a310c3dfbaf979888972f1f1f759e5e8ec321780a208b962c2fa1", + "file:size": 460584, + "roles": [ + "data" + ] + }, + "coastal": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/B01.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Coastal - 60m", + "eo:bands": [ + { + "name": "B01", + "common_name": "coastal", + "center_wavelength": 0.443, + "full_width_half_max": 0.027 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12202a5deafb6de8c5dcf37428a737cd3bb3e46f832ac81bf466b0d67efaf2a60771", + "file:size": 1930963, + "roles": [ + "data", + "reflectance" + ] + }, + "nir09": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/B09.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 3 - 60m", + "eo:bands": [ + { + "name": "B09", + "common_name": "nir09", + "center_wavelength": 0.945, + "full_width_half_max": 0.026 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122013b74ec469fb09eafd2eeca07577842da410a9128a59f7ce99b089a750eb0c33", + "file:size": 1785830, + "roles": [ + "data", + "reflectance" + ] + }, + "cloud": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/CLD_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Cloud Probabilities", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "122079ced8dc29c333fee3b10da4f6e837d9b09c993a971eb4a4ffdefed6f6791158", + "file:size": 2226147, + "roles": [ + "data", + "cloud" + ] + }, + "snow": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/SNW_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Snow Probabilities", + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "122025311046f270980fbfcc87a4cfa2cf2f267d5ea192b7edc0c05135e211250ead", + "file:size": 64130, + "roles": [ + "data", + "snow-ice" + ] + }, + "preview": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/L2A_PVI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color preview", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "file:checksum": "1220384720686449fe76ecb8ff8cd81ead5f50a979f9d4264de2084e6d4302e7be6b", + "file:size": 54954, + "roles": [ + "overview" + ] + }, + "granule_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/metadata.xml", + "type": "application/xml", + "file:checksum": "1220d5c04fd611d4b5bb2ff13d8395da1a9b0c7bd181e98a7116c7fe56f4b35b149f", + "file:size": 193635, + "roles": [ + "metadata" + ] + }, + "tileinfo_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/tileInfo.json", + "type": "application/json", + "file:checksum": "122068c0e71607ca2842410036d5e13ac4d173c6b08b70fbd0828b76e9ce79ec8e38", + "file:size": 1517, + "roles": [ + "metadata" + ] + }, + "product_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/product_metadata.xml", + "type": "application/xml", + "file:checksum": "12209fde7c8606c312b98d11755c0ccf16148d33182c9e0b2ec65fd5cd0df8f5d82a", + "file:size": 54579, + "roles": [ + "metadata" + ] + }, + "thumbnail": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240417T174407_L2A/L2A_PVI.jpg", + "type": "image/jpeg", + "title": "Thumbnail of preview image", + "file:checksum": "1220b1906424215b95e4404787436488a197a761ac4ac6eb1a2a29473f7c57efaadf", + "file:size": 13975, + "roles": [ + "thumbnail" + ] + } + }, + "bbox": [ + -105.369502, + 39.661028, + -104.884569, + 40.650825 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.1.0/schema.json", + "https://stac-extensions.github.io/file/v2.1.0/schema.json", + "https://stac-extensions.github.io/grid/v1.1.0/schema.json", + "https://stac-extensions.github.io/mgrs/v1.0.0/schema.json", + "https://stac-extensions.github.io/processing/v1.1.0/schema.json", + "https://stac-extensions.github.io/projection/v1.1.0/schema.json", + "https://stac-extensions.github.io/raster/v1.1.0/schema.json", + "https://stac-extensions.github.io/sentinel-2/v1.0.0/schema.json", + "https://stac-extensions.github.io/storage/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "collection": "sentinel-2-c1-l2a" + }, + { + "type": "Feature", + "stac_version": "1.0.0", + "id": "S2A_T13TDE_20240415T180048_L2A", + "properties": { + "created": "2024-04-16T03:53:07.700Z", + "platform": "sentinel-2a", + "constellation": "sentinel-2", + "instruments": [ + "msi" + ], + "eo:cloud_cover": 22.001417, + "proj:epsg": 32613, + "proj:centroid": { + "lat": 40.15442, + "lon": -105.53002 + }, + "mgrs:utm_zone": 13, + "mgrs:latitude_band": "T", + "mgrs:grid_square": "DE", + "grid:code": "MGRS-13TDE", + "view:azimuth": 235.96838232110483, + "view:incidence_angle": 3.666996342330071, + "view:sun_azimuth": 152.404011934022, + "view:sun_elevation": 57.2531341800585, + "s2:tile_id": "S2A_OPER_MSI_L2A_TL_2APS_20240416T005353_A046041_T13TDE_N05.10", + "s2:degraded_msi_data_percentage": 0.5104, + "s2:nodata_pixel_percentage": 3e-6, + "s2:saturated_defective_pixel_percentage": 0, + "s2:dark_features_percentage": 1.076075, + "s2:cloud_shadow_percentage": 0.394455, + "s2:vegetation_percentage": 8.887585, + "s2:not_vegetated_percentage": 40.498501, + "s2:water_percentage": 1.027701, + "s2:unclassified_percentage": 0.88799, + "s2:medium_proba_clouds_percentage": 9.967004, + "s2:high_proba_clouds_percentage": 12.0164, + "s2:thin_cirrus_percentage": 0.018013, + "s2:snow_ice_percentage": 25.226274, + "s2:product_type": "S2MSI2A", + "s2:processing_baseline": "05.10", + "s2:product_uri": "S2A_MSIL2A_20240415T174911_N0510_R141_T13TDE_20240416T005353.SAFE", + "s2:generation_time": "2024-04-16T00:53:53.000000Z", + "s2:datatake_id": "GS2A_20240415T174911_046041_N05.10", + "s2:datatake_type": "INS-NOBS", + "s2:datastrip_id": "S2A_OPER_MSI_L2A_DS_2APS_20240416T005353_S20240415T180048_N05.10", + "s2:reflectance_conversion_factor": 0.995648108361933, + "datetime": "2024-04-15T18:02:58.110000Z", + "earthsearch:payload_id": "roda-sentinel-2-c1-l2a/workflow-sentinel-2-c1-l2a-to-stac/b01683f237d6046b4eca1e94576eb2da", + "storage:platform": "AWS", + "storage:region": "us-west-2", + "storage:requester_pays": false, + "processing:software": { + "sentinel-2-c1-l2a-to-stac": "v2024.02.01" + }, + "updated": "2024-04-16T03:53:07.700Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -106.18316062292897, + 40.64478591807637 + ], + [ + -106.1661201925584, + 39.65576169772817 + ], + [ + -104.88623172845638, + 39.661560248682505 + ], + [ + -104.88456877606482, + 40.65078981397619 + ], + [ + -106.18316062292897, + 40.64478591807637 + ] + ] + ] + }, + "links": [ + { + "rel": "self", + "type": "application/geo+json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2A_T13TDE_20240415T180048_L2A" + }, + { + "rel": "canonical", + "href": "s3://e84-earth-search-sentinel-data/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/S2A_T13TDE_20240415T180048_L2A.json", + "type": "application/json" + }, + { + "rel": "via", + "href": "s3://sentinel-s2-l2a/tiles/13/T/DE/2024/4/15/0/metadata.xml", + "type": "application/xml", + "title": "Granule Metadata in Sinergize RODA Archive" + }, + { + "rel": "parent", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "collection", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "root", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1" + }, + { + "rel": "thumbnail", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2A_T13TDE_20240415T180048_L2A/thumbnail" + } + ], + "assets": { + "red": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/B04.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red - 10m", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12206e6b704ce7f67095049bd2526119348b04ddbc3163e6aaaf8bb6b5b84c2a9e54", + "file:size": 241850053, + "roles": [ + "data", + "reflectance" + ] + }, + "green": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/B03.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Green - 10m", + "eo:bands": [ + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220087875f0b81f668019807661ecc30801c56eaf0c4d5ab800d5ed592e77d26c32", + "file:size": 241079825, + "roles": [ + "data", + "reflectance" + ] + }, + "blue": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/B02.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Blue - 10m", + "eo:bands": [ + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12207626cb13bd8b923e40530bc421dbdfdc3d2a8da5e63c25e74ac5fa127d363c00", + "file:size": 241384778, + "roles": [ + "data", + "reflectance" + ] + }, + "visual": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/TCI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color image", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 10 + }, + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 10 + }, + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 10 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "file:checksum": "1220fe110ff77170c5c4e519f30c969bb50a8147e4f391feda9cc7ab805759e9ad35", + "file:size": 268745425, + "roles": [ + "visual" + ] + }, + "nir": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/B08.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 1 - 10m", + "eo:bands": [ + { + "name": "B08", + "common_name": "nir", + "center_wavelength": 0.842, + "full_width_half_max": 0.145 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12201e01d709d113be500fc8b92ca9e85b7e22d75043e60efbb813bed36d6a471ea7", + "file:size": 238443473, + "roles": [ + "data", + "reflectance" + ] + }, + "swir22": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/B12.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 2.2μm - 20m", + "eo:bands": [ + { + "name": "B12", + "common_name": "swir22", + "center_wavelength": 2.19, + "full_width_half_max": 0.242 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220ce00ccd3fa3a04d4f2f119b8518afdfe68a3ff8d398b658e0a392c8c6f20edbe", + "file:size": 59039752, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge2": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/B06.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 2 - 20m", + "eo:bands": [ + { + "name": "B06", + "common_name": "rededge", + "center_wavelength": 0.74, + "full_width_half_max": 0.018 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12202845ee9ab281d92f8a52ca258888dfc5d365fd573c84a2e0e1333f04bec1002c", + "file:size": 63261115, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge3": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/B07.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 3 - 20m", + "eo:bands": [ + { + "name": "B07", + "common_name": "rededge", + "center_wavelength": 0.783, + "full_width_half_max": 0.028 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220cb2a79c6896d487e1807376f10f04b95d67551347a2b8981638e598c099c6d50", + "file:size": 63176832, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge1": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/B05.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 1 - 20m", + "eo:bands": [ + { + "name": "B05", + "common_name": "rededge", + "center_wavelength": 0.704, + "full_width_half_max": 0.019 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12200a6a8b9d24cae10dfce2a03c991812a680eef1d1a7eba2f6cf981eba173996f5", + "file:size": 63413189, + "roles": [ + "data", + "reflectance" + ] + }, + "swir16": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/B11.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 1.6μm - 20m", + "eo:bands": [ + { + "name": "B11", + "common_name": "swir16", + "center_wavelength": 1.61, + "full_width_half_max": 0.143 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220f95845a647746d0ccb2fc94de8b991e7f58340ac4f0025dc40a0125feb423ad8", + "file:size": 59790146, + "roles": [ + "data", + "reflectance" + ] + }, + "wvp": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/WVP.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Water Vapour (WVP)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "unit": "cm", + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "12207d0019ae019c4366eacd6686eb6c6410472d31bc0c4be234f2040c425ae029db", + "file:size": 37646951, + "roles": [ + "data" + ] + }, + "nir08": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/B8A.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 2 - 20m", + "eo:bands": [ + { + "name": "B8A", + "common_name": "nir08", + "center_wavelength": 0.865, + "full_width_half_max": 0.033 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122035484a2ad13d811b4df5890d9135db88eef3b079e6f1d796bfb18a6d5ca4011d", + "file:size": 62890319, + "roles": [ + "data", + "reflectance" + ] + }, + "scl": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/SCL.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Scene classification map (SCL)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "1220eccfe8e8d91fe2ee32d02244438bf53efef35776037fb7b03914cacbfc78509c", + "file:size": 3112448, + "roles": [ + "data" + ] + }, + "aot": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/AOT.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Aerosol optical thickness (AOT)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "12203193ed9b34ee26035bca48613b6b202b2a8d41b7abb36e99712c912ae832c870", + "file:size": 3103511, + "roles": [ + "data" + ] + }, + "coastal": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/B01.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Coastal - 60m", + "eo:bands": [ + { + "name": "B01", + "common_name": "coastal", + "center_wavelength": 0.443, + "full_width_half_max": 0.027 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220369e932ae7a3a7b0ad356027465df1c390f84d9a0b36bf1314bb3ade3a7052be", + "file:size": 7018677, + "roles": [ + "data", + "reflectance" + ] + }, + "nir09": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/B09.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 3 - 60m", + "eo:bands": [ + { + "name": "B09", + "common_name": "nir09", + "center_wavelength": 0.945, + "full_width_half_max": 0.026 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220dd431c567b7104000a81e67ac23243e901824db76f3069e1fadc3ce483bf6280", + "file:size": 7142847, + "roles": [ + "data", + "reflectance" + ] + }, + "cloud": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/CLD_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Cloud Probabilities", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "12202ea95956830184ceabc81780f85cfc16bccc42127f71c396e4c2db1e1155bb48", + "file:size": 1918151, + "roles": [ + "data", + "cloud" + ] + }, + "snow": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/SNW_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Snow Probabilities", + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "122010005a2d79fd6a264dab2010163b2a77ea458b5f82ee25cecef7c5e972d571fa", + "file:size": 6149375, + "roles": [ + "data", + "snow-ice" + ] + }, + "preview": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/L2A_PVI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color preview", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "file:checksum": "1220f62bfa7f004d85d0fdbd8bbb87e1a5876a31dc73b183bc35348221f09a8aac15", + "file:size": 216155, + "roles": [ + "overview" + ] + }, + "granule_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/metadata.xml", + "type": "application/xml", + "file:checksum": "122077b9985bae1d16f7833d2fc398591e04173fbf2fb7da4ef623d3cb2887fc2de6", + "file:size": 626562, + "roles": [ + "metadata" + ] + }, + "tileinfo_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/tileInfo.json", + "type": "application/json", + "file:checksum": "1220990b7dcd83a3816d8162e9fb41da3732a69fe76da451634ebc806184a7eba5f5", + "file:size": 1491, + "roles": [ + "metadata" + ] + }, + "product_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/product_metadata.xml", + "type": "application/xml", + "file:checksum": "122018d0e98faa43224cfa448ec939b4a79698cfb6f9b24d63ec8afffa8b2f3b2b59", + "file:size": 54765, + "roles": [ + "metadata" + ] + }, + "thumbnail": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240415T180048_L2A/L2A_PVI.jpg", + "type": "image/jpeg", + "title": "Thumbnail of preview image", + "file:checksum": "12207197f6e92438993f9a23ae92688eb484b4230847aba7d7e2c37fe6f4c4f67840", + "file:size": 43884, + "roles": [ + "thumbnail" + ] + } + }, + "bbox": [ + -106.183161, + 39.655762, + -104.884569, + 40.65079 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.1.0/schema.json", + "https://stac-extensions.github.io/file/v2.1.0/schema.json", + "https://stac-extensions.github.io/grid/v1.1.0/schema.json", + "https://stac-extensions.github.io/mgrs/v1.0.0/schema.json", + "https://stac-extensions.github.io/processing/v1.1.0/schema.json", + "https://stac-extensions.github.io/projection/v1.1.0/schema.json", + "https://stac-extensions.github.io/raster/v1.1.0/schema.json", + "https://stac-extensions.github.io/sentinel-2/v1.0.0/schema.json", + "https://stac-extensions.github.io/storage/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "collection": "sentinel-2-c1-l2a" + }, + { + "type": "Feature", + "stac_version": "1.0.0", + "id": "S2A_T13TDE_20240412T175055_L2A", + "properties": { + "created": "2024-04-13T02:31:00.070Z", + "platform": "sentinel-2a", + "constellation": "sentinel-2", + "instruments": [ + "msi" + ], + "eo:cloud_cover": 0.044906, + "proj:epsg": 32613, + "proj:centroid": { + "lat": 40.08313, + "lon": -105.06304 + }, + "mgrs:utm_zone": 13, + "mgrs:latitude_band": "T", + "mgrs:grid_square": "DE", + "grid:code": "MGRS-13TDE", + "view:azimuth": 106.27797350502138, + "view:incidence_angle": 10.600279751402354, + "view:sun_azimuth": 148.74435524318, + "view:sun_elevation": 55.2487220595099, + "s2:tile_id": "S2A_OPER_MSI_L2A_TL_2APS_20240413T003752_A045998_T13TDE_N05.10", + "s2:degraded_msi_data_percentage": 0.0428, + "s2:nodata_pixel_percentage": 73.963046, + "s2:saturated_defective_pixel_percentage": 0, + "s2:dark_features_percentage": 0.119145, + "s2:cloud_shadow_percentage": 0.014412, + "s2:vegetation_percentage": 13.459617, + "s2:not_vegetated_percentage": 82.864326, + "s2:water_percentage": 3.047927, + "s2:unclassified_percentage": 0.279488, + "s2:medium_proba_clouds_percentage": 0.013673, + "s2:high_proba_clouds_percentage": 0.002778, + "s2:thin_cirrus_percentage": 0.028455, + "s2:snow_ice_percentage": 0.17018, + "s2:product_type": "S2MSI2A", + "s2:processing_baseline": "05.10", + "s2:product_uri": "S2A_MSIL2A_20240412T173901_N0510_R098_T13TDE_20240413T003752.SAFE", + "s2:generation_time": "2024-04-13T00:37:52.000000Z", + "s2:datatake_id": "GS2A_20240412T173901_045998_N05.10", + "s2:datatake_type": "INS-NOBS", + "s2:datastrip_id": "S2A_OPER_MSI_L2A_DS_2APS_20240413T003752_S20240412T175055_N05.10", + "s2:reflectance_conversion_factor": 0.997359967327157, + "datetime": "2024-04-12T17:53:00.534000Z", + "earthsearch:payload_id": "roda-sentinel-2-c1-l2a/workflow-sentinel-2-c1-l2a-to-stac/8e7c18c202144b6123396ad6056b0029", + "storage:platform": "AWS", + "storage:region": "us-west-2", + "storage:requester_pays": false, + "processing:software": { + "sentinel-2-c1-l2a-to-stac": "v2024.02.01" + }, + "updated": "2024-04-13T02:31:00.070Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -105.07045544265836, + 40.65082601343913 + ], + [ + -105.36693669221448, + 39.66103634108784 + ], + [ + -104.88623172845638, + 39.661560248682505 + ], + [ + -104.88456877606482, + 40.65078981397619 + ], + [ + -105.07045544265836, + 40.65082601343913 + ] + ] + ] + }, + "links": [ + { + "rel": "self", + "type": "application/geo+json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2A_T13TDE_20240412T175055_L2A" + }, + { + "rel": "canonical", + "href": "s3://e84-earth-search-sentinel-data/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/S2A_T13TDE_20240412T175055_L2A.json", + "type": "application/json" + }, + { + "rel": "via", + "href": "s3://sentinel-s2-l2a/tiles/13/T/DE/2024/4/12/0/metadata.xml", + "type": "application/xml", + "title": "Granule Metadata in Sinergize RODA Archive" + }, + { + "rel": "parent", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "collection", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "root", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1" + }, + { + "rel": "thumbnail", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2A_T13TDE_20240412T175055_L2A/thumbnail" + } + ], + "assets": { + "red": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/B04.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red - 10m", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12201ad54c10ad7837f68cb8452fbd14d77ba5eec73e3314c5dd96f239166e4051d5", + "file:size": 60034972, + "roles": [ + "data", + "reflectance" + ] + }, + "green": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/B03.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Green - 10m", + "eo:bands": [ + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12209abbe6b8f7b1044da038fabc6a5b7f045d570d500f3032c3ce881663f70f0b6e", + "file:size": 59425681, + "roles": [ + "data", + "reflectance" + ] + }, + "blue": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/B02.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Blue - 10m", + "eo:bands": [ + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12209111704350b9280e6972487f1c4d33d3dd5ce573a62196a4cd6c8cd00d0ab170", + "file:size": 60236910, + "roles": [ + "data", + "reflectance" + ] + }, + "visual": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/TCI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color image", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "file:checksum": "1220c7fb1643a757e79b905fafb628d56c647f6943b95ace6701f0e43b4ca432751b", + "file:size": 94534216, + "roles": [ + "visual" + ] + }, + "nir": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/B08.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 1 - 10m", + "eo:bands": [ + { + "name": "B08", + "common_name": "nir", + "center_wavelength": 0.842, + "full_width_half_max": 0.145 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12207fced1671169225c1db61f0595f9bcc234c7ac01837fe3e07ce69c0d77fadd25", + "file:size": 60216710, + "roles": [ + "data", + "reflectance" + ] + }, + "swir22": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/B12.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 2.2μm - 20m", + "eo:bands": [ + { + "name": "B12", + "common_name": "swir22", + "center_wavelength": 2.19, + "full_width_half_max": 0.242 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122069348f0e259f5f04078e0986159967908ff799c1c648955541044a546f3af385", + "file:size": 15942833, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge2": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/B06.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 2 - 20m", + "eo:bands": [ + { + "name": "B06", + "common_name": "rededge", + "center_wavelength": 0.74, + "full_width_half_max": 0.018 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122050907d29a925e53c9e2e75faed8fb493667fe50b45561b905c14a14d440d8c0d", + "file:size": 16101490, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge3": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/B07.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 3 - 20m", + "eo:bands": [ + { + "name": "B07", + "common_name": "rededge", + "center_wavelength": 0.783, + "full_width_half_max": 0.028 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12207a462d819688498051d8e2ede3d23c4ef08ccc47c5e2f9ce4ee3f99f0f9144a8", + "file:size": 16253802, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge1": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/B05.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 1 - 20m", + "eo:bands": [ + { + "name": "B05", + "common_name": "rededge", + "center_wavelength": 0.704, + "full_width_half_max": 0.019 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122099921bae2b5e028f9d7ecfb8968e1a109dd848b9669ce393ac3d002dbc90f41c", + "file:size": 15918299, + "roles": [ + "data", + "reflectance" + ] + }, + "swir16": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/B11.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 1.6μm - 20m", + "eo:bands": [ + { + "name": "B11", + "common_name": "swir16", + "center_wavelength": 1.61, + "full_width_half_max": 0.143 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220a8b40260f180f72180530536316e51881b618a438ccf2e923b6d5d72c0c8860d", + "file:size": 16033877, + "roles": [ + "data", + "reflectance" + ] + }, + "wvp": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/WVP.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Water Vapour (WVP)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "unit": "cm", + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "1220bc1942e9ec697d6f01e883ba9c9bec651cf57542f1f35c9e2ddd252e7dc68b17", + "file:size": 12462896, + "roles": [ + "data" + ] + }, + "nir08": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/B8A.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 2 - 20m", + "eo:bands": [ + { + "name": "B8A", + "common_name": "nir08", + "center_wavelength": 0.865, + "full_width_half_max": 0.033 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12208f467f31d7cfed675723cce5b12c3028cd2a09e43e25f910e7e9620203e8a70a", + "file:size": 16286067, + "roles": [ + "data", + "reflectance" + ] + }, + "scl": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/SCL.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Scene classification map (SCL)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "12203352ad0b8f0818941c76f5c46a26d1e0b047ff45bfad4586f2cf2d016276502b", + "file:size": 788325, + "roles": [ + "data" + ] + }, + "aot": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/AOT.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Aerosol optical thickness (AOT)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "122089a083fc809809fed54aa369232b4e7312b5e7797eb0d75854ffbfe72791ea47", + "file:size": 292700, + "roles": [ + "data" + ] + }, + "coastal": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/B01.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Coastal - 60m", + "eo:bands": [ + { + "name": "B01", + "common_name": "coastal", + "center_wavelength": 0.443, + "full_width_half_max": 0.027 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220292cf06a07ee40a35bf8f16acada9dded7c944d6b2ad117ac7ba3fd1a7e1bb4e", + "file:size": 1706605, + "roles": [ + "data", + "reflectance" + ] + }, + "nir09": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/B09.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 3 - 60m", + "eo:bands": [ + { + "name": "B09", + "common_name": "nir09", + "center_wavelength": 0.945, + "full_width_half_max": 0.026 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220172f1451ad87bd93a440917d7386061faa348407dd3f3659f7bcb0824c64c5d3", + "file:size": 1857378, + "roles": [ + "data", + "reflectance" + ] + }, + "cloud": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/CLD_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Cloud Probabilities", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "122009ece2a6822c3715c98789878f8b17a3100c0cef6117a4fc242a9d8bc4012a8e", + "file:size": 94196, + "roles": [ + "data", + "cloud" + ] + }, + "snow": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/SNW_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Snow Probabilities", + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "1220eaf498105039de71c6706b9edcfe414cb9b72f4ae7f1ff0afe507bf33c7b198c", + "file:size": 69827, + "roles": [ + "data", + "snow-ice" + ] + }, + "preview": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/L2A_PVI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color preview", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "file:checksum": "12209ff8fc31034c5d6cd080d414fe9c971236de05d1c2335924ccb74f67f10257db", + "file:size": 96308, + "roles": [ + "overview" + ] + }, + "granule_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/metadata.xml", + "type": "application/xml", + "file:checksum": "1220086bc3574d011e8b0f268ff5f22b0109f089a9645a322a77d45ba21e0e27f360", + "file:size": 193456, + "roles": [ + "metadata" + ] + }, + "tileinfo_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/tileInfo.json", + "type": "application/json", + "file:checksum": "12209138608b9ae3625ede6565408c3b3e8f7b2f93caa8642440092d936ddb7009f6", + "file:size": 1560, + "roles": [ + "metadata" + ] + }, + "product_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/product_metadata.xml", + "type": "application/xml", + "file:checksum": "1220a518be1bb259e9e028786ea80ab02a5f2c13ac5ed2efa90364100d10f1008480", + "file:size": 55026, + "roles": [ + "metadata" + ] + }, + "thumbnail": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240412T175055_L2A/L2A_PVI.jpg", + "type": "image/jpeg", + "title": "Thumbnail of preview image", + "file:checksum": "1220507b32d9025323ae25d1f85e3488ce8c19465a90435f88b8150701d49a4d9f08", + "file:size": 15913, + "roles": [ + "thumbnail" + ] + } + }, + "bbox": [ + -105.366937, + 39.661036, + -104.884569, + 40.650826 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.1.0/schema.json", + "https://stac-extensions.github.io/file/v2.1.0/schema.json", + "https://stac-extensions.github.io/grid/v1.1.0/schema.json", + "https://stac-extensions.github.io/mgrs/v1.0.0/schema.json", + "https://stac-extensions.github.io/processing/v1.1.0/schema.json", + "https://stac-extensions.github.io/projection/v1.1.0/schema.json", + "https://stac-extensions.github.io/raster/v1.1.0/schema.json", + "https://stac-extensions.github.io/sentinel-2/v1.0.0/schema.json", + "https://stac-extensions.github.io/storage/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "collection": "sentinel-2-c1-l2a" + }, + { + "type": "Feature", + "stac_version": "1.0.0", + "id": "S2B_T13TDE_20240410T175332_L2A", + "properties": { + "created": "2024-04-11T04:44:01.302Z", + "platform": "sentinel-2b", + "constellation": "sentinel-2", + "instruments": [ + "msi" + ], + "eo:cloud_cover": 77.654099, + "proj:epsg": 32613, + "proj:centroid": { + "lat": 40.15442, + "lon": -105.53002 + }, + "mgrs:utm_zone": 13, + "mgrs:latitude_band": "T", + "mgrs:grid_square": "DE", + "grid:code": "MGRS-13TDE", + "view:azimuth": 234.47551682773184, + "view:incidence_angle": 3.6551478212696207, + "view:sun_azimuth": 153.024011299339, + "view:sun_elevation": 55.4508689714105, + "s2:tile_id": "S2B_OPER_MSI_L2A_TL_2BPS_20240410T214811_A037061_T13TDE_N05.10", + "s2:degraded_msi_data_percentage": 0.0436, + "s2:nodata_pixel_percentage": 0, + "s2:saturated_defective_pixel_percentage": 0, + "s2:dark_features_percentage": 0.078649, + "s2:cloud_shadow_percentage": 3.186134, + "s2:vegetation_percentage": 0.902718, + "s2:not_vegetated_percentage": 9.745422, + "s2:water_percentage": 0.219359, + "s2:unclassified_percentage": 1.279992, + "s2:medium_proba_clouds_percentage": 30.563575, + "s2:high_proba_clouds_percentage": 47.03404, + "s2:thin_cirrus_percentage": 0.056486, + "s2:snow_ice_percentage": 6.933624, + "s2:product_type": "S2MSI2A", + "s2:processing_baseline": "05.10", + "s2:product_uri": "S2B_MSIL2A_20240410T174909_N0510_R141_T13TDE_20240410T214811.SAFE", + "s2:generation_time": "2024-04-10T21:48:11.000000Z", + "s2:datatake_id": "GS2B_20240410T174909_037061_N05.10", + "s2:datatake_type": "INS-NOBS", + "s2:datastrip_id": "S2B_OPER_MSI_L2A_DS_2BPS_20240410T214811_S20240410T175332_N05.10", + "s2:reflectance_conversion_factor": 0.998501129753324, + "datetime": "2024-04-10T18:02:55.451000Z", + "earthsearch:payload_id": "roda-sentinel-2-c1-l2a/workflow-sentinel-2-c1-l2a-to-stac/4024ee73f8123ec1db5d30dc6357ace1", + "storage:platform": "AWS", + "storage:region": "us-west-2", + "storage:requester_pays": false, + "processing:software": { + "sentinel-2-c1-l2a-to-stac": "v2024.02.01" + }, + "updated": "2024-04-11T04:44:01.302Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -106.18316062292897, + 40.64478591807637 + ], + [ + -106.1661201925584, + 39.65576169772817 + ], + [ + -104.88623172845638, + 39.661560248682505 + ], + [ + -104.88456877606482, + 40.65078981397619 + ], + [ + -106.18316062292897, + 40.64478591807637 + ] + ] + ] + }, + "links": [ + { + "rel": "self", + "type": "application/geo+json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2B_T13TDE_20240410T175332_L2A" + }, + { + "rel": "canonical", + "href": "s3://e84-earth-search-sentinel-data/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/S2B_T13TDE_20240410T175332_L2A.json", + "type": "application/json" + }, + { + "rel": "via", + "href": "s3://sentinel-s2-l2a/tiles/13/T/DE/2024/4/10/0/metadata.xml", + "type": "application/xml", + "title": "Granule Metadata in Sinergize RODA Archive" + }, + { + "rel": "parent", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "collection", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "root", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1" + }, + { + "rel": "thumbnail", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2B_T13TDE_20240410T175332_L2A/thumbnail" + } + ], + "assets": { + "red": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/B04.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red - 10m", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122019f2d790295fbf31278df051ad0cf23590ee4e3fd6cde07d06d3a9607973f5b7", + "file:size": 205423827, + "roles": [ + "data", + "reflectance" + ] + }, + "green": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/B03.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Green - 10m", + "eo:bands": [ + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220715db3e7c2de889a2d1642240ccc6b12ad7b14a6841219275420b607d7c652b1", + "file:size": 205287985, + "roles": [ + "data", + "reflectance" + ] + }, + "blue": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/B02.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Blue - 10m", + "eo:bands": [ + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12200b26564ef00bf1fe15888312a071c96873ddeafc8bdfe249e8671278a3cb057a", + "file:size": 206188082, + "roles": [ + "data", + "reflectance" + ] + }, + "visual": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/TCI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color image", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "file:checksum": "12202fbd7769938dd7964115cf8dd8cbbc276e2ce7658b2c67439ab701a484d9402a", + "file:size": 99252557, + "roles": [ + "visual" + ] + }, + "nir": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/B08.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 1 - 10m", + "eo:bands": [ + { + "name": "B08", + "common_name": "nir", + "center_wavelength": 0.842, + "full_width_half_max": 0.145 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122008ccac63bdfbc5e2e00e69504e9723c7558c5beda0ec6b9361ff82caf2558c2b", + "file:size": 202146858, + "roles": [ + "data", + "reflectance" + ] + }, + "swir22": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/B12.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 2.2μm - 20m", + "eo:bands": [ + { + "name": "B12", + "common_name": "swir22", + "center_wavelength": 2.19, + "full_width_half_max": 0.242 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12204c52662d26efa636b8d565b0daa51a3a2c9162886765795fd4c8b92a7b59dd28", + "file:size": 59245368, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge2": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/B06.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 2 - 20m", + "eo:bands": [ + { + "name": "B06", + "common_name": "rededge", + "center_wavelength": 0.74, + "full_width_half_max": 0.018 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220b8350283b0215b1ef2ec18e75b20dbbb051aab8dcecc824b2aa569cc7fbe8151", + "file:size": 61166510, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge3": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/B07.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 3 - 20m", + "eo:bands": [ + { + "name": "B07", + "common_name": "rededge", + "center_wavelength": 0.783, + "full_width_half_max": 0.028 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220f6e4a05d72d076e39b4da9d2754214ab69e4352cef1b101356d778fffcf435c9", + "file:size": 61073576, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge1": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/B05.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 1 - 20m", + "eo:bands": [ + { + "name": "B05", + "common_name": "rededge", + "center_wavelength": 0.704, + "full_width_half_max": 0.019 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220c71a38b182cbdfd717aaba488812f9477256f5939861e85ecf1541e8022957dc", + "file:size": 61342653, + "roles": [ + "data", + "reflectance" + ] + }, + "swir16": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/B11.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 1.6μm - 20m", + "eo:bands": [ + { + "name": "B11", + "common_name": "swir16", + "center_wavelength": 1.61, + "full_width_half_max": 0.143 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220b9ff7a78888561409ce7df087f5149d40c88ef0beab71a6dbc4f3c6fa21404fd", + "file:size": 59213880, + "roles": [ + "data", + "reflectance" + ] + }, + "wvp": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/WVP.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Water Vapour (WVP)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "unit": "cm", + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "12201f6548031eba196024d29aa7eda1d4d18b9e3f18fb6b6f0ca9529bbaff3b4b91", + "file:size": 10046154, + "roles": [ + "data" + ] + }, + "nir08": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/B8A.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 2 - 20m", + "eo:bands": [ + { + "name": "B8A", + "common_name": "nir08", + "center_wavelength": 0.865, + "full_width_half_max": 0.033 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220812a9e640ac3d312f064e9eaa2124e01d4f3c8c9e31bfed7b2d07ba5c098867e", + "file:size": 60943243, + "roles": [ + "data", + "reflectance" + ] + }, + "scl": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/SCL.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Scene classification map (SCL)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "1220e53d624bb547ab2a37210b76a49b2254f1a8150e45b75e322a95b783d401b708", + "file:size": 2530218, + "roles": [ + "data" + ] + }, + "aot": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/AOT.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Aerosol optical thickness (AOT)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "12205e5fa2b27f2968be0ce28ec70a2f3e243b585aa0c0e8469ce8e6c2600d78054b", + "file:size": 1385315, + "roles": [ + "data" + ] + }, + "coastal": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/B01.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Coastal - 60m", + "eo:bands": [ + { + "name": "B01", + "common_name": "coastal", + "center_wavelength": 0.443, + "full_width_half_max": 0.027 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122054f66d90a5f7ce92e70322d74668816c1fae6012b6a56faff04410555665c4c7", + "file:size": 7098101, + "roles": [ + "data", + "reflectance" + ] + }, + "nir09": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/B09.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 3 - 60m", + "eo:bands": [ + { + "name": "B09", + "common_name": "nir09", + "center_wavelength": 0.945, + "full_width_half_max": 0.026 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12207c6eec77d31f391ca91625bbd8c3d6da501ceb4966df126e102c488b4af13e81", + "file:size": 7248524, + "roles": [ + "data", + "reflectance" + ] + }, + "cloud": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/CLD_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Cloud Probabilities", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "12207327e57223dcf41dffe97f3fe8d24c12db81ded2b8e42b0fd5269bfbfc098773", + "file:size": 6029404, + "roles": [ + "data", + "cloud" + ] + }, + "snow": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/SNW_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Snow Probabilities", + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "12205c8d933e9889bcb558ba7d0f198c4e5e4cbf8b340bf0d87316bac78bfe1c2dee", + "file:size": 2770297, + "roles": [ + "data", + "snow-ice" + ] + }, + "preview": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/L2A_PVI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color preview", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "file:checksum": "122031fee660caa99cd6f35f2beaf5323ea87e3ae78175f875ec1809602f8f552aa3", + "file:size": 145272, + "roles": [ + "overview" + ] + }, + "granule_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/metadata.xml", + "type": "application/xml", + "file:checksum": "1220fc9774deda91e34674dfbcf3fdcf8fc5c4fd4c19a1c72914b1ab80ba2e62d6d4", + "file:size": 626455, + "roles": [ + "metadata" + ] + }, + "tileinfo_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/tileInfo.json", + "type": "application/json", + "file:checksum": "12203ac9a988ec52e13a34f328ac1d96522f7c421285bce8369f38d6157129692a4e", + "file:size": 1491, + "roles": [ + "metadata" + ] + }, + "product_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/product_metadata.xml", + "type": "application/xml", + "file:checksum": "1220f5c80fb21dbd0ec82f45426646b0f4da15f8b6b3b4b05066da11c73055ed1415", + "file:size": 54715, + "roles": [ + "metadata" + ] + }, + "thumbnail": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240410T175332_L2A/L2A_PVI.jpg", + "type": "image/jpeg", + "title": "Thumbnail of preview image", + "file:checksum": "12207fc04ac89e82b7ff74b704ca631ad928c12f0099d60805b07c2d72c179c006e7", + "file:size": 27615, + "roles": [ + "thumbnail" + ] + } + }, + "bbox": [ + -106.183161, + 39.655762, + -104.884569, + 40.65079 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.1.0/schema.json", + "https://stac-extensions.github.io/file/v2.1.0/schema.json", + "https://stac-extensions.github.io/grid/v1.1.0/schema.json", + "https://stac-extensions.github.io/mgrs/v1.0.0/schema.json", + "https://stac-extensions.github.io/processing/v1.1.0/schema.json", + "https://stac-extensions.github.io/projection/v1.1.0/schema.json", + "https://stac-extensions.github.io/raster/v1.1.0/schema.json", + "https://stac-extensions.github.io/sentinel-2/v1.0.0/schema.json", + "https://stac-extensions.github.io/storage/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "collection": "sentinel-2-c1-l2a" + }, + { + "type": "Feature", + "stac_version": "1.0.0", + "id": "S2B_T13TDE_20240407T174209_L2A", + "properties": { + "created": "2024-04-07T23:51:26.431Z", + "platform": "sentinel-2b", + "constellation": "sentinel-2", + "instruments": [ + "msi" + ], + "eo:cloud_cover": 0.881778, + "proj:epsg": 32613, + "proj:centroid": { + "lat": 40.0806, + "lon": -105.0586 + }, + "mgrs:utm_zone": 13, + "mgrs:latitude_band": "T", + "mgrs:grid_square": "DE", + "grid:code": "MGRS-13TDE", + "view:azimuth": 107.03632894972338, + "view:incidence_angle": 10.6354581492193, + "view:sun_azimuth": 149.467152013734, + "view:sun_elevation": 53.4226167804796, + "s2:tile_id": "S2B_OPER_MSI_L2A_TL_2BPS_20240407T213028_A037018_T13TDE_N05.10", + "s2:degraded_msi_data_percentage": 0.0004, + "s2:nodata_pixel_percentage": 74.705076, + "s2:saturated_defective_pixel_percentage": 0, + "s2:dark_features_percentage": 0.140217, + "s2:cloud_shadow_percentage": 0.031677, + "s2:vegetation_percentage": 10.994349, + "s2:not_vegetated_percentage": 84.091443, + "s2:water_percentage": 2.945336, + "s2:unclassified_percentage": 0.330263, + "s2:medium_proba_clouds_percentage": 0.099004, + "s2:high_proba_clouds_percentage": 0.35163, + "s2:thin_cirrus_percentage": 0.431143, + "s2:snow_ice_percentage": 0.584936, + "s2:product_type": "S2MSI2A", + "s2:processing_baseline": "05.10", + "s2:product_uri": "S2B_MSIL2A_20240407T173859_N0510_R098_T13TDE_20240407T213028.SAFE", + "s2:generation_time": "2024-04-07T21:30:28.000000Z", + "s2:datatake_id": "GS2B_20240407T173859_037018_N05.10", + "s2:datatake_type": "INS-NOBS", + "s2:datastrip_id": "S2B_OPER_MSI_L2A_DS_2BPS_20240407T213028_S20240407T174209_N05.10", + "s2:reflectance_conversion_factor": 1.00022957618885, + "datetime": "2024-04-07T17:52:58.094000Z", + "earthsearch:payload_id": "roda-sentinel-2-c1-l2a/workflow-sentinel-2-c1-l2a-to-stac/40f56a26b6053501082949ec83d47a5b", + "storage:platform": "AWS", + "storage:region": "us-west-2", + "storage:requester_pays": false, + "processing:software": { + "sentinel-2-c1-l2a-to-stac": "v2024.02.01" + }, + "updated": "2024-04-07T23:51:26.431Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -105.0600460464306, + 40.650831895317104 + ], + [ + -105.35784488133612, + 39.661064708907155 + ], + [ + -104.88623172845638, + 39.661560248682505 + ], + [ + -104.88456877606482, + 40.65078981397619 + ], + [ + -105.0600460464306, + 40.650831895317104 + ] + ] + ] + }, + "links": [ + { + "rel": "self", + "type": "application/geo+json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2B_T13TDE_20240407T174209_L2A" + }, + { + "rel": "canonical", + "href": "s3://e84-earth-search-sentinel-data/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/S2B_T13TDE_20240407T174209_L2A.json", + "type": "application/json" + }, + { + "rel": "via", + "href": "s3://sentinel-s2-l2a/tiles/13/T/DE/2024/4/7/0/metadata.xml", + "type": "application/xml", + "title": "Granule Metadata in Sinergize RODA Archive" + }, + { + "rel": "parent", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "collection", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "root", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1" + }, + { + "rel": "thumbnail", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2B_T13TDE_20240407T174209_L2A/thumbnail" + } + ], + "assets": { + "red": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/B04.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red - 10m", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12205ec6ea21446e1e3ba223ccf03275b1e6d171777c1c2bfdbaa53bc788eb7695b0", + "file:size": 58254385, + "roles": [ + "data", + "reflectance" + ] + }, + "green": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/B03.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Green - 10m", + "eo:bands": [ + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12201a439686f888c93e8fdcc28caac4c35f3142d413c8a6fda0de7a5371e9cc9c54", + "file:size": 57573183, + "roles": [ + "data", + "reflectance" + ] + }, + "blue": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/B02.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Blue - 10m", + "eo:bands": [ + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220b9df608f5904f655d9b70aea44cf0fe7e201c891b2d5bb3cddb16f15d05a9963", + "file:size": 58280277, + "roles": [ + "data", + "reflectance" + ] + }, + "visual": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/TCI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color image", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "file:checksum": "12205c9604382bcf5d7350f249590c579f830603a4600acfe8b889b5bba9a7a0b0b7", + "file:size": 91620879, + "roles": [ + "visual" + ] + }, + "nir": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/B08.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 1 - 10m", + "eo:bands": [ + { + "name": "B08", + "common_name": "nir", + "center_wavelength": 0.842, + "full_width_half_max": 0.145 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12205105e2e2ed0ca9ffa7fdd4c11904ed2f28b1cff121909121f2346d078b763334", + "file:size": 58645788, + "roles": [ + "data", + "reflectance" + ] + }, + "swir22": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/B12.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 2.2μm - 20m", + "eo:bands": [ + { + "name": "B12", + "common_name": "swir22", + "center_wavelength": 2.19, + "full_width_half_max": 0.242 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122041f19b57aad0792a3f5d955fec886d31b61a54d46b84f3e52ad519516a9cf272", + "file:size": 15622638, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge2": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/B06.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 2 - 20m", + "eo:bands": [ + { + "name": "B06", + "common_name": "rededge", + "center_wavelength": 0.74, + "full_width_half_max": 0.018 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220b0bd7adcf58ef4204f61d4a76784dfd204eb243853f98cebaa8d545fc1df8824", + "file:size": 15655225, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge3": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/B07.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 3 - 20m", + "eo:bands": [ + { + "name": "B07", + "common_name": "rededge", + "center_wavelength": 0.783, + "full_width_half_max": 0.028 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220595653a898ac584871280ace97126b99dbdfa9583090552d970bc5fbcd6e2910", + "file:size": 15776270, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge1": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/B05.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 1 - 20m", + "eo:bands": [ + { + "name": "B05", + "common_name": "rededge", + "center_wavelength": 0.704, + "full_width_half_max": 0.019 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122090713807c7c32e14d51bfc4765a23dca3d41df2c040a3fbca3b68adefd490f60", + "file:size": 15490464, + "roles": [ + "data", + "reflectance" + ] + }, + "swir16": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/B11.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 1.6μm - 20m", + "eo:bands": [ + { + "name": "B11", + "common_name": "swir16", + "center_wavelength": 1.61, + "full_width_half_max": 0.143 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122069ac9f10dda430723f0d6f07c104c502f83384ee8b35eae699e5ae3ea411d404", + "file:size": 15667152, + "roles": [ + "data", + "reflectance" + ] + }, + "wvp": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/WVP.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Water Vapour (WVP)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "unit": "cm", + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "12206da9cc02fdd0128922ae5fea6d584fe3e46252b4d1a9015428537164a03ba97e", + "file:size": 11487615, + "roles": [ + "data" + ] + }, + "nir08": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/B8A.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 2 - 20m", + "eo:bands": [ + { + "name": "B8A", + "common_name": "nir08", + "center_wavelength": 0.865, + "full_width_half_max": 0.033 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122062c636f189f95474774ec944aad0a41ecb8217541f93cf3e1da6f3d6fa0939e7", + "file:size": 15816134, + "roles": [ + "data", + "reflectance" + ] + }, + "scl": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/SCL.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Scene classification map (SCL)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "12202954129d836c523e31fda45c9b5cfe3d8a578c02cc3712b177d8883a1d44624c", + "file:size": 737440, + "roles": [ + "data" + ] + }, + "aot": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/AOT.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Aerosol optical thickness (AOT)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "1220df1a34be54bf96c1dd380368c2bae58c8e354e0c86f0a303474d0e1980fca53e", + "file:size": 225500, + "roles": [ + "data" + ] + }, + "coastal": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/B01.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Coastal - 60m", + "eo:bands": [ + { + "name": "B01", + "common_name": "coastal", + "center_wavelength": 0.443, + "full_width_half_max": 0.027 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122023b05f067c57dbbc22bf76e3f9cf3acade755d0f436919b64c4ea4cc40b14b0e", + "file:size": 1654191, + "roles": [ + "data", + "reflectance" + ] + }, + "nir09": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/B09.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 3 - 60m", + "eo:bands": [ + { + "name": "B09", + "common_name": "nir09", + "center_wavelength": 0.945, + "full_width_half_max": 0.026 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122069b62b9f0ede695a55e3a5410991a0ba4b98c04fda7ac0c4925949324d3b5786", + "file:size": 1801813, + "roles": [ + "data", + "reflectance" + ] + }, + "cloud": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/CLD_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Cloud Probabilities", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "1220650f579671a6ee927abb463f4df57cf1dc9f06d0cbe7ea375662f6c6172ffd67", + "file:size": 119775, + "roles": [ + "data", + "cloud" + ] + }, + "snow": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/SNW_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Snow Probabilities", + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "122094b4259a0c0e947234d1accc3a3a91e2239dec5811363292445a43e7edad178e", + "file:size": 95899, + "roles": [ + "data", + "snow-ice" + ] + }, + "preview": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/L2A_PVI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color preview", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "file:checksum": "12208553a6ec993b26cce3f9813efa7039584294d425e6ac6df95726e1adf4e2b6b2", + "file:size": 94000, + "roles": [ + "overview" + ] + }, + "granule_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/metadata.xml", + "type": "application/xml", + "file:checksum": "1220cace748377474c4effc63b62e77e078bb450382be69e343cf19b4c642428135c", + "file:size": 193254, + "roles": [ + "metadata" + ] + }, + "tileinfo_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/tileInfo.json", + "type": "application/json", + "file:checksum": "1220d2d55b5d0320bdabb448ffe5678a4b6b889877f42df452c9b054edc2327bae34", + "file:size": 1515, + "roles": [ + "metadata" + ] + }, + "product_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/product_metadata.xml", + "type": "application/xml", + "file:checksum": "12200df7f6c4e3c0dc1396f23fe50d4831af49564ae9043ff5d337f24d8e142cd696", + "file:size": 55079, + "roles": [ + "metadata" + ] + }, + "thumbnail": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2B_T13TDE_20240407T174209_L2A/L2A_PVI.jpg", + "type": "image/jpeg", + "title": "Thumbnail of preview image", + "file:checksum": "12204a3ed53b519b4f2a04d439fd90d78e84932cc3c55d705671b09677582ff7027c", + "file:size": 15394, + "roles": [ + "thumbnail" + ] + } + }, + "bbox": [ + -105.357845, + 39.661065, + -104.884569, + 40.650832 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.1.0/schema.json", + "https://stac-extensions.github.io/file/v2.1.0/schema.json", + "https://stac-extensions.github.io/grid/v1.1.0/schema.json", + "https://stac-extensions.github.io/mgrs/v1.0.0/schema.json", + "https://stac-extensions.github.io/processing/v1.1.0/schema.json", + "https://stac-extensions.github.io/projection/v1.1.0/schema.json", + "https://stac-extensions.github.io/raster/v1.1.0/schema.json", + "https://stac-extensions.github.io/sentinel-2/v1.0.0/schema.json", + "https://stac-extensions.github.io/storage/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "collection": "sentinel-2-c1-l2a" + }, + { + "type": "Feature", + "stac_version": "1.0.0", + "id": "S2A_T13TDE_20240405T175934_L2A", + "properties": { + "created": "2024-04-06T02:48:12.170Z", + "platform": "sentinel-2a", + "constellation": "sentinel-2", + "instruments": [ + "msi" + ], + "eo:cloud_cover": 11.954951, + "proj:epsg": 32613, + "proj:centroid": { + "lat": 40.15442, + "lon": -105.53002 + }, + "mgrs:utm_zone": 13, + "mgrs:latitude_band": "T", + "mgrs:grid_square": "DE", + "grid:code": "MGRS-13TDE", + "view:azimuth": 232.86576267913935, + "view:incidence_angle": 3.592679045669366, + "view:sun_azimuth": 153.575015779937, + "view:sun_elevation": 53.5805861726739, + "s2:tile_id": "S2A_OPER_MSI_L2A_TL_2APS_20240406T010253_A045898_T13TDE_N05.10", + "s2:degraded_msi_data_percentage": 0.0112, + "s2:nodata_pixel_percentage": 7e-6, + "s2:saturated_defective_pixel_percentage": 0, + "s2:dark_features_percentage": 1.734726, + "s2:cloud_shadow_percentage": 0.478177, + "s2:vegetation_percentage": 3.90948, + "s2:not_vegetated_percentage": 29.967618, + "s2:water_percentage": 0.930345, + "s2:unclassified_percentage": 2.679892, + "s2:medium_proba_clouds_percentage": 6.220929, + "s2:high_proba_clouds_percentage": 5.032399, + "s2:thin_cirrus_percentage": 0.701623, + "s2:snow_ice_percentage": 48.344812, + "s2:product_type": "S2MSI2A", + "s2:processing_baseline": "05.10", + "s2:product_uri": "S2A_MSIL2A_20240405T174901_N0510_R141_T13TDE_20240406T010253.SAFE", + "s2:generation_time": "2024-04-06T01:02:53.000000Z", + "s2:datatake_id": "GS2A_20240405T174901_045898_N05.10", + "s2:datatake_type": "INS-NOBS", + "s2:datastrip_id": "S2A_OPER_MSI_L2A_DS_2APS_20240406T010253_S20240405T175934_N05.10", + "s2:reflectance_conversion_factor": 1.00137758593587, + "datetime": "2024-04-05T18:02:53.145000Z", + "earthsearch:payload_id": "roda-sentinel-2-c1-l2a/workflow-sentinel-2-c1-l2a-to-stac/bbd23714be61b82ca1205e9f42d834fa", + "storage:platform": "AWS", + "storage:region": "us-west-2", + "storage:requester_pays": false, + "processing:software": { + "sentinel-2-c1-l2a-to-stac": "v2024.02.01" + }, + "updated": "2024-04-06T02:48:12.170Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -106.18316062292897, + 40.64478591807637 + ], + [ + -106.1661201925584, + 39.65576169772817 + ], + [ + -104.88623172845638, + 39.661560248682505 + ], + [ + -104.88456877606482, + 40.65078981397619 + ], + [ + -106.18316062292897, + 40.64478591807637 + ] + ] + ] + }, + "links": [ + { + "rel": "self", + "type": "application/geo+json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2A_T13TDE_20240405T175934_L2A" + }, + { + "rel": "canonical", + "href": "s3://e84-earth-search-sentinel-data/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/S2A_T13TDE_20240405T175934_L2A.json", + "type": "application/json" + }, + { + "rel": "via", + "href": "s3://sentinel-s2-l2a/tiles/13/T/DE/2024/4/5/0/metadata.xml", + "type": "application/xml", + "title": "Granule Metadata in Sinergize RODA Archive" + }, + { + "rel": "parent", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "collection", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "root", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1" + }, + { + "rel": "thumbnail", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2A_T13TDE_20240405T175934_L2A/thumbnail" + } + ], + "assets": { + "red": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/B04.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red - 10m", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12209b4639287ff96d63851fc365c796c3ed5212c12dcf1fc2ecbfd919f227cb4a96", + "file:size": 254077337, + "roles": [ + "data", + "reflectance" + ] + }, + "green": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/B03.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Green - 10m", + "eo:bands": [ + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122074be2bf5b443234248b76162d1ae8413885ca793304c1c3c5176251f0afd9a62", + "file:size": 253916402, + "roles": [ + "data", + "reflectance" + ] + }, + "blue": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/B02.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Blue - 10m", + "eo:bands": [ + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12206bf4081f242cd4e1bc03071cc165c4cd1f949883cb966d382ef9ca71ee7bc128", + "file:size": 254166519, + "roles": [ + "data", + "reflectance" + ] + }, + "visual": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/TCI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color image", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "file:checksum": "1220620a7225a365503edd6129509a780756a42a4da492bc9b99aa2ff9953951b3a5", + "file:size": 270613067, + "roles": [ + "visual" + ] + }, + "nir": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/B08.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 1 - 10m", + "eo:bands": [ + { + "name": "B08", + "common_name": "nir", + "center_wavelength": 0.842, + "full_width_half_max": 0.145 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12202c2f98baa5cf6bd8e634a325116ab9da31de560eecbafae4a6aa23c74cef321b", + "file:size": 251008841, + "roles": [ + "data", + "reflectance" + ] + }, + "swir22": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/B12.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 2.2μm - 20m", + "eo:bands": [ + { + "name": "B12", + "common_name": "swir22", + "center_wavelength": 2.19, + "full_width_half_max": 0.242 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220feaef5b81c5dae7bd29c45b60263a3824b01f46130f5c15cc2ed0a11e7a368a5", + "file:size": 55984827, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge2": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/B06.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 2 - 20m", + "eo:bands": [ + { + "name": "B06", + "common_name": "rededge", + "center_wavelength": 0.74, + "full_width_half_max": 0.018 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220cc7f84e719a44931904e62e6f44225ce558f4c9ce60257ae83d754eb90d204eb", + "file:size": 64145930, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge3": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/B07.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 3 - 20m", + "eo:bands": [ + { + "name": "B07", + "common_name": "rededge", + "center_wavelength": 0.783, + "full_width_half_max": 0.028 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220a48524e8eb6d88f41a40728b3f22e74fea777f2acbd37da6b7f92a690b087853", + "file:size": 63878390, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge1": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/B05.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 1 - 20m", + "eo:bands": [ + { + "name": "B05", + "common_name": "rededge", + "center_wavelength": 0.704, + "full_width_half_max": 0.019 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220c25f8b7228b50353656b84a3345f01dc40253ff4608f513aecd7b3905a8355f0", + "file:size": 64396331, + "roles": [ + "data", + "reflectance" + ] + }, + "swir16": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/B11.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 1.6μm - 20m", + "eo:bands": [ + { + "name": "B11", + "common_name": "swir16", + "center_wavelength": 1.61, + "full_width_half_max": 0.143 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12200fa0af6c0831d007114c4446b24e114f70c3244762cac6803d72fbac254f5bae", + "file:size": 56979236, + "roles": [ + "data", + "reflectance" + ] + }, + "wvp": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/WVP.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Water Vapour (WVP)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "unit": "cm", + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "12203d41aaf48702838cf78e0719273bf21e876464ade68bfafa749f22903b1a415c", + "file:size": 42551332, + "roles": [ + "data" + ] + }, + "nir08": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/B8A.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 2 - 20m", + "eo:bands": [ + { + "name": "B8A", + "common_name": "nir08", + "center_wavelength": 0.865, + "full_width_half_max": 0.033 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12205e0ee3df4573e77b4d83ec08efb77b56ea64be7f1a9ebd0a19a99f6be5fd9cab", + "file:size": 63431868, + "roles": [ + "data", + "reflectance" + ] + }, + "scl": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/SCL.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Scene classification map (SCL)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "1220268dee4b82585e0f85d7acbb28afb7c35acf6cd2f300e921245e5b60ad8621e5", + "file:size": 2629376, + "roles": [ + "data" + ] + }, + "aot": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/AOT.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Aerosol optical thickness (AOT)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "1220d26f4d330c3ff53280de277ccb13bee0d42b818c8a50089c736b9c278ee569fb", + "file:size": 2964037, + "roles": [ + "data" + ] + }, + "coastal": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/B01.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Coastal - 60m", + "eo:bands": [ + { + "name": "B01", + "common_name": "coastal", + "center_wavelength": 0.443, + "full_width_half_max": 0.027 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220a887aa7cf47dd3193d84804c5a9c167890db1ef3f2f884ba272f33fd5dd5910b", + "file:size": 7145498, + "roles": [ + "data", + "reflectance" + ] + }, + "nir09": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/B09.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 3 - 60m", + "eo:bands": [ + { + "name": "B09", + "common_name": "nir09", + "center_wavelength": 0.945, + "full_width_half_max": 0.026 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12202b291624012ec6827106e761db61cd3d4f288868aa71908afb0b989288e4f2a6", + "file:size": 7170397, + "roles": [ + "data", + "reflectance" + ] + }, + "cloud": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/CLD_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Cloud Probabilities", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "1220874a02b1c85e2442b22b671381b389e2a4da8ec2437c3e44fed329217bc89f36", + "file:size": 2338594, + "roles": [ + "data", + "cloud" + ] + }, + "snow": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/SNW_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Snow Probabilities", + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "1220582d03be3419aab806895aa36d2a2692cdcba4f54255eddc6c5d8bd6e4c0207b", + "file:size": 7595816, + "roles": [ + "data", + "snow-ice" + ] + }, + "preview": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/L2A_PVI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color preview", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "file:checksum": "1220254d81a9596a119a7ae584dc4980f001c906fbb1f4e0dc7467c2542bda4fc07b", + "file:size": 219550, + "roles": [ + "overview" + ] + }, + "granule_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/metadata.xml", + "type": "application/xml", + "file:checksum": "1220680ad7a78359b90621b3278b9b428f9f3bc8825211f3959f2680b256b780f648", + "file:size": 626574, + "roles": [ + "metadata" + ] + }, + "tileinfo_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/tileInfo.json", + "type": "application/json", + "file:checksum": "1220bbc85c2853e0905ba2b18a1af62587efd227abd66ec269920bf6c7a4264b5572", + "file:size": 1488, + "roles": [ + "metadata" + ] + }, + "product_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/product_metadata.xml", + "type": "application/xml", + "file:checksum": "122008614280b2122ac74cac78b81e9a1daa6d96177afa70eceafb25530974e2a99e", + "file:size": 54766, + "roles": [ + "metadata" + ] + }, + "thumbnail": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240405T175934_L2A/L2A_PVI.jpg", + "type": "image/jpeg", + "title": "Thumbnail of preview image", + "file:checksum": "1220e6ec3b692692f291fc1d58bc451afa4ff383122174e6b9b3e5013f1355506e8a", + "file:size": 46830, + "roles": [ + "thumbnail" + ] + } + }, + "bbox": [ + -106.183161, + 39.655762, + -104.884569, + 40.65079 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.1.0/schema.json", + "https://stac-extensions.github.io/file/v2.1.0/schema.json", + "https://stac-extensions.github.io/grid/v1.1.0/schema.json", + "https://stac-extensions.github.io/mgrs/v1.0.0/schema.json", + "https://stac-extensions.github.io/processing/v1.1.0/schema.json", + "https://stac-extensions.github.io/projection/v1.1.0/schema.json", + "https://stac-extensions.github.io/raster/v1.1.0/schema.json", + "https://stac-extensions.github.io/sentinel-2/v1.0.0/schema.json", + "https://stac-extensions.github.io/storage/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "collection": "sentinel-2-c1-l2a" + }, + { + "type": "Feature", + "stac_version": "1.0.0", + "id": "S2A_T13TDE_20240402T174230_L2A", + "properties": { + "created": "2024-04-03T03:37:33.923Z", + "platform": "sentinel-2a", + "constellation": "sentinel-2", + "instruments": [ + "msi" + ], + "eo:cloud_cover": 0.118322, + "proj:epsg": 32613, + "proj:centroid": { + "lat": 40.07961, + "lon": -105.05588 + }, + "mgrs:utm_zone": 13, + "mgrs:latitude_band": "T", + "mgrs:grid_square": "DE", + "grid:code": "MGRS-13TDE", + "view:azimuth": 106.54646389341784, + "view:incidence_angle": 10.653590762714533, + "view:sun_azimuth": 150.129041983544, + "view:sun_elevation": 51.5374593346921, + "s2:tile_id": "S2A_OPER_MSI_L2A_TL_2APS_20240403T012353_A045855_T13TDE_N05.10", + "s2:degraded_msi_data_percentage": 0.0446, + "s2:nodata_pixel_percentage": 75.1279, + "s2:saturated_defective_pixel_percentage": 0, + "s2:dark_features_percentage": 0.190623, + "s2:cloud_shadow_percentage": 0.075249, + "s2:vegetation_percentage": 7.499056, + "s2:not_vegetated_percentage": 83.973408, + "s2:water_percentage": 3.139982, + "s2:unclassified_percentage": 0.399374, + "s2:medium_proba_clouds_percentage": 0.09918, + "s2:high_proba_clouds_percentage": 0.008377, + "s2:thin_cirrus_percentage": 0.010765, + "s2:snow_ice_percentage": 4.603989, + "s2:product_type": "S2MSI2A", + "s2:processing_baseline": "05.10", + "s2:product_uri": "S2A_MSIL2A_20240402T173901_N0510_R098_T13TDE_20240403T012353.SAFE", + "s2:generation_time": "2024-04-03T01:23:53.000000Z", + "s2:datatake_id": "GS2A_20240402T173901_045855_N05.10", + "s2:datatake_type": "INS-NOBS", + "s2:datastrip_id": "S2A_OPER_MSI_L2A_DS_2APS_20240403T012353_S20240402T174230_N05.10", + "s2:reflectance_conversion_factor": 1.00310985637058, + "datetime": "2024-04-02T17:52:57.105000Z", + "earthsearch:payload_id": "roda-sentinel-2-c1-l2a/workflow-sentinel-2-c1-l2a-to-stac/75865858822323f2f60ec69042e4a30c", + "storage:platform": "AWS", + "storage:region": "us-west-2", + "storage:requester_pays": false, + "processing:software": { + "sentinel-2-c1-l2a-to-stac": "v2024.02.01" + }, + "updated": "2024-04-03T03:37:33.923Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -105.0550784920466, + 40.65083437151588 + ], + [ + -105.35155014903962, + 39.661083932459455 + ], + [ + -104.88623172845638, + 39.661560248682505 + ], + [ + -104.88456877606482, + 40.65078981397619 + ], + [ + -105.0550784920466, + 40.65083437151588 + ] + ] + ] + }, + "links": [ + { + "rel": "self", + "type": "application/geo+json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2A_T13TDE_20240402T174230_L2A" + }, + { + "rel": "canonical", + "href": "s3://e84-earth-search-sentinel-data/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/S2A_T13TDE_20240402T174230_L2A.json", + "type": "application/json" + }, + { + "rel": "via", + "href": "s3://sentinel-s2-l2a/tiles/13/T/DE/2024/4/2/0/metadata.xml", + "type": "application/xml", + "title": "Granule Metadata in Sinergize RODA Archive" + }, + { + "rel": "parent", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "collection", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "root", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1" + }, + { + "rel": "thumbnail", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2A_T13TDE_20240402T174230_L2A/thumbnail" + } + ], + "assets": { + "red": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/B04.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red - 10m", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220344c899115ce2b1930b975b2c23f3f8c1c1d08d6da6939e572332cef915fe2c9", + "file:size": 57369733, + "roles": [ + "data", + "reflectance" + ] + }, + "green": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/B03.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Green - 10m", + "eo:bands": [ + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220f77158e33dc38eae761d3d98a6048213b7a7d839d33d7db9ee6b4f6e0814629b", + "file:size": 57486863, + "roles": [ + "data", + "reflectance" + ] + }, + "blue": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/B02.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Blue - 10m", + "eo:bands": [ + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220092a16ad19d18b52be4de5c965b061de9013a84b5c2113a936db435abcaeed57", + "file:size": 58021606, + "roles": [ + "data", + "reflectance" + ] + }, + "visual": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/TCI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color image", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "file:checksum": "1220f13a6d97428b4928d33645a9edeef17f39eb477836d32ac61ded7b8b7817daca", + "file:size": 89304169, + "roles": [ + "visual" + ] + }, + "nir": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/B08.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 1 - 10m", + "eo:bands": [ + { + "name": "B08", + "common_name": "nir", + "center_wavelength": 0.842, + "full_width_half_max": 0.145 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12205e266415f790f7d5ab6a8bf5416882f33565856de667895ebf51f7425ed58429", + "file:size": 58094369, + "roles": [ + "data", + "reflectance" + ] + }, + "swir22": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/B12.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 2.2μm - 20m", + "eo:bands": [ + { + "name": "B12", + "common_name": "swir22", + "center_wavelength": 2.19, + "full_width_half_max": 0.242 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220a875eca70cb3ea0ae2dfa25f031a6a33cd3786c6e62d23286d288199f737547b", + "file:size": 15059788, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge2": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/B06.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 2 - 20m", + "eo:bands": [ + { + "name": "B06", + "common_name": "rededge", + "center_wavelength": 0.74, + "full_width_half_max": 0.018 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220ff8280cc939f98669747d560828cec19d33a56decf11093ff5938a726c54f59c", + "file:size": 15526400, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge3": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/B07.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 3 - 20m", + "eo:bands": [ + { + "name": "B07", + "common_name": "rededge", + "center_wavelength": 0.783, + "full_width_half_max": 0.028 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122012f1be4583f05ea9474bf2c3765e0c135d75134c890fb3d2f420775ae6990ba4", + "file:size": 15631924, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge1": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/B05.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 1 - 20m", + "eo:bands": [ + { + "name": "B05", + "common_name": "rededge", + "center_wavelength": 0.704, + "full_width_half_max": 0.019 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122035efdd67b16c53921cf49f4fbdee0312118762ea639d11bf3a553c364a9eec8f", + "file:size": 15291177, + "roles": [ + "data", + "reflectance" + ] + }, + "swir16": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/B11.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 1.6μm - 20m", + "eo:bands": [ + { + "name": "B11", + "common_name": "swir16", + "center_wavelength": 1.61, + "full_width_half_max": 0.143 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220fa86bbedac613f20cbc05b408e65efb2c5d7f89afc6d8b7d1fe861d2e0886956", + "file:size": 15269476, + "roles": [ + "data", + "reflectance" + ] + }, + "wvp": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/WVP.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Water Vapour (WVP)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "unit": "cm", + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "1220e61718337eec32e43f799a4dced8940dda664306dae9b1213cd810f85a8ecd8e", + "file:size": 12173938, + "roles": [ + "data" + ] + }, + "nir08": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/B8A.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 2 - 20m", + "eo:bands": [ + { + "name": "B8A", + "common_name": "nir08", + "center_wavelength": 0.865, + "full_width_half_max": 0.033 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122043bb8e65e82fe9db82b59d003fe3cd5abfd32eeb5d21c044e8709ec7826d7653", + "file:size": 15663912, + "roles": [ + "data", + "reflectance" + ] + }, + "scl": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/SCL.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Scene classification map (SCL)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "122040b14acef6192d41b2004f19276fc84e00730d7c6e99e1ff99c31f369622a991", + "file:size": 654119, + "roles": [ + "data" + ] + }, + "aot": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/AOT.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Aerosol optical thickness (AOT)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "12206dc497288dda9b7b15f16ea5cbc856ae9f1f3a8cc75afa9553544c570d458808", + "file:size": 295446, + "roles": [ + "data" + ] + }, + "coastal": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/B01.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Coastal - 60m", + "eo:bands": [ + { + "name": "B01", + "common_name": "coastal", + "center_wavelength": 0.443, + "full_width_half_max": 0.027 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122022f01590c18979ad16ea9e0fd7769f4fc47ed3be91c0c94485a848c552ff0815", + "file:size": 1645337, + "roles": [ + "data", + "reflectance" + ] + }, + "nir09": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/B09.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 3 - 60m", + "eo:bands": [ + { + "name": "B09", + "common_name": "nir09", + "center_wavelength": 0.945, + "full_width_half_max": 0.026 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220017667b0f59e101e3a4fdaa0e993027e5b76385df3f0a9c036508b08ba462eb2", + "file:size": 1787870, + "roles": [ + "data", + "reflectance" + ] + }, + "cloud": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/CLD_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Cloud Probabilities", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "12207018bd02bd1c6c3028f2e7a0ed273ee893d2a6d66b01717f78e140ff922c54ba", + "file:size": 129061, + "roles": [ + "data", + "cloud" + ] + }, + "snow": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/SNW_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Snow Probabilities", + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "1220cf37dfb425a0ed350d2c1decee2f0717c93fe81cbedcd688740e9f480a36e4b3", + "file:size": 287930, + "roles": [ + "data", + "snow-ice" + ] + }, + "preview": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/L2A_PVI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color preview", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "file:checksum": "12205c0871058f0558da87f56616c62064015709e0671b8cc253b8e16697eef04c1e", + "file:size": 92206, + "roles": [ + "overview" + ] + }, + "granule_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/metadata.xml", + "type": "application/xml", + "file:checksum": "12203e40fc2f9820a8e3d15e0d57efec037fe3a58b5769dd3a38fa2c5407c77290cc", + "file:size": 192703, + "roles": [ + "metadata" + ] + }, + "tileinfo_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/tileInfo.json", + "type": "application/json", + "file:checksum": "122074a1b60165f2d707f12d760c51fea44d499615742e3453d59cac984c5554d777", + "file:size": 1513, + "roles": [ + "metadata" + ] + }, + "product_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/product_metadata.xml", + "type": "application/xml", + "file:checksum": "12201681ccfffc865eb207125eb505afe50892b124b6b870f555a4ff5f026ce1a5a7", + "file:size": 55223, + "roles": [ + "metadata" + ] + }, + "thumbnail": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/4/S2A_T13TDE_20240402T174230_L2A/L2A_PVI.jpg", + "type": "image/jpeg", + "title": "Thumbnail of preview image", + "file:checksum": "12208f6218e3fe646034545b64a9eac8bfaebfa378d4f0e3eeb0674b10291f909102", + "file:size": 15034, + "roles": [ + "thumbnail" + ] + } + }, + "bbox": [ + -105.35155, + 39.661084, + -104.884569, + 40.650834 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.1.0/schema.json", + "https://stac-extensions.github.io/file/v2.1.0/schema.json", + "https://stac-extensions.github.io/grid/v1.1.0/schema.json", + "https://stac-extensions.github.io/mgrs/v1.0.0/schema.json", + "https://stac-extensions.github.io/processing/v1.1.0/schema.json", + "https://stac-extensions.github.io/projection/v1.1.0/schema.json", + "https://stac-extensions.github.io/raster/v1.1.0/schema.json", + "https://stac-extensions.github.io/sentinel-2/v1.0.0/schema.json", + "https://stac-extensions.github.io/storage/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "collection": "sentinel-2-c1-l2a" + }, + { + "type": "Feature", + "stac_version": "1.0.0", + "id": "S2B_T13TDE_20240331T175111_L2A", + "properties": { + "created": "2024-04-01T00:08:38.369Z", + "platform": "sentinel-2b", + "constellation": "sentinel-2", + "instruments": [ + "msi" + ], + "eo:cloud_cover": 46.011618, + "proj:epsg": 32613, + "proj:centroid": { + "lat": 40.15442, + "lon": -105.53002 + }, + "mgrs:utm_zone": 13, + "mgrs:latitude_band": "T", + "mgrs:grid_square": "DE", + "grid:code": "MGRS-13TDE", + "view:azimuth": 233.69282425486853, + "view:incidence_angle": 3.6369564167355457, + "view:sun_azimuth": 154.09026456574, + "view:sun_elevation": 51.6621523205168, + "s2:tile_id": "S2B_OPER_MSI_L2A_TL_2BPS_20240331T214312_A036918_T13TDE_N05.10", + "s2:degraded_msi_data_percentage": 0.0818, + "s2:nodata_pixel_percentage": 0, + "s2:saturated_defective_pixel_percentage": 0, + "s2:dark_features_percentage": 0.562032, + "s2:cloud_shadow_percentage": 2.286685, + "s2:vegetation_percentage": 1.333768, + "s2:not_vegetated_percentage": 24.073228, + "s2:water_percentage": 0.574437, + "s2:unclassified_percentage": 2.004675, + "s2:medium_proba_clouds_percentage": 25.859308, + "s2:high_proba_clouds_percentage": 20.152313, + "s2:thin_cirrus_percentage": 0, + "s2:snow_ice_percentage": 23.153557, + "s2:product_type": "S2MSI2A", + "s2:processing_baseline": "05.10", + "s2:product_uri": "S2B_MSIL2A_20240331T174909_N0510_R141_T13TDE_20240331T214312.SAFE", + "s2:generation_time": "2024-03-31T21:43:12.000000Z", + "s2:datatake_id": "GS2B_20240331T174909_036918_N05.10", + "s2:datatake_type": "INS-NOBS", + "s2:datastrip_id": "S2B_OPER_MSI_L2A_DS_2BPS_20240331T214312_S20240331T175111_N05.10", + "s2:reflectance_conversion_factor": 1.00425614597814, + "datetime": "2024-03-31T18:02:54.659000Z", + "earthsearch:payload_id": "roda-sentinel-2-c1-l2a/workflow-sentinel-2-c1-l2a-to-stac/7f2ba77589ac144de202541a780be226", + "storage:platform": "AWS", + "storage:region": "us-west-2", + "storage:requester_pays": false, + "processing:software": { + "sentinel-2-c1-l2a-to-stac": "v2024.02.01" + }, + "updated": "2024-04-01T00:08:38.369Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -106.18316062292897, + 40.64478591807637 + ], + [ + -106.1661201925584, + 39.65576169772817 + ], + [ + -104.88623172845638, + 39.661560248682505 + ], + [ + -104.88456877606482, + 40.65078981397619 + ], + [ + -106.18316062292897, + 40.64478591807637 + ] + ] + ] + }, + "links": [ + { + "rel": "self", + "type": "application/geo+json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2B_T13TDE_20240331T175111_L2A" + }, + { + "rel": "canonical", + "href": "s3://e84-earth-search-sentinel-data/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/S2B_T13TDE_20240331T175111_L2A.json", + "type": "application/json" + }, + { + "rel": "via", + "href": "s3://sentinel-s2-l2a/tiles/13/T/DE/2024/3/31/0/metadata.xml", + "type": "application/xml", + "title": "Granule Metadata in Sinergize RODA Archive" + }, + { + "rel": "parent", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "collection", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a" + }, + { + "rel": "root", + "type": "application/json", + "href": "https://earth-search.aws.element84.com/v1" + }, + { + "rel": "thumbnail", + "href": "https://earth-search.aws.element84.com/v1/collections/sentinel-2-c1-l2a/items/S2B_T13TDE_20240331T175111_L2A/thumbnail" + } + ], + "assets": { + "red": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/B04.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red - 10m", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122035a1bc51ef056968d87faba369f88daebd2cfc4207edc748728688116af217e9", + "file:size": 228900065, + "roles": [ + "data", + "reflectance" + ] + }, + "green": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/B03.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Green - 10m", + "eo:bands": [ + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220981818ecc315f0cff2f3f7f00941f16c3b2b8bebed1a1a739c234de2f7185553", + "file:size": 229236548, + "roles": [ + "data", + "reflectance" + ] + }, + "blue": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/B02.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Blue - 10m", + "eo:bands": [ + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "122044669840133b6843c8b18ac9e81b65b22d300cd9af5a5d1d4cf2345ac377e736", + "file:size": 230279366, + "roles": [ + "data", + "reflectance" + ] + }, + "visual": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/TCI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color image", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "file:checksum": "12201c87628cf1f75d8b7e4a3dfc96b8ce1cae9f7ea61329ddfb9a106613b9a4456d", + "file:size": 170582980, + "roles": [ + "visual" + ] + }, + "nir": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/B08.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 1 - 10m", + "eo:bands": [ + { + "name": "B08", + "common_name": "nir", + "center_wavelength": 0.842, + "full_width_half_max": 0.145 + } + ], + "gsd": 10, + "proj:shape": [ + 10980, + 10980 + ], + "proj:transform": [ + 10, + 0, + 399960, + 0, + -10, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 10, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220a4420fb3d83d1511e2ff5e986f2e61d6a9b40db57065c4d1eb774101af01ee65", + "file:size": 225324186, + "roles": [ + "data", + "reflectance" + ] + }, + "swir22": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/B12.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 2.2μm - 20m", + "eo:bands": [ + { + "name": "B12", + "common_name": "swir22", + "center_wavelength": 2.19, + "full_width_half_max": 0.242 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220d78376833aec639d988b89cdcd5e0cd3d1a6d8a36e0049350b462672468712fc", + "file:size": 58684340, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge2": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/B06.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 2 - 20m", + "eo:bands": [ + { + "name": "B06", + "common_name": "rededge", + "center_wavelength": 0.74, + "full_width_half_max": 0.018 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220b5834ed4d67a0b20b42d1cac8fc70d237c546aa45c4d4d688261b6efe3345d75", + "file:size": 62762964, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge3": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/B07.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 3 - 20m", + "eo:bands": [ + { + "name": "B07", + "common_name": "rededge", + "center_wavelength": 0.783, + "full_width_half_max": 0.028 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12204bf693ed80ee960d8b5f88919917c2fd5fbf10ddb2a2924dc5ba9a9048bc75a0", + "file:size": 62603604, + "roles": [ + "data", + "reflectance" + ] + }, + "rededge1": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/B05.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Red Edge 1 - 20m", + "eo:bands": [ + { + "name": "B05", + "common_name": "rededge", + "center_wavelength": 0.704, + "full_width_half_max": 0.019 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220dcc344c598f38830f46f4843e919cd7db61515359ad4ba549c652012767a1b96", + "file:size": 62970496, + "roles": [ + "data", + "reflectance" + ] + }, + "swir16": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/B11.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "SWIR 1.6μm - 20m", + "eo:bands": [ + { + "name": "B11", + "common_name": "swir16", + "center_wavelength": 1.61, + "full_width_half_max": 0.143 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12207f1871ddeb17fcba739001f8196a56703537b39d1494dca8216bc42543d254e8", + "file:size": 58812992, + "roles": [ + "data", + "reflectance" + ] + }, + "wvp": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/WVP.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Water Vapour (WVP)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "unit": "cm", + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "12206e5f0819853d5a26999afcfc18bed9c8f201ee33d41d0eee38cd1095c8606409", + "file:size": 26524391, + "roles": [ + "data" + ] + }, + "nir08": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/B8A.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 2 - 20m", + "eo:bands": [ + { + "name": "B8A", + "common_name": "nir08", + "center_wavelength": 0.865, + "full_width_half_max": 0.033 + } + ], + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "12203d75053f7b42e382df27a0c0bae5c137a1d704bf0e6df85f0d5b00150bcdec1b", + "file:size": 62391131, + "roles": [ + "data", + "reflectance" + ] + }, + "scl": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/SCL.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Scene classification map (SCL)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "122004aa44450f8a3948ea7d541807fb7e6c2929033ca2215789a0713cf737f113d4", + "file:size": 2785404, + "roles": [ + "data" + ] + }, + "aot": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/AOT.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Aerosol optical thickness (AOT)", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 20, + "scale": 0.001, + "offset": 0 + } + ], + "file:checksum": "12206a8be9f1180173d8e0ec6f2fbdd41187e2f2811e7e923221bdde2c7c979b1944", + "file:size": 1679633, + "roles": [ + "data" + ] + }, + "coastal": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/B01.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Coastal - 60m", + "eo:bands": [ + { + "name": "B01", + "common_name": "coastal", + "center_wavelength": 0.443, + "full_width_half_max": 0.027 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220ea861c524ef5df28f851db0fc10dc8d0159a0e853a00b4c4c54a258817c1bf54", + "file:size": 7139971, + "roles": [ + "data", + "reflectance" + ] + }, + "nir09": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/B09.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "NIR 3 - 60m", + "eo:bands": [ + { + "name": "B09", + "common_name": "nir09", + "center_wavelength": 0.945, + "full_width_half_max": 0.026 + } + ], + "gsd": 60, + "proj:shape": [ + 1830, + 1830 + ], + "proj:transform": [ + 60, + 0, + 399960, + 0, + -60, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint16", + "spatial_resolution": 60, + "scale": 0.0001, + "offset": -0.1 + } + ], + "file:checksum": "1220c3f449596e4cd29ec2b5e96266e1fa5b0b3470c8bc36155aa0a33858b7e2faa1", + "file:size": 7223382, + "roles": [ + "data", + "reflectance" + ] + }, + "cloud": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/CLD_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Cloud Probabilities", + "gsd": 20, + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "12200456cc4fc0077686847809c6debe77e3f333639d8270b25871ccd31080774500", + "file:size": 4294768, + "roles": [ + "data", + "cloud" + ] + }, + "snow": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/SNW_20m.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "Snow Probabilities", + "proj:shape": [ + 5490, + 5490 + ], + "proj:transform": [ + 20, + 0, + 399960, + 0, + -20, + 4500000 + ], + "raster:bands": [ + { + "nodata": 0, + "data_type": "uint8", + "spatial_resolution": 20 + } + ], + "file:checksum": "12206b98d63cbfbb89e4f822a155d684fa02cf345fc36e3b94883207e653e9e311b3", + "file:size": 4164287, + "roles": [ + "data", + "snow-ice" + ] + }, + "preview": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/L2A_PVI.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "True color preview", + "eo:bands": [ + { + "name": "B04", + "common_name": "red", + "center_wavelength": 0.665, + "full_width_half_max": 0.038 + }, + { + "name": "B03", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.045 + }, + { + "name": "B02", + "common_name": "blue", + "center_wavelength": 0.49, + "full_width_half_max": 0.098 + } + ], + "file:checksum": "12202b3bb6932e112d41204410d0270eff371f40a72d76122abda1008a8d739f307a", + "file:size": 189049, + "roles": [ + "overview" + ] + }, + "granule_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/metadata.xml", + "type": "application/xml", + "file:checksum": "12200efae888c31465c451fe79836bd17c59717b96d2ba70eef3c9637da594ff889a", + "file:size": 626609, + "roles": [ + "metadata" + ] + }, + "tileinfo_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/tileInfo.json", + "type": "application/json", + "file:checksum": "1220f77ad0a7b19b71d81edf6ab3680965ba6bb0c2d6e1a276e08e275af24b75715f", + "file:size": 1491, + "roles": [ + "metadata" + ] + }, + "product_metadata": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/product_metadata.xml", + "type": "application/xml", + "file:checksum": "12200d997315de64a81a7335ea90bb70383fb53a64ff076132d07772e146f2743a6d", + "file:size": 54347, + "roles": [ + "metadata" + ] + }, + "thumbnail": { + "href": "https://e84-earth-search-sentinel-data.s3.us-west-2.amazonaws.com/sentinel-2-c1-l2a/13/T/DE/2024/3/S2B_T13TDE_20240331T175111_L2A/L2A_PVI.jpg", + "type": "image/jpeg", + "title": "Thumbnail of preview image", + "file:checksum": "1220178285661998e10a875fccd731acd4e81586579c06345c7cddef260bce1e7ce1", + "file:size": 37057, + "roles": [ + "thumbnail" + ] + } + }, + "bbox": [ + -106.183161, + 39.655762, + -104.884569, + 40.65079 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.1.0/schema.json", + "https://stac-extensions.github.io/file/v2.1.0/schema.json", + "https://stac-extensions.github.io/grid/v1.1.0/schema.json", + "https://stac-extensions.github.io/mgrs/v1.0.0/schema.json", + "https://stac-extensions.github.io/processing/v1.1.0/schema.json", + "https://stac-extensions.github.io/projection/v1.1.0/schema.json", + "https://stac-extensions.github.io/raster/v1.1.0/schema.json", + "https://stac-extensions.github.io/sentinel-2/v1.0.0/schema.json", + "https://stac-extensions.github.io/storage/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "collection": "sentinel-2-c1-l2a" + } + ], + "links": [], + "numberReturned": 10 +} diff --git a/stac-server/src/api.rs b/stac-server/src/api.rs new file mode 100644 index 00000000..7ae8265c --- /dev/null +++ b/stac-server/src/api.rs @@ -0,0 +1,730 @@ +use crate::{Backend, Error, Result, APPLICATION_OPENAPI_3_0, DEFAULT_DESCRIPTION, DEFAULT_ID}; +use http::Method; +use serde::Serialize; +use serde_json::{Map, Value}; +use stac::{Catalog, Collection, Fields, Item, Link, Links}; +use stac_api::{Collections, Conformance, ItemCollection, Items, Root, Search}; +use url::Url; + +/// A STAC server API. +#[derive(Clone, Debug)] +pub struct Api { + /// The backend storage for this API. + pub backend: B, + + /// The text description of this API. + pub description: String, + + /// The catalog id of this API. + pub id: String, + + /// The root url of this API. + pub root: Url, +} + +impl Api { + /// Creates a new API with the given backend. + /// + /// # Examples + /// + /// ``` + /// use stac_server::{Api, MemoryBackend}; + /// + /// let backend = MemoryBackend::new(); + /// let api = Api::new(backend, "http://stac.test").unwrap(); + /// ``` + pub fn new(backend: B, root: &str) -> Result> { + Ok(Api { + backend, + id: DEFAULT_ID.to_string(), + description: DEFAULT_DESCRIPTION.to_string(), + root: root.parse()?, + }) + } + + /// Sets this API's id. + /// + /// # Examples + /// + /// ``` + /// use stac_server::{Api, MemoryBackend}; + /// + /// let backend = MemoryBackend::new(); + /// let api = Api::new(backend, "http://stac.test").unwrap().id("an-id"); + /// ``` + pub fn id(mut self, id: impl ToString) -> Api { + self.id = id.to_string(); + self + } + + /// Sets this API's description. + /// + /// # Examples + /// + /// ``` + /// use stac_server::{Api, MemoryBackend}; + /// + /// let backend = MemoryBackend::new(); + /// let api = Api::new(backend, "http://stac.test").unwrap().description("a description"); + /// ``` + pub fn description(mut self, description: impl ToString) -> Api { + self.description = description.to_string(); + self + } + + fn url(&self, path: &str) -> Result { + self.root.join(path).map_err(Error::from) + } + + /// Returns the root of the API. + /// + /// # Examples + /// + /// ``` + /// use stac_server::{Api, MemoryBackend}; + /// + /// let api = Api::new(MemoryBackend::new(), "http://stac.test").unwrap(); + /// # tokio_test::block_on(async { + /// let root = api.root().await.unwrap(); + /// # }) + /// ``` + pub async fn root(&self) -> Result { + let mut catalog = Catalog::new(&self.id, &self.description); + catalog.set_link(Link::root(&self.root).json()); + catalog.set_link(Link::self_(&self.root).json()); + catalog.set_link( + Link::new(self.url("/api")?, "service-desc") + .r#type(APPLICATION_OPENAPI_3_0.to_string()), + ); + catalog.set_link( + Link::new(self.url("/api.html")?, "service-doc").r#type("text/html".to_string()), + ); + catalog.set_link(Link::new(self.url("/conformance")?, "conformance").json()); + catalog.set_link(Link::new(self.url("/collections")?, "data").json()); + for collection in self.backend.collections().await? { + catalog + .links + .push(Link::child(self.url(&format!("/collections/{}", collection.id))?).json()); + } + let search_url = self.url("/search")?; + catalog + .links + .push(Link::new(&search_url, "search").geojson().method("GET")); + catalog + .links + .push(Link::new(search_url, "search").geojson().method("POST")); + Ok(Root { + catalog, + conformance: self.conformance(), + }) + } + + /// Returns the conformance classes. + /// + /// # Examples + /// + /// ``` + /// use stac_server::{Api, MemoryBackend}; + /// + /// let api = Api::new(MemoryBackend::new(), "http://stac.test").unwrap(); + /// let conformance = api.conformance(); + /// ``` + pub fn conformance(&self) -> Conformance { + let mut conformance = Conformance::new().ogcapi_features(); + if self.backend.has_item_search() { + conformance = conformance.item_search(); + } + conformance + } + + /// Returns the collections from the backend. + /// + /// # Examples + /// + /// ``` + /// use stac_server::{Api, MemoryBackend}; + /// + /// let api = Api::new(MemoryBackend::new(), "http://stac.test").unwrap(); + /// # tokio_test::block_on(async { + /// let collections = api.collections().await.unwrap(); + /// # }) + /// ``` + pub async fn collections(&self) -> Result { + let mut collections: Collections = self.backend.collections().await?.into(); + collections.set_link(Link::root(&self.root).json()); + collections.set_link(Link::self_(self.url("/collections")?).json()); + for mut collection in collections.collections.iter_mut() { + self.set_collection_links(&mut collection)?; + } + Ok(collections) + } + + /// Returns the collections from the backend. + /// + /// # Examples + /// + /// ``` + /// use stac_server::{Api, MemoryBackend, Backend}; + /// use stac::Collection; + /// + /// let mut backend = MemoryBackend::new(); + /// # tokio_test::block_on(async { + /// backend.add_collection(Collection::new("an-id", "a description")).await.unwrap(); + /// let api = Api::new(backend, "http://stac.test").unwrap(); + /// let collection = api.collection("an-id").await.unwrap().unwrap(); + /// # }) + /// ``` + pub async fn collection(&self, id: &str) -> Result> { + if let Some(mut collection) = self.backend.collection(id).await? { + self.set_collection_links(&mut collection)?; + Ok(Some(collection)) + } else { + Ok(None) + } + } + + /// Returns all items for a given collection. + /// + /// # Examples + /// + /// ``` + /// use stac_server::{Api, MemoryBackend, Backend}; + /// use stac::{Collection, Item}; + /// use stac_api::Items; + /// + /// let mut backend = MemoryBackend::new(); + /// # tokio_test::block_on(async { + /// backend.add_collection(Collection::new("collection-id", "a description")).await.unwrap(); + /// backend.add_item(Item::new("item-id").collection("collection-id")).await.unwrap(); + /// let api = Api::new(backend, "http://stac.test").unwrap(); + /// let items = api.items("collection-id", Items::default()).await.unwrap().unwrap(); + /// assert_eq!(items.items.len(), 1); + /// # }) + /// ``` + pub async fn items(&self, collection_id: &str, items: Items) -> Result> { + if let Some(mut item_collection) = self.backend.items(collection_id, items.clone()).await? { + let collection_url = self.url(&format!("/collections/{}", collection_id))?; + let items_url = self.url(&format!("/collections/{}/items", collection_id))?; + item_collection.set_link(Link::root(&self.root).json()); + item_collection.set_link(Link::self_(items_url.clone()).geojson()); + item_collection.set_link(Link::collection(&collection_url).json()); + if let Some(next) = item_collection.next.take() { + item_collection.set_link(self.pagination_link( + items_url.clone(), + items.clone(), + next, + "next", + &Method::GET, + )?); + } + if let Some(prev) = item_collection.prev.take() { + item_collection.set_link(self.pagination_link( + items_url, + items, + prev, + "prev", + &Method::GET, + )?); + } + for mut item in item_collection.items.iter_mut() { + self.set_item_links(&mut item)?; + } + Ok(Some(item_collection)) + } else { + Ok(None) + } + } + + /// Returns an item. + /// + /// # Examples + /// + /// ``` + /// use stac_server::{Api, MemoryBackend, Backend}; + /// use stac::{Collection, Item}; + /// use stac_api::Items; + /// + /// let mut backend = MemoryBackend::new(); + /// # tokio_test::block_on(async { + /// backend.add_collection(Collection::new("collection-id", "a description")).await.unwrap(); + /// backend.add_item(Item::new("item-id").collection("collection-id")).await.unwrap(); + /// let api = Api::new(backend, "http://stac.test").unwrap(); + /// let item = api.item("collection-id", "item-id").await.unwrap().unwrap(); + /// # }) + /// ``` + pub async fn item(&self, collection_id: &str, item_id: &str) -> Result> { + if let Some(mut item) = self.backend.item(collection_id, item_id).await? { + item.set_link(Link::root(&self.root).json()); + item.set_link( + Link::self_( + self.url(&format!("/collections/{}/items/{}", collection_id, item_id))?, + ) + .geojson(), + ); + let collection_url = self.url(&format!("/collections/{}", collection_id))?; + item.set_link(Link::collection(collection_url.clone()).json()); + item.set_link(Link::parent(collection_url).json()); + Ok(Some(item)) + } else { + Ok(None) + } + } + + /// Searches the API. + /// + /// # Examples + /// + /// ``` + /// use stac_api::Search; + /// use stac_server::{Api, MemoryBackend, Backend}; + /// use http::Method; + /// + /// let api = Api::new(MemoryBackend::new(), "http://stac.test").unwrap(); + /// # tokio_test::block_on(async { + /// let item_collection = api.search(Search::default(), Method::GET).await.unwrap(); + /// # }) + /// ``` + pub async fn search(&self, search: Search, method: Method) -> Result { + let mut item_collection = self.backend.search(search.clone()).await?; + item_collection.set_link(Link::root(&self.root).json()); + let search_url = self.url("/search")?; + if let Some(next) = item_collection.next.take() { + item_collection.set_link(self.pagination_link( + search_url.clone(), + search.clone(), + next, + "next", + &method, + )?); + } + if let Some(prev) = item_collection.prev.take() { + item_collection + .set_link(self.pagination_link(search_url, search, prev, "prev", &method)?); + } + for mut item in item_collection.items.iter_mut() { + self.set_item_links(&mut item)?; + } + Ok(item_collection) + } + + fn set_collection_links(&self, collection: &mut Collection) -> Result<()> { + collection.set_link(Link::root(&self.root).json()); + collection + .set_link(Link::self_(self.url(&format!("/collections/{}", collection.id))?).json()); + collection.set_link(Link::parent(&self.root).json()); + collection.set_link( + Link::new( + self.url(&format!("/collections/{}/items", collection.id))?, + "items", + ) + .geojson(), + ); + Ok(()) + } + + fn pagination_link( + &self, + mut url: Url, + mut data: D, + pagination: Map, + rel: &str, + method: &Method, + ) -> Result + where + D: Fields + Serialize, + { + for (key, value) in pagination { + let _ = data.set_field(key, value)?; + } + match *method { + Method::GET => { + url.set_query(Some(&serde_urlencoded::to_string(data)?)); + Ok(Link::new(url, rel).geojson().method("GET")) + } + Method::POST => Ok(Link::new(url, rel).geojson().method("POST").body(data)?), + _ => unimplemented!(), + } + } + + fn set_item_links(&self, item: &mut stac_api::Item) -> Result<()> { + let mut collection_url = None; + let mut item_link = None; + if let Some(item_id) = item.get("id").and_then(|id| id.as_str()) { + if let Some(collection_id) = item.get("collection").and_then(|id| id.as_str()) { + collection_url = Some(self.url(&format!("/collections/{}", collection_id))?); + item_link = Some(serde_json::to_value( + Link::self_( + self.url(&format!("/collections/{}/items/{}", collection_id, item_id))?, + ) + .geojson(), + )?); + } + } + if item + .get("links") + .map(|links| !links.is_array()) + .unwrap_or(true) + { + let _ = item.insert("links".to_string(), Value::Array(Vec::new())); + } + let links = item.get_mut("links").unwrap().as_array_mut().unwrap(); + links.push(serde_json::to_value(Link::root(&self.root).json())?); + if let Some(item_link) = item_link { + links.push(item_link); + } + if let Some(collection_url) = collection_url { + links.push(serde_json::to_value( + Link::collection(&collection_url).json(), + )?); + links.push(serde_json::to_value(Link::parent(&collection_url).json())?); + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::Api; + use crate::{Backend, MemoryBackend}; + use http::Method; + use stac::{Catalog, Collection, Item, Links}; + use stac_api::{Items, Search, ITEM_SEARCH_URI}; + use stac_validate::Validate; + use std::collections::HashSet; + + macro_rules! assert_link { + ($link:expr, $href:expr, $media_type:expr) => { + let link = $link.unwrap(); + assert_eq!(link.href, $href); + assert_eq!(link.r#type.as_ref().unwrap(), $media_type); + }; + } + + fn test_api(backend: MemoryBackend) -> Api { + Api::new(backend, "http://stac.test/") + .unwrap() + .id("an-id") + .description("a description") + } + + #[tokio::test] + async fn root() { + let mut backend = MemoryBackend::new(); + backend + .add_collection(Collection::new("a-collection", "A description")) + .await + .unwrap(); + let api = test_api(backend); + let root = api.root().await.unwrap(); + assert!(!root.conformance.conforms_to.is_empty()); + let catalog: Catalog = serde_json::from_value(serde_json::to_value(root).unwrap()).unwrap(); + catalog.validate().unwrap(); + assert_eq!(catalog.id, "an-id"); + assert_eq!(catalog.description, "a description"); + assert_link!( + catalog.link("root"), + "http://stac.test/", + "application/json" + ); + assert_link!( + catalog.link("self"), + "http://stac.test/", + "application/json" + ); + assert_link!( + catalog.link("service-desc"), + "http://stac.test/api", + "application/vnd.oai.openapi+json;version=3.0" + ); + assert_link!( + catalog.link("service-doc"), + "http://stac.test/api.html", + "text/html" + ); + assert_link!( + catalog.link("conformance"), + "http://stac.test/conformance", + "application/json" + ); + assert_link!( + catalog.link("data"), + "http://stac.test/collections", + "application/json" + ); + let mut methods = HashSet::new(); + let search_links = catalog.links.iter().filter(|link| link.rel == "search"); + for link in search_links { + assert_eq!(link.href, "http://stac.test/search"); + assert_eq!(link.r#type.as_deref().unwrap(), "application/geo+json"); + let _ = methods.insert(link.method.as_deref().unwrap()); + } + assert_eq!(methods.len(), 2); + assert!(methods.contains("GET")); + assert!(methods.contains("POST")); + + let children: Vec<_> = catalog.iter_child_links().collect(); + assert_eq!(children.len(), 1); + let child = children[0]; + assert_eq!(child.href, "http://stac.test/collections/a-collection"); + assert_eq!(child.r#type.as_ref().unwrap(), "application/json"); + } + + #[tokio::test] + async fn conformance() { + let api = test_api(MemoryBackend::new()); + let conformance = api.conformance(); + for conformance_class in [ + "https://api.stacspec.org/v1.0.0/core", + "https://api.stacspec.org/v1.0.0/ogcapi-features", + "https://api.stacspec.org/v1.0.0/collections", + "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/geojson", + "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/core", + ] { + assert!( + conformance + .conforms_to + .contains(&conformance_class.to_string()), + "{} not in the conforms_to list", + conformance_class + ); + } + } + + #[tokio::test] + async fn collections() { + let mut backend = MemoryBackend::new(); + backend + .add_collection(Collection::new("a-collection", "A description")) + .await + .unwrap(); + let api = test_api(backend); + let collections = api.collections().await.unwrap(); + assert_link!( + collections.link("root"), + "http://stac.test/", + "application/json" + ); + assert_link!( + collections.link("self"), + "http://stac.test/collections", + "application/json" + ); + assert_eq!(collections.collections.len(), 1); + let collection = &collections.collections[0]; + collection.validate().unwrap(); + assert_link!( + collection.link("root"), + "http://stac.test/", + "application/json" + ); + assert_link!( + collection.link("self"), + "http://stac.test/collections/a-collection", + "application/json" + ); + assert_link!( + collection.link("parent"), + "http://stac.test/", + "application/json" + ); + assert_link!( + collection.link("items"), + "http://stac.test/collections/a-collection/items", + "application/geo+json" + ); + } + + #[tokio::test] + async fn collection() { + let mut backend = MemoryBackend::new(); + backend + .add_collection(Collection::new("a-collection", "A description")) + .await + .unwrap(); + let api = test_api(backend); + let collection = api.collection("a-collection").await.unwrap().unwrap(); + collection.validate().unwrap(); + assert_link!( + collection.link("root"), + "http://stac.test/", + "application/json" + ); + assert_link!( + collection.link("self"), + "http://stac.test/collections/a-collection", + "application/json" + ); + assert_link!( + collection.link("parent"), + "http://stac.test/", + "application/json" + ); + assert_link!( + collection.link("items"), + "http://stac.test/collections/a-collection/items", + "application/geo+json" + ); + } + + #[tokio::test] + async fn items() { + let mut backend = MemoryBackend::new(); + let api = test_api(backend.clone()); + assert!(api + .items("collection-id", Items::default()) + .await + .unwrap() + .is_none()); + + backend + .add_collection(Collection::new("collection-id", "a description")) + .await + .unwrap(); + backend + .add_item(Item::new("item-a").collection("collection-id")) + .await + .unwrap(); + let items = api + .items("collection-id", Items::default()) + .await + .unwrap() + .unwrap(); + assert_link!(items.link("root"), "http://stac.test/", "application/json"); + assert_link!( + items.link("self"), + "http://stac.test/collections/collection-id/items", + "application/geo+json" + ); + assert_link!( + items.link("collection"), + "http://stac.test/collections/collection-id", + "application/json" + ); + assert_eq!(items.items.len(), 1); + let item: Item = items.items[0].clone().try_into().unwrap(); + assert_link!(item.link("root"), "http://stac.test/", "application/json"); + assert_link!( + item.link("self"), + "http://stac.test/collections/collection-id/items/item-a", + "application/geo+json" + ); + assert_link!( + item.link("collection"), + "http://stac.test/collections/collection-id", + "application/json" + ); + assert_link!( + item.link("parent"), + "http://stac.test/collections/collection-id", + "application/json" + ); + } + + #[tokio::test] + async fn items_pagination() { + let mut backend = MemoryBackend::new(); + backend + .add_collection(Collection::new("collection-id", "a description")) + .await + .unwrap(); + backend + .add_item(Item::new("item-a").collection("collection-id")) + .await + .unwrap(); + backend + .add_item(Item::new("item-b").collection("collection-id")) + .await + .unwrap(); + let api = test_api(backend); + let items = Items { + limit: Some(1), + ..Default::default() + }; + let items = api.items("collection-id", items).await.unwrap().unwrap(); + assert_eq!(items.items.len(), 1); + assert_link!( + items.link("next"), + "http://stac.test/collections/collection-id/items?limit=1&skip=1", + "application/geo+json" + ); + + let mut items = Items { + limit: Some(1), + ..Default::default() + }; + let _ = items + .additional_fields + .insert("skip".to_string(), "1".into()); + let items = api.items("collection-id", items).await.unwrap().unwrap(); + assert_eq!(items.items.len(), 1); + assert_link!( + items.link("prev"), + "http://stac.test/collections/collection-id/items?limit=1&skip=0", + "application/geo+json" + ); + } + + #[tokio::test] + async fn item() { + let mut backend = MemoryBackend::new(); + let api = test_api(backend.clone()); + assert!(api + .item("collection-id", "item-id") + .await + .unwrap() + .is_none()); + + backend + .add_collection(Collection::new("collection-id", "a description")) + .await + .unwrap(); + backend + .add_item(Item::new("item-id").collection("collection-id")) + .await + .unwrap(); + let item = api.item("collection-id", "item-id").await.unwrap().unwrap(); + assert_link!(item.link("root"), "http://stac.test/", "application/json"); + assert_link!( + item.link("self"), + "http://stac.test/collections/collection-id/items/item-id", + "application/geo+json" + ); + assert_link!( + item.link("collection"), + "http://stac.test/collections/collection-id", + "application/json" + ); + assert_link!( + item.link("parent"), + "http://stac.test/collections/collection-id", + "application/json" + ); + } + + #[tokio::test] + async fn search() { + let api = test_api(MemoryBackend::new()); + let item_collection = api.search(Search::default(), Method::GET).await.unwrap(); + assert!(item_collection.items.is_empty()); + assert_link!( + item_collection.link("root"), + "http://stac.test/", + "application/json" + ); + } + + #[test] + fn memory_item_search_conformance() { + let api = test_api(MemoryBackend::new()); + let conformance = api.conformance(); + if cfg!(feature = "memory-item-search") { + assert!(conformance + .conforms_to + .contains(&ITEM_SEARCH_URI.to_string())); + } else { + assert!(!conformance + .conforms_to + .contains(&ITEM_SEARCH_URI.to_string())); + } + } +} diff --git a/stac-server/src/backend/memory.rs b/stac-server/src/backend/memory.rs new file mode 100644 index 00000000..07920729 --- /dev/null +++ b/stac-server/src/backend/memory.rs @@ -0,0 +1,144 @@ +use crate::{Backend, Error, Result, DEFAULT_LIMIT}; +use async_trait::async_trait; +use serde_json::Map; +use stac::{Collection, Item}; +use stac_api::{ItemCollection, Items, Search}; +use std::{ + collections::{BTreeMap, HashMap}, + sync::{Arc, RwLock}, +}; + +/// A naive backend that stores collections and items in memory. +/// +/// This backend is meant to be used for testing and toy servers, not for production. +#[derive(Clone, Debug)] +pub struct MemoryBackend { + collections: Arc>>, + items: Arc>>>, +} + +impl MemoryBackend { + /// Creates a new memory backend. + /// + /// # Examples + /// + /// ``` + /// use stac_server::MemoryBackend; + /// let backend = MemoryBackend::new(); + /// ``` + pub fn new() -> MemoryBackend { + MemoryBackend { + collections: Arc::new(RwLock::new(BTreeMap::new())), + items: Arc::new(RwLock::new(HashMap::new())), + } + } +} + +#[async_trait] +impl Backend for MemoryBackend { + fn has_item_search(&self) -> bool { + cfg!(feature = "memory-item-search") + } + + async fn collections(&self) -> Result> { + let collections = self.collections.read().unwrap(); + Ok(collections.values().cloned().collect()) + } + + async fn collection(&self, id: &str) -> Result> { + let collections = self.collections.read().unwrap(); + Ok(collections.get(id).cloned()) + } + + async fn add_collection(&mut self, collection: Collection) -> Result<()> { + let mut collections = self.collections.write().unwrap(); + let _ = collections.insert(collection.id.clone(), collection); + Ok(()) + } + + async fn add_item(&mut self, item: Item) -> Result<()> { + if let Some(collection_id) = item.collection.clone() { + if self.collection(&collection_id).await?.is_none() { + Err(Error::MemoryBackend(format!( + "no collection with id='{}'", + collection_id + ))) + } else { + let mut items = self.items.write().unwrap(); + items.entry(collection_id).or_default().push(item); + Ok(()) + } + } else { + Err(Error::MemoryBackend(format!( + "collection not set on item: {}", + item.id + ))) + } + } + + async fn items(&self, collection_id: &str, items: Items) -> Result> { + { + let collections = self.collections.read().unwrap(); + if !collections.contains_key(collection_id) { + return Ok(None); + } + }; + let search = items.into_search(collection_id); + self.search(search).await.map(Some) + } + + async fn item(&self, collection_id: &str, item_id: &str) -> Result> { + let items = self.items.read().unwrap(); + Ok(items.get(collection_id).and_then(|items| { + items + .iter() + .find(|item| item.id == item_id) + .map(|item| item.clone()) + })) + } + + async fn search(&self, mut search: Search) -> Result { + let items = self.items.read().unwrap(); + if search.collections.is_none() { + search.collections = Some(items.keys().cloned().collect()); + } + let mut item_references = Vec::new(); + for collection in search.collections.as_ref().unwrap() { + if let Some(items) = items.get(collection) { + item_references.extend( + items + .iter() + .filter(|item| search.matches(item).unwrap_or_default()), + ); + } + } + let limit = search.limit.unwrap_or(DEFAULT_LIMIT).try_into()?; + let skip = search + .additional_fields + .get("skip") + .and_then(|skip| skip.as_str()) + .and_then(|skip| skip.parse::().ok()) + .unwrap_or_default() + .try_into()?; + let len = item_references.len(); + let items = item_references + .into_iter() + .skip(skip) + .take(limit) + .map(|item| stac_api::Item::try_from(item.clone()).map_err(Error::from)) + .collect::>>()?; + let mut item_collection = ItemCollection::new(items)?; + if len > item_collection.items.len() + skip { + let mut next = Map::new(); + let _ = next.insert("skip".to_string(), (skip + limit).into()); + item_collection.next = Some(next); + } + if skip > 0 { + let mut prev = Map::new(); + let skip = if skip > limit { skip - limit } else { 0 }; + let _ = prev.insert("skip".to_string(), skip.into()); + item_collection.prev = Some(prev); + } + Ok(item_collection) + } +} diff --git a/stac-server/src/backend/mod.rs b/stac-server/src/backend/mod.rs new file mode 100644 index 00000000..d6ec2de6 --- /dev/null +++ b/stac-server/src/backend/mod.rs @@ -0,0 +1,180 @@ +mod memory; +#[cfg(feature = "pgstac")] +mod pgstac; + +use crate::{Error, Result}; +use async_trait::async_trait; +pub use memory::MemoryBackend; +#[cfg(feature = "pgstac")] +pub use pgstac::PgstacBackend; +use stac::{Collection, Item, Value}; +use stac_api::{ItemCollection, Items, Search}; + +/// Storage backend for a STAC API. +#[async_trait] +pub trait Backend: Clone + Sync + Send + 'static { + /// Returns true if this backend has item search capabilities. + /// + /// # Examples + /// + /// ``` + /// use stac_server::{MemoryBackend, Backend}; + /// + /// assert_eq!(MemoryBackend::new().has_item_search(), cfg!(feature = "memory-item-search")); + /// ``` + fn has_item_search(&self) -> bool; + + /// Adds collections and items from hrefs. + /// + /// A default implementation is provided. + /// + /// # Examples + /// + /// ``` + /// use stac_server::{MemoryBackend, Backend}; + /// let mut backend = MemoryBackend::new(); + /// # tokio_test::block_on(async { + /// backend.add_from_hrefs(&[ + /// "tests/data/collection.json".to_string(), + /// "tests/data/feature.geojson".to_string(), + /// ]); + /// # }) + /// ``` + async fn add_from_hrefs(&mut self, hrefs: &[String]) -> Result<()> { + let mut items = Vec::new(); + for href in hrefs { + let value: Value = stac_async::read(href).await?; + match value { + Value::Item(item) => items.push(item), + Value::Catalog(catalog) => { + return Err(Error::Backend(format!( + "cannot add catalog with id={} to the backend", + catalog.id + ))) + } + Value::Collection(collection) => self.add_collection(collection).await?, + Value::ItemCollection(item_collection) => { + items.extend(item_collection.items.into_iter()) + } + } + } + for item in items { + self.add_item(item).await?; + } + Ok(()) + } + + /// Returns all collections. + /// + /// # Examples + /// + /// ``` + /// use stac_server::{MemoryBackend, Backend}; + /// let backend = MemoryBackend::new(); + /// # tokio_test::block_on(async { + /// let collections = backend.collections().await.unwrap(); + /// assert!(collections.is_empty()); + /// # }) + /// ``` + async fn collections(&self) -> Result>; + + /// Returns a single collection. + /// + /// # Examples + /// + /// ``` + /// use stac_server::{MemoryBackend, Backend}; + /// let backend = MemoryBackend::new(); + /// # tokio_test::block_on(async { + /// let collection = backend.collection("does-not-exist").await.unwrap(); + /// assert!(collection.is_none()); + /// # }) + /// ``` + async fn collection(&self, id: &str) -> Result>; + + /// Adds a collection. + /// + /// # Examples + /// + /// ``` + /// use stac::Collection; + /// use stac_server::{MemoryBackend, Backend}; + /// + /// let mut backend = MemoryBackend::new(); + /// # tokio_test::block_on(async { + /// backend.add_collection(Collection::new("an-id", "a description")).await.unwrap(); + /// # }) + /// ``` + async fn add_collection(&mut self, collection: Collection) -> Result<()>; + + /// Adds an item. + /// + /// If the item doesn't have its `collection` field set, or a collection + /// with that id does not exist in the backend, throws an error. + /// + /// # Examples + /// + /// ``` + /// use stac::{Collection, Item}; + /// use stac_server::{MemoryBackend, Backend}; + /// + /// let mut backend = MemoryBackend::new(); + /// # tokio_test::block_on(async { + /// assert!(backend.add_item(Item::new("item-id")).await.is_err()); + /// + /// backend.add_collection(Collection::new("collection-id", "a description")).await.unwrap(); + /// backend.add_item(Item::new("item-id").collection("collection-id")).await.unwrap(); + /// # }) + /// ``` + async fn add_item(&mut self, item: Item) -> Result<()>; + + /// Retrieves items for a given collection. + /// + /// # Examples + /// + /// ``` + /// use stac::{Collection, Item}; + /// use stac_api::Items; + /// use stac_server::{MemoryBackend, Backend}; + /// + /// let mut backend = MemoryBackend::new(); + /// # tokio_test::block_on(async { + /// backend.add_collection(Collection::new("collection-id", "a description")).await.unwrap(); + /// backend.add_item(Item::new("item-id").collection("collection-id")).await.unwrap(); + /// let items = backend.items("collection-id", Items::default()).await.unwrap(); + /// # }) + /// ``` + async fn items(&self, collection_id: &str, items: Items) -> Result>; + + /// Retrieves an item from a collection. + /// + /// # Examples + /// + /// ``` + /// use stac::{Collection, Item}; + /// use stac_server::{MemoryBackend, Backend}; + /// + /// let mut backend = MemoryBackend::new(); + /// # tokio_test::block_on(async { + /// backend.add_collection(Collection::new("collection-id", "a description")).await.unwrap(); + /// backend.add_item(Item::new("item-id").collection("collection-id")).await.unwrap(); + /// let item = backend.item("collection-id", "item-id").await.unwrap().unwrap(); + /// # }) + /// ``` + async fn item(&self, collection_id: &str, item_id: &str) -> Result>; + + /// Searches a backend. + /// + /// # Examples + /// + /// ``` + /// use stac_api::Search; + /// use stac_server::{MemoryBackend, Backend}; + /// + /// let mut backend = MemoryBackend::new(); + /// # tokio_test::block_on(async { + /// let item_collection = backend.search(Search::default()).await.unwrap(); + /// # }) + /// ``` + async fn search(&self, search: Search) -> Result; +} diff --git a/stac-server/src/backend/pgstac.rs b/stac-server/src/backend/pgstac.rs new file mode 100644 index 00000000..be5b6f63 --- /dev/null +++ b/stac-server/src/backend/pgstac.rs @@ -0,0 +1,104 @@ +use crate::{Backend, Error, Result}; +use async_trait::async_trait; +use bb8::Pool; +use bb8_postgres::PostgresConnectionManager; +use pgstac::Client; +use serde_json::Map; +use stac::{Collection, Item}; +use stac_api::{ItemCollection, Items, Search}; +use tokio_postgres::tls::NoTls; + +/// A backend for a [pgstac](https://github.com/stac-utils/pgstac) database. +#[derive(Clone, Debug)] +pub struct PgstacBackend { + pool: Pool>, +} + +impl PgstacBackend { + /// Creates a new PgstacBackend from a string-like configuration. + /// + /// # Examples + /// + /// ```no_run + /// use stac_server::PgstacBackend; + /// # tokio_test::block_on(async { + /// let backend = PgstacBackend::new_from_stringlike("postgresql://username:password@localhost:5432/postgis").await.unwrap(); + /// # }) + /// ``` + pub async fn new_from_stringlike(params: impl ToString) -> Result { + let connection_manager = PostgresConnectionManager::new_from_stringlike(params, NoTls)?; + let pool = Pool::builder().build(connection_manager).await?; + Ok(PgstacBackend::new(pool)) + } + + fn new(pool: Pool>) -> PgstacBackend { + PgstacBackend { pool } + } +} + +#[async_trait] +impl Backend for PgstacBackend { + fn has_item_search(&self) -> bool { + true + } + + async fn add_collection(&mut self, collection: Collection) -> Result<()> { + let client = self.pool.get().await?; + let client = Client::new(&*client); + client.add_collection(collection).await.map_err(Error::from) + } + + async fn collection(&self, id: &str) -> Result> { + let client = self.pool.get().await?; + let client = Client::new(&*client); + client.collection(id).await.map_err(Error::from) + } + + async fn collections(&self) -> Result> { + let client = self.pool.get().await?; + let client = Client::new(&*client); + client.collections().await.map_err(Error::from) + } + + async fn add_item(&mut self, item: Item) -> Result<()> { + let client = self.pool.get().await?; + let client = Client::new(&*client); + client.add_item(item).await.map_err(Error::from) + } + + async fn items(&self, collection_id: &str, items: Items) -> Result> { + // TODO should we check for collection existence? + let search = items.into_search(collection_id); + self.search(search).await.map(Some) + } + + async fn item(&self, collection_id: &str, item_id: &str) -> Result> { + let client = self.pool.get().await?; + let client = Client::new(&*client); + client + .item(item_id, collection_id) + .await + .map_err(Error::from) + } + + async fn search(&self, search: Search) -> Result { + let client = self.pool.get().await?; + let client = Client::new(&*client); + let page = client.search(search).await?; + let next_token = page.next_token(); + let prev_token = page.prev_token(); + let mut item_collection = ItemCollection::new(page.features)?; + if let Some(next_token) = next_token { + let mut next = Map::new(); + let _ = next.insert("token".into(), next_token.into()); + item_collection.next = Some(next); + } + if let Some(prev_token) = prev_token { + let mut prev = Map::new(); + let _ = prev.insert("token".into(), prev_token.into()); + item_collection.prev = Some(prev); + } + item_collection.context = Some(page.context); + Ok(item_collection) + } +} diff --git a/stac-server/src/error.rs b/stac-server/src/error.rs new file mode 100644 index 00000000..19fe45f1 --- /dev/null +++ b/stac-server/src/error.rs @@ -0,0 +1,56 @@ +use thiserror::Error; + +/// A crate-specific error type. +#[derive(Debug, Error)] +pub enum Error { + /// [bb8::RunError] + #[cfg(feature = "pgstac")] + #[error(transparent)] + Bb8TokioPostgresRun(#[from] bb8::RunError), + + /// A generic backend error. + #[error("backend error: {0}")] + Backend(String), + + /// A memory backend error. + #[error("memory backend error: {0}")] + MemoryBackend(String), + + /// [pgstac::Error] + #[cfg(feature = "pgstac")] + #[error(transparent)] + Pgstac(#[from] pgstac::Error), + + /// [serde_json::Error] + #[error(transparent)] + SerdeJson(#[from] serde_json::Error), + + /// [serde_urlencoded::ser::Error] + #[error(transparent)] + SerdeUrlencodedSer(#[from] serde_urlencoded::ser::Error), + + /// [stac::Error] + #[error(transparent)] + Stac(#[from] stac::Error), + + /// [stac_api::Error] + #[error(transparent)] + StacApi(#[from] stac_api::Error), + + /// [stac_async::Error] + #[error(transparent)] + StacAsync(#[from] stac_async::Error), + + /// [tokio_postgres::Error] + #[cfg(feature = "pgstac")] + #[error(transparent)] + TokioPostgres(#[from] tokio_postgres::Error), + + /// [std::num::TryFromIntError] + #[error(transparent)] + TryFromInt(#[from] std::num::TryFromIntError), + + /// [url::ParseError] + #[error(transparent)] + UrlParse(#[from] url::ParseError), +} diff --git a/stac-server/src/lib.rs b/stac-server/src/lib.rs new file mode 100644 index 00000000..9cf43dab --- /dev/null +++ b/stac-server/src/lib.rs @@ -0,0 +1,67 @@ +//! A [STAC API](https://github.com/radiantearth/stac-api-spec) server written in Rust. + +#![deny( + elided_lifetimes_in_paths, + explicit_outlives_requirements, + keyword_idents, + macro_use_extern_crate, + meta_variable_misuse, + missing_abi, + missing_debug_implementations, + missing_docs, + non_ascii_idents, + noop_method_call, + pointer_structural_match, + rust_2021_incompatible_closure_captures, + rust_2021_incompatible_or_patterns, + rust_2021_prefixes_incompatible_syntax, + rust_2021_prelude_collisions, + single_use_lifetimes, + trivial_casts, + trivial_numeric_casts, + unreachable_pub, + unsafe_code, + unsafe_op_in_unsafe_fn, + unused_crate_dependencies, + unused_extern_crates, + unused_import_braces, + unused_lifetimes, + unused_qualifications, + unused_results, + warnings +)] + +mod api; +mod backend; +mod error; +#[cfg(feature = "axum")] +pub mod routes; + +pub use backend::MemoryBackend; +#[cfg(feature = "pgstac")] +pub use backend::PgstacBackend; +pub use {api::Api, backend::Backend, error::Error}; + +/// A crate-specific result type. +pub type Result = std::result::Result; + +/// The default catalog id. +pub const DEFAULT_ID: &str = "stac-server-rs"; + +/// The default catalog description. +pub const DEFAULT_DESCRIPTION: &str = "A STAC API server written in Rust"; + +/// The default limit. +pub const DEFAULT_LIMIT: u64 = 10; + +/// The GeoJSON content type. +pub const APPLICATION_GEO_JSON: &str = "application/geo+json"; + +/// The OpenAPI 3.0 content type. +pub const APPLICATION_OPENAPI_3_0: &str = "application/vnd.oai.openapi+json;version=3.0"; + +#[cfg(test)] +use tokio_test as _; + +#[cfg(all(test, not(feature = "axum")))] +use tower as _; diff --git a/stac-server/src/openapi.yaml b/stac-server/src/openapi.yaml new file mode 100644 index 00000000..14f264f0 --- /dev/null +++ b/stac-server/src/openapi.yaml @@ -0,0 +1,1938 @@ +openapi: 3.0.3 +info: + title: STAC API + version: 1.0.0 + description: >- + This is an OpenAPI definition of the SpatioTemporal Asset Catalog API specification. + contact: + name: STAC Specification + url: http://stacspec.org + license: + name: Apache License 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0 +tags: + - name: Item Search + description: Search for Items + - name: Features + description: Retrieve Item and Collection resources + - name: Transaction + description: Execute transactions on Items +paths: + /: + get: + tags: + - Features + summary: landing page + description: >- + The landing page provides links to the sub-resources. + operationId: getLandingPage + responses: + "200": + $ref: "#/components/responses/LandingPage" + "500": + $ref: "#/components/responses/Error" + /collections: + get: + tags: + - Features + summary: the feature collections in the dataset + description: >- + A body of Feature Collections that belong or are used together with additional links. + + Request may not return the full set of metadata per Feature Collection. + operationId: getCollections + responses: + "200": + $ref: "#/components/responses/Collections" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}: + get: + tags: + - Features + summary: describe the feature collection with id `collectionId` + description: >- + A single Feature Collection for the given if `collectionId`. + + Request this endpoint to get a full list of metadata for the Feature Collection. + operationId: describeCollection + parameters: + - $ref: "#/components/parameters/collectionId" + responses: + "200": + $ref: "#/components/responses/Collection" + "404": + $ref: "#/components/responses/NotFound" + "500": + $ref: "#/components/responses/ServerError" + /conformance: + get: + tags: + - Features + summary: information about specifications that this API conforms to + description: |- + A list of all conformance classes specified in a standard that the + server conforms to. + operationId: getConformanceDeclaration + responses: + "200": + $ref: "#/components/responses/ConformanceDeclaration" + "500": + $ref: "#/components/responses/ServerError" + /collections/{collectionId}/items: + get: + tags: + - Features + summary: fetch features + description: |- + Fetch features of the feature collection with id `collectionId`. + + Every feature in a dataset belongs to a collection. A dataset may + consist of multiple feature collections. A feature collection is often a + collection of features of a similar type, based on a common schema. + operationId: getFeatures + parameters: + - $ref: "#/components/parameters/collectionId" + - $ref: "#/components/parameters/limit" + - $ref: "#/components/parameters/bbox" + - $ref: "#/components/parameters/datetime" + responses: + "200": + $ref: "#/components/responses/Features" + "400": + $ref: "#/components/responses/InvalidParameter" + "404": + $ref: "#/components/responses/NotFound" + "500": + $ref: "#/components/responses/ServerError" + parameters: + - $ref: "#/components/parameters/collectionId" + post: + summary: add a new STAC Item to a collection + description: create a new STAC Item in a specific collection + operationId: postFeature + tags: + - Transaction + requestBody: + content: + application/json: + schema: + oneOf: + - $ref: "#/components/schemas/item" + - $ref: "#/components/schemas/itemCollection" + responses: + "201": + description: Status of the create request. + headers: + Location: + description: >- + The URL of the newly added resource (i.e. path of the resource end point) + schema: + type: string + format: url + ETag: + schema: + type: string + description: A string to ensure the item has not been modified + content: + application/json: + schema: + $ref: "#/components/schemas/item" + "400": + $ref: "#/components/responses/BadRequest" + "404": + $ref: "#/components/responses/NotFound" + "500": + $ref: "#/components/responses/ServerError" + default: + description: An error occurred. + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + /collections/{collectionId}/items/{featureId}: + get: + tags: + - Transaction + summary: fetch a single feature + description: |- + Fetch the feature with id `featureId` in the feature collection + with id `collectionId`. + operationId: getFeature + parameters: + - $ref: "#/components/parameters/collectionId" + - $ref: "#/components/parameters/featureId" + responses: + "200": + $ref: "#/components/responses/Feature" + "404": + $ref: "#/components/responses/NotFound" + "500": + $ref: "#/components/responses/ServerError" + parameters: + - $ref: "#/components/parameters/collectionId" + - $ref: "#/components/parameters/featureId" + put: + summary: update an existing feature by Id with a complete item definition + description: >- + Use this method to update an existing feature. Requires the entire GeoJSON description be submitted. + operationId: updateFeature + tags: + - Transaction + parameters: + - $ref: "#/components/parameters/IfMatch" + requestBody: + description: >- + The request body shall contain a representation of the replacement item. + content: + application/json: + schema: + $ref: "#/components/schemas/item" + responses: + "204": + description: The item was replaced + headers: + ETag: + schema: + type: string + description: An updated string to track changes + "400": + $ref: "#/components/responses/BadRequest" + "404": + $ref: "#/components/responses/NotFound" + "412": + $ref: "#/components/responses/PreconditionFailed" + "500": + $ref: "#/components/responses/ServerError" + default: + description: An error occurred. + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + patch: + summary: update an existing feature by Id with a partial item definition + description: >- + Use this method to update an existing feature. Requires a GeoJSON fragment (containing the fields to be updated) be submitted. + operationId: patchFeature + tags: + - Transaction + parameters: + - $ref: "#/components/parameters/IfMatchOptional" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/partialItem" + responses: + "204": + description: Status of the update request. + headers: + ETag: + schema: + type: string + description: A string to ensure the item has not been modified + "400": + $ref: "#/components/responses/BadRequest" + "404": + $ref: "#/components/responses/NotFound" + "500": + $ref: "#/components/responses/ServerError" + default: + description: An error occurred. + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + delete: + summary: delete an existing feature by Id + description: Use this method to delete an existing feature. + operationId: deleteFeature + tags: + - Transaction + parameters: + - $ref: "#/components/parameters/IfMatch" + responses: + "204": + description: The resource was deleted. + "400": + $ref: "#/components/responses/BadRequest" + "404": + $ref: "#/components/responses/NotFound" + "500": + $ref: "#/components/responses/ServerError" + default: + description: An error occurred. + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + /search: + get: + summary: Search STAC items with simple filtering. + operationId: getItemSearch + description: |- + Retrieve Items matching filters. Intended as a shorthand API for simple + queries. + + This method is required to implement. + + If this endpoint is implemented on a server, it is required to add a + link referring to this endpoint with `rel` set to `search` to the + `links` array in `GET /`. As `GET` is the default method, the `method` + may not be set explicitly in the link. + tags: + - Item Search + parameters: + - $ref: "#/components/parameters/bbox" + - $ref: "#/components/parameters/intersects" + - $ref: "#/components/parameters/datetime" + - $ref: "#/components/parameters/limit" + - $ref: "#/components/parameters/ids" + - $ref: "#/components/parameters/collectionsArray" + - $ref: "#/components/parameters/fields" + - $ref: "#/components/parameters/sortby" + responses: + "200": + description: A feature collection. + content: + application/geo+json: + schema: + allOf: + - $ref: "#/components/schemas/itemCollection" + - $ref: "#/components/schemas/schemas-itemCollection" + text/html: + schema: + type: string + default: + $ref: "#/components/responses/Error" + post: + summary: Search STAC items with full-featured filtering. + operationId: postItemSearch + description: |- + Retrieve items matching filters. Intended as the standard, full-featured + query API. + + This method is optional to implement, but recommended. + + If this endpoint is implemented on a server, it is required to add a + link referring to this endpoint with `rel` set to `search` and `method` + set to `POST` to the `links` array in `GET /`. + tags: + - Item Search + requestBody: + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/searchBody" + - $ref: "#/components/schemas/schemas-searchBody" + - $ref: "#/components/schemas/openapi_components-schemas-searchBody" + responses: + "200": + description: A feature collection. + content: + application/geo+json: + schema: + $ref: "#/components/schemas/itemCollection" + text/html: + schema: + type: string + default: + $ref: "#/components/responses/Error" +components: + schemas: + landingPage: + allOf: + - $ref: "#/components/schemas/catalog" + - $ref: "#/components/schemas/conformanceClasses" + stac_version: + title: STAC version + type: string + example: 1.0.0 + stac_extensions: + title: STAC extensions + type: array + uniqueItems: true + items: + anyOf: + - title: Reference to a JSON Schema + type: string + format: uri + - title: Reference to a core extension + type: string + link: + title: Link + type: object + required: + - href + - rel + properties: + href: + type: string + format: uri + description: The location of the resource + rel: + type: string + description: Relation type of the link + type: + type: string + description: The media type of the resource + title: + type: string + description: Title of the resource + method: + type: string + enum: + - GET + - POST + default: GET + description: Specifies the HTTP method that the resource expects + headers: + type: object + description: Object key values pairs they map to headers + example: + Accept: application/json + body: + type: object + description: >- + For POST requests, the resource can specify the HTTP body as a JSON object. + merge: + type: boolean + default: false + description: |- + This is only valid when the server is responding to POST request. + + If merge is true, the client is expected to merge the body value + into the current request body before following the link. + This avoids passing large post bodies back and forth when following + links, particularly for navigating pages through the `POST /search` + endpoint. + + NOTE: To support form encoding it is expected that a client be able + to merge in the key value pairs specified as JSON + `{"next": "token"}` will become `&next=token`. + links: + type: array + items: + $ref: "#/components/schemas/link" + catalog: + type: object + required: + - stac_version + - type + - id + - description + - links + properties: + stac_version: + $ref: "#/components/schemas/stac_version" + stac_extensions: + $ref: "#/components/schemas/stac_extensions" + type: + type: string + id: + type: string + title: + type: string + description: + type: string + links: + $ref: "#/components/schemas/links" + conformanceClasses: + type: object + required: + - conformsTo + properties: + conformsTo: + description: >- + A list of all conformance classes implemented by the server. In addition to the STAC-specific conformance classes, all OGC-related conformance classes listed at `GET /conformances` must be listed here. This entry should mirror what `GET /conformances` returns, if implemented. + type: array + items: + type: string + exception: + type: object + description: >- + Information about the exception: an error code plus an optional description. + required: + - code + properties: + code: + type: string + description: + type: string + collections: + type: object + required: + - links + - collections + properties: + links: + $ref: "#/components/schemas/links" + collections: + type: array + items: + $ref: "#/components/schemas/collection" + license: + type: string + description: |- + License(s) of the data as a SPDX + [License identifier](https://spdx.org/licenses/). Alternatively, use + `proprietary` if the license is not on the SPDX license list or + `various` if multiple licenses apply. In these two cases links to the + license texts SHOULD be added, see the `license` link relation type. + + Non-SPDX licenses SHOULD add a link to the license text with the + `license` relation in the links section. The license text MUST NOT be + provided as a value of this field. If there is no public license URL + available, it is RECOMMENDED to host the license text and + link to it. + example: Apache-2.0 + extent: + type: object + description: "The extent of the features in the collection. In the Core only spatial and temporal\nextents are specified. Extensions may add additional members to represent other\nextents, for example, thermal or pressure ranges.\n\nThe first item in the array describes the overall extent of\nthe data. All subsequent items describe more precise extents, \ne.g., to identify clusters of data.\nClients only interested in the overall extent will only need to\naccess the first item in each array." + required: + - spatial + - temporal + properties: + spatial: + description: The spatial extent of the features in the collection. + type: object + required: + - bbox + properties: + bbox: + description: "One or more bounding boxes that describe the spatial extent of the dataset.\n\nThe first bounding box describes the overall spatial\nextent of the data. All subsequent bounding boxes describe \nmore precise bounding boxes, e.g., to identify clusters of data.\nClients only interested in the overall spatial extent will\nonly need to access the first item in each array." + type: array + minItems: 1 + items: + description: >- + Each bounding box is provided as four or six numbers, depending on + + whether the coordinate reference system includes a vertical axis + + (height or depth): + + + * Lower left corner, coordinate axis 1 + + * Lower left corner, coordinate axis 2 + + * Minimum value, coordinate axis 3 (optional) + + * Upper right corner, coordinate axis 1 + + * Upper right corner, coordinate axis 2 + + * Maximum value, coordinate axis 3 (optional) + + + The coordinate reference system of the values is WGS 84 longitude/latitude + + (http://www.opengis.net/def/crs/OGC/1.3/CRS84) unless a different coordinate + + reference system is specified in `crs`. + + + For WGS 84 longitude/latitude the values are in most cases the sequence of + + minimum longitude, minimum latitude, maximum longitude and maximum latitude. + + However, in cases where the box spans the antimeridian the first value + + (west-most box edge) is larger than the third value (east-most box edge). + + + If the vertical axis is included, the third and the sixth number are + + the bottom and the top of the 3-dimensional bounding box. + + + If a feature has multiple spatial geometry properties, it is the decision of the + + server whether only a single spatial geometry property is used to determine + + the extent or all relevant geometries. + type: array + minItems: 4 + maxItems: 6 + items: + type: number + example: + - -180 + - -90 + - 180 + - 90 + crs: + description: >- + Coordinate reference system of the coordinates in the spatial extent + + (property `bbox`). The default reference system is WGS 84 longitude/latitude. + + In the Core this is the only supported coordinate reference system. + + Extensions may support additional coordinate reference systems and add + + additional enum values. + type: string + enum: + - http://www.opengis.net/def/crs/OGC/1.3/CRS84 + default: http://www.opengis.net/def/crs/OGC/1.3/CRS84 + temporal: + description: The temporal extent of the features in the collection. + type: object + required: + - interval + properties: + interval: + description: "One or more time intervals that describe the temporal extent of the dataset.\n\nThe first time interval describes the overall\ntemporal extent of the data. All subsequent time intervals describe \nmore precise time intervals, e.g., to identify clusters of data.\nClients only interested in the overall extent will only need\nto access the first item in each array." + type: array + minItems: 1 + items: + description: >- + Begin and end times of the time interval. The timestamps + + are in the coordinate reference system specified in `trs`. By default + + this is the Gregorian calendar. + + + The value `null` is supported and indicates an open time interval. + type: array + minItems: 2 + maxItems: 2 + items: + type: string + format: date-time + nullable: true + example: + - 2011-11-11T12:22:11Z + - null + trs: + description: >- + Coordinate reference system of the coordinates in the temporal extent + + (property `interval`). The default reference system is the Gregorian calendar. + + In the Core this is the only supported temporal reference system. + + Extensions may support additional temporal reference systems and add + + additional enum values. + type: string + enum: + - http://www.opengis.net/def/uom/ISO-8601/0/Gregorian + default: http://www.opengis.net/def/uom/ISO-8601/0/Gregorian + providers: + type: array + description: >- + A list of providers, which may include all organizations capturing or processing the data or the hosting provider. Providers should be listed in chronological order with the most recent provider being the last element of the list. + items: + type: object + title: Provider + required: + - name + properties: + name: + description: The name of the organization or the individual. + type: string + description: + description: >- + Multi-line description to add further provider information such as processing details for processors and producers, hosting details for hosts or basic contact information. + + + [CommonMark 0.29](http://commonmark.org/) syntax MAY be used for rich text representation. + type: string + roles: + description: |- + Roles of the provider. + + The provider's role(s) can be one or more of the following + elements: + + * licensor: The organization that is licensing the dataset under + the license specified in the collection's license field. + * producer: The producer of the data is the provider that + initially captured and processed the source data, e.g. ESA for + Sentinel-2 data. + * processor: A processor is any provider who processed data to a + derived product. + * host: The host is the actual provider offering the data on their + storage. There should be no more than one host, specified as last + element of the list. + type: array + items: + type: string + enum: + - producer + - licensor + - processor + - host + url: + description: >- + Homepage on which the provider describes the dataset and publishes contact information. + type: string + format: url + collection: + type: object + required: + - stac_version + - type + - id + - description + - license + - extent + - links + properties: + stac_version: + $ref: "#/components/schemas/stac_version" + stac_extensions: + $ref: "#/components/schemas/stac_extensions" + type: + type: string + id: + description: identifier of the collection used, for example, in URIs + type: string + title: + description: human readable title of the collection + type: string + description: + type: string + description: >- + Detailed multi-line description to fully explain the catalog or collection. + + [CommonMark 0.29](http://commonmark.org/) syntax MAY be used for rich text representation. + keywords: + type: array + description: List of keywords describing the collection. + items: + type: string + license: + $ref: "#/components/schemas/license" + extent: + $ref: "#/components/schemas/extent" + providers: + $ref: "#/components/schemas/providers" + links: + $ref: "#/components/schemas/links" + summaries: + description: |- + Summaries are either a unique set of all available values *or* + statistics. Statistics by default only specify the range (minimum + and maximum values), but can optionally be accompanied by additional + statistical values. The range can specify the potential range of + values, but it is recommended to be as precise as possible. The set + of values must contain at least one element and it is strongly + recommended to list all values. It is recommended to list as many + properties as reasonable so that consumers get a full overview of + the Collection. Properties that are covered by the Collection + specification (e.g. `providers` and `license`) may not be repeated + in the summaries. + type: object + additionalProperties: + oneOf: + - type: array + title: Set of values + items: + description: A value of any type. + - type: object + title: Statistics + description: |- + By default, only ranges with a minimum and a maximum value can + be specified. Ranges can be specified for ordinal values only, + which means they need to have a rank order. Therefore, ranges + can only be specified for numbers and some special types of + strings. Examples: grades (A to F), dates or times. + Implementors are free to add other derived statistical values + to the object, for example `mean` or `stddev`. + required: + - min + - max + properties: + min: + anyOf: + - type: string + - type: number + max: + anyOf: + - type: string + - type: number + example: + stac_version: 1.0.0 + stac_extensions: [] + type: Collection + id: Sentinel-2 + title: "Sentinel-2 MSI: MultiSpectral Instrument, Level-1C" + description: | + Sentinel-2 is a wide-swath, high-resolution, multi-spectral + imaging mission... + license: proprietary + keywords: + - copernicus + - esa + - eu + - msi + - radiance + - sentinel + providers: + - name: ESA + roles: + - producer + - licensor + url: https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi + extent: + spatial: + bbox: + - - -180 + - -56 + - 180 + - 83 + temporal: + interval: + - - 2015-06-23T00:00:00Z + - 2019-07-10T13:44:56Z + summaries: + datetime: + min: 2015-06-23T00:00:00Z + max: 2019-07-10T13:44:56Z + sci:citation: + - Copernicus Sentinel data [Year] + eo:gsd: + - 10 + - 30 + - 60 + platform: + - sentinel-2a + - sentinel-2b + constellation: + - sentinel-2 + instruments: + - msi + view:off_nadir: + min: 0 + max: 100 + view:sun_elevation: + min: 6.78 + max: 89.9 + eo:bands: + - - name: B1 + common_name: coastal + center_wavelength: 4.439 + - name: B2 + common_name: blue + center_wavelength: 4.966 + - name: B3 + common_name: green + center_wavelength: 5.6 + - name: B4 + common_name: red + center_wavelength: 6.645 + - name: B5 + center_wavelength: 7.039 + - name: B6 + center_wavelength: 7.402 + - name: B7 + center_wavelength: 7.825 + - name: B8 + common_name: nir + center_wavelength: 8.351 + - name: B8A + center_wavelength: 8.648 + - name: B9 + center_wavelength: 9.45 + - name: B10 + center_wavelength: 1.3735 + - name: B11 + common_name: swir16 + center_wavelength: 1.6137 + - name: B12 + common_name: swir22 + center_wavelength: 2.2024 + links: + - rel: self + href: http://cool-sat.com/collections/Sentinel-2 + - rel: root + href: http://cool-sat.com/collections + - rel: license + href: >- + https://scihub.copernicus.eu/twiki/pub/SciHubWebPortal/TermsConditions/Sentinel_Data_Terms_and_Conditions.pdf + title: >- + Legal notice on the use of Copernicus Sentinel Data and Service Information + featureCollectionGeoJSON: + allOf: + - $ref: "#/components/schemas/schemas-featureCollectionGeoJSON" + - type: object + required: + - features + properties: + features: + type: array + items: + $ref: "#/components/schemas/item" + links: + $ref: "#/components/schemas/links" + timeStamp: + $ref: "#/components/schemas/timeStamp" + numberMatched: + $ref: "#/components/schemas/numberMatched" + numberReturned: + $ref: "#/components/schemas/numberReturned" + numberMatched: + description: |- + The number of features of the feature type that match the selection + parameters like `bbox`. + type: integer + minimum: 0 + example: 127 + numberReturned: + description: |- + The number of features in the feature collection. + + A server may omit this information in a response, if the information + about the number of features is not known or difficult to compute. + + If the value is provided, the value shall be identical to the number + of items in the "features" array. + type: integer + minimum: 0 + example: 10 + timeStamp: + description: >- + This property indicates the time and date when the response was generated. + type: string + format: date-time + example: 2017-08-17T08:05:32Z + pointGeoJSON: + type: object + required: + - type + - coordinates + properties: + type: + type: string + enum: + - Point + coordinates: + type: array + minItems: 2 + items: + type: number + multipointGeoJSON: + type: object + required: + - type + - coordinates + properties: + type: + type: string + enum: + - MultiPoint + coordinates: + type: array + items: + type: array + minItems: 2 + items: + type: number + linestringGeoJSON: + type: object + required: + - type + - coordinates + properties: + type: + type: string + enum: + - LineString + coordinates: + type: array + minItems: 2 + items: + type: array + minItems: 2 + items: + type: number + multilinestringGeoJSON: + type: object + required: + - type + - coordinates + properties: + type: + type: string + enum: + - MultiLineString + coordinates: + type: array + items: + type: array + minItems: 2 + items: + type: array + minItems: 2 + items: + type: number + polygonGeoJSON: + type: object + required: + - type + - coordinates + properties: + type: + type: string + enum: + - Polygon + coordinates: + type: array + items: + type: array + minItems: 4 + items: + type: array + minItems: 2 + items: + type: number + multipolygonGeoJSON: + type: object + required: + - type + - coordinates + properties: + type: + type: string + enum: + - MultiPolygon + coordinates: + type: array + items: + type: array + items: + type: array + minItems: 4 + items: + type: array + minItems: 2 + items: + type: number + geometryGeoJSON: + oneOf: + - $ref: "#/components/schemas/pointGeoJSON" + - $ref: "#/components/schemas/multipointGeoJSON" + - $ref: "#/components/schemas/linestringGeoJSON" + - $ref: "#/components/schemas/multilinestringGeoJSON" + - $ref: "#/components/schemas/polygonGeoJSON" + - $ref: "#/components/schemas/multipolygonGeoJSON" + - $ref: "#/components/schemas/geometrycollectionGeoJSON" + geometrycollectionGeoJSON: + type: object + required: + - type + - geometries + properties: + type: + type: string + enum: + - GeometryCollection + geometries: + type: array + items: + $ref: "#/components/schemas/geometryGeoJSON" + featureGeoJSON: + type: object + required: + - type + - geometry + - properties + properties: + type: + type: string + enum: + - Feature + geometry: + $ref: "#/components/schemas/geometryGeoJSON" + properties: + type: object + nullable: true + schemas-featureCollectionGeoJSON: + type: object + required: + - type + - features + properties: + type: + type: string + enum: + - FeatureCollection + features: + type: array + items: + $ref: "#/components/schemas/featureGeoJSON" + itemId: + type: string + description: Provider identifier, a unique ID. + bbox: + description: "Only features that have a geometry that intersects the bounding box are\nselected. The bounding box is provided as four or six numbers,\ndepending on whether the coordinate reference system includes a\nvertical axis (elevation or depth):\n\n* Lower left corner, coordinate axis 1\n* Lower left corner, coordinate axis 2 \n* Lower left corner, coordinate axis 3 (optional) \n* Upper right corner, coordinate axis 1 \n* Upper right corner, coordinate axis 2 \n* Upper right corner, coordinate axis 3 (optional)\n\nThe coordinate reference system of the values is WGS84\nlongitude/latitude (http://www.opengis.net/def/crs/OGC/1.3/CRS84).\n\nFor WGS84 longitude/latitude the values are in most cases the sequence\nof minimum longitude, minimum latitude, maximum longitude and maximum\nlatitude. However, in cases where the box spans the antimeridian the\nfirst value (west-most box edge) is larger than the third value\n(east-most box edge).\n\nIf a feature has multiple spatial geometry properties, it is the\ndecision of the server whether only a single spatial geometry property\nis used to determine the extent or all relevant geometries.\n\nExample: The bounding box of the New Zealand Exclusive Economic Zone in\nWGS 84 (from 160.6°E to 170°W and from 55.95°S to 25.89°S) would be\nrepresented in JSON as `[160.6, -55.95, -170, -25.89]` and in a query as\n`bbox=160.6,-55.95,-170,-25.89`." + type: array + minItems: 4 + maxItems: 6 + items: + type: number + example: + - -110 + - 39.5 + - -105 + - 40.5 + oneOf: + - minItems: 4 + maxItems: 4 + - minItems: 6 + maxItems: 6 + itemType: + type: string + description: The GeoJSON type + enum: + - Feature + datetime: + type: string + format: date-time + nullable: true + description: >- + The searchable date and time of the assets, in UTC. + + It is formatted according to [RFC 3339, section 5.6](https://tools.ietf.org/html/rfc3339#section-5.6). + + `null` is allowed, but requires `start_datetime` and `end_datetime` from common metadata to be set. + example: 2018-02-12T00:00:00Z + properties: + type: object + required: + - datetime + description: provides the core metadata fields plus extensions + properties: + datetime: + $ref: "#/components/schemas/datetime" + additionalProperties: + description: >- + Any additional properties added in via Item specification or extensions. + assets: + type: object + additionalProperties: + type: object + required: + - href + properties: + href: + type: string + format: url + description: Link to the asset object + example: >- + http://cool-sat.com/catalog/collections/cs/items/CS3-20160503_132130_04/thumb.png + title: + type: string + description: Displayed title + example: Thumbnail + description: + type: string + description: >- + Multi-line description to explain the asset. + + + [CommonMark 0.29](http://commonmark.org/) syntax MAY be used for rich text representation. + example: Small 256x256px PNG thumbnail for a preview. + type: + type: string + description: Media type of the asset + example: image/png + roles: + type: array + items: + type: string + description: Purposes of the asset + example: + - thumbnail + item: + description: >- + A GeoJSON Feature augmented with foreign members that contain values relevant to a STAC entity + type: object + required: + - stac_version + - id + - type + - geometry + - bbox + - links + - properties + - assets + properties: + stac_version: + $ref: "#/components/schemas/stac_version" + stac_extensions: + $ref: "#/components/schemas/stac_extensions" + id: + $ref: "#/components/schemas/itemId" + bbox: + $ref: "#/components/schemas/schemas-bbox" + geometry: + $ref: "#/components/schemas/geometryGeoJSON" + type: + $ref: "#/components/schemas/itemType" + links: + $ref: "#/components/schemas/links" + properties: + $ref: "#/components/schemas/properties" + assets: + $ref: "#/components/schemas/assets" + example: + stac_version: 1.0.0 + stac_extensions: + - https://stac-extensions.github.io/eo/v1.0.0/schema.json + - https://stac-extensions.github.io/view/v1.0.0/schema.json + - https://example.com/cs-extension/1.0/schema.json + type: Feature + id: CS3-20160503_132131_05 + bbox: + - -122.59750209 + - 37.48803556 + - -122.2880486 + - 37.613537207 + geometry: + type: Polygon + coordinates: + - - - -122.308150179 + - 37.488035566 + - - -122.597502109 + - 37.538869539 + - - -122.576687533 + - 37.613537207 + - - -122.2880486 + - 37.562818007 + - - -122.308150179 + - 37.488035566 + properties: + datetime: 2016-05-03T13:22:30.040Z + title: A CS3 item + license: PDDL-1.0 + providers: + - name: CoolSat + roles: + - producer + - licensor + url: https://cool-sat.com/ + view:sun_azimuth: 168.7 + eo:cloud_cover: 0.12 + view:off_nadir: 1.4 + platform: coolsat2 + instruments: + - cool_sensor_v1 + eo:bands: [] + view:sun_elevation: 33.4 + eo:gsd: 0.512 + collection: CS3 + links: + - rel: self + href: http://cool-sat.com/collections/CS3/items/20160503_132130_04 + - rel: root + href: http://cool-sat.com/collections + - rel: parent + href: http://cool-sat.com/collections/CS3 + - rel: collection + href: http://cool-sat.com/collections/CS3 + assets: + analytic: + href: >- + http://cool-sat.com/static-catalog/CS3/20160503_132130_04/analytic.tif + title: 4-Band Analytic + thumbnail: + href: >- + http://cool-sat.com/static-catalog/CS3/20160503_132130_04/thumbnail.png + title: Thumbnail + partialItem: + type: object + properties: + stac_version: + $ref: "#/components/schemas/stac_version" + stac_extensions: + $ref: "#/components/schemas/stac_extensions" + id: + $ref: "#/components/schemas/itemId" + bbox: + $ref: "#/components/schemas/bbox" + geometry: + $ref: "#/components/schemas/geometryGeoJSON" + type: + $ref: "#/components/schemas/itemType" + properties: + $ref: "#/components/schemas/partialItemProperties" + links: + type: array + items: + $ref: "#/components/schemas/link" + assets: + $ref: "#/components/schemas/assets" + example: + assets: + analytic: + title: 1-Band Analytic + href: >- + http://cool-sat.com/catalog/collections/cs/items/CS3-201605XX_132130_04/analytic-1.tif + partialItemProperties: + type: object + description: allows for partial collections of metadata fields + additionalProperties: true + properties: + datetime: + $ref: "#/components/schemas/datetime" + itemCollection: + description: >- + A GeoJSON FeatureCollection augmented with foreign members that contain values relevant to a STAC entity + type: object + required: + - features + - type + properties: + type: + type: string + enum: + - FeatureCollection + features: + type: array + items: + $ref: "#/components/schemas/item" + links: + type: array + description: >- + An array of links. Can be used for pagination, e.g. by providing a link with the `next` relation type. + items: + $ref: "#/components/schemas/link" + example: + - rel: next + href: >- + http://api.cool-sat.com/search?next=ANsXtp9mrqN0yrKWhf-y2PUpHRLQb1GT-mtxNcXou8TwkXhi1Jbk + searchBody: + description: The search criteria + type: object + allOf: + - $ref: "#/components/schemas/bboxFilter" + - $ref: "#/components/schemas/datetimeFilter" + - $ref: "#/components/schemas/intersectsFilter" + - $ref: "#/components/schemas/collectionsFilter" + - $ref: "#/components/schemas/idsFilter" + - $ref: "#/components/schemas/limitFilter" + limit: + type: integer + minimum: 1 + example: 10 + default: 10 + maximum: 10000 + description: >- + The optional limit parameter limits the number of items that are presented in the response document. + + + If the limit parameter value is greater than advertised limit maximum, the server shall return the + + maximum possible number of items, rather than responding with an error. + + + Only items are counted that are on the first level of the collection in the response document. + + Nested objects contained within the explicitly requested items shall not be counted. + + + Minimum = 1. Maximum = 10000. Default = 10. + bboxFilter: + type: object + description: Only return items that intersect the provided bounding box. + properties: + bbox: + $ref: "#/components/schemas/schemas-bbox" + collectionsArray: + type: array + description: |- + Array of Collection IDs to include in the search for items. + Only Item objects in one of the provided collections will be searched. + items: + type: string + ids: + type: array + description: Array of Item ids to return. + items: + type: string + datetimeFilter: + description: An object representing a date+time based filter. + type: object + properties: + datetime: + $ref: "#/components/schemas/datetime_interval" + intersectsFilter: + type: object + description: Only returns items that intersect with the provided polygon. + properties: + intersects: + $ref: "#/components/schemas/geometryGeoJSON" + limitFilter: + type: object + description: Only returns maximum number of results (page size) + properties: + limit: + $ref: "#/components/schemas/limit" + idsFilter: + type: object + description: Only returns items that match the array of given ids + properties: + ids: + $ref: "#/components/schemas/ids" + collectionsFilter: + type: object + description: Only returns the collections specified + properties: + collections: + $ref: "#/components/schemas/collectionsArray" + datetime_interval: + type: string + description: >- + Either a date-time or an interval, open or closed. Date and time expressions + + adhere to RFC 3339. Open intervals are expressed using double-dots. + + + Examples: + + + * A date-time: "2018-02-12T23:20:50Z" + + * A closed interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" + + * Open intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + + + Only features that have a temporal property that intersects the value of + + `datetime` are selected. + + + If a feature has multiple temporal properties, it is the decision of the + + server whether only a single temporal property is used to determine + + the extent or all relevant temporal properties. + example: 2018-02-12T00:00:00Z/2018-03-18T12:31:12Z + schemas-bbox: + description: "Only features that have a geometry that intersects the bounding box are\nselected. The bounding box is provided as four or six numbers,\ndepending on whether the coordinate reference system includes a\nvertical axis (elevation or depth):\n\n* Lower left corner, coordinate axis 1\n* Lower left corner, coordinate axis 2 \n* Lower left corner, coordinate axis 3 (optional) \n* Upper right corner, coordinate axis 1 \n* Upper right corner, coordinate axis 2 \n* Upper right corner, coordinate axis 3 (optional)\n\nThe coordinate reference system of the values is WGS84\nlongitude/latitude (http://www.opengis.net/def/crs/OGC/1.3/CRS84).\n\nFor WGS84 longitude/latitude the values are in most cases the sequence\nof minimum longitude, minimum latitude, maximum longitude and maximum\nlatitude. However, in cases where the box spans the antimeridian the\nfirst value (west-most box edge) is larger than the third value\n(east-most box edge).\n\nIf a feature has multiple spatial geometry properties, it is the\ndecision of the server whether only a single spatial geometry property\nis used to determine the extent or all relevant geometries.\n\nExample: The bounding box of the New Zealand Exclusive Economic Zone in\nWGS 84 (from 160.6°E to 170°W and from 55.95°S to 25.89°S) would be\nrepresented in JSON as `[160.6, -55.95, -170, -25.89]` and in a query as\n`bbox=160.6,-55.95,-170,-25.89`." + type: array + minItems: 4 + maxItems: 6 + items: + type: number + example: + - -110 + - 39.5 + - -105 + - 40.5 + schemas-itemCollection: + type: object + description: >- + **Extension:** Context + + + Augments lists of resources with the number of returned and matches resource and the given limit for the request. + x-stac-api-fragment: context + properties: + context: + type: object + required: + - returned + properties: + returned: + type: integer + minimum: 0 + example: 1 + limit: + type: integer + nullable: true + minimum: 0 + example: 5 + matched: + type: integer + minimum: 0 + example: 314159 + fields: + description: | + The include and exclude members specify an array of + property names that are either included or excluded + from the result, respectively. If both include and + exclude are specified, include takes precedence. + Values should include the full JSON path of the property. + type: object + properties: + include: + type: array + items: + type: string + exclude: + type: array + items: + type: string + example: + include: + - id + - properties.eo:cloud_cover + exclude: + - geometry + - properties.datetime + schemas-searchBody: + type: object + x-stac-api-fragment: fields + description: |- + **Extension:** Fields + + Determines the shape of the features in the response + properties: + fields: + $ref: "#/components/schemas/fields" + sortby: + type: array + description: | + An array of objects containing a property name and sort direction. + minItems: 1 + items: + type: object + required: + - field + - direction + properties: + field: + type: string + direction: + type: string + default: asc + enum: + - asc + - desc + example: + - field: properties.eo:cloud_cover + direction: asc + - field: id + direction: desc + openapi_components-schemas-searchBody: + type: object + x-stac-api-fragment: sort + description: |- + **Extension:** Sort + + Sort the results. + properties: + sortby: + $ref: "#/components/schemas/sortby" + responses: + LandingPage: + description: |- + The landing page provides links to the API definition + (link relations `service-desc` and `service-doc`) + and the Feature Collection (path `/collections`, link relation + `data`). + content: + application/json: + schema: + $ref: "#/components/schemas/landingPage" + example: + type: Catalog + stac_version: 1.0.0 + id: sentinel + title: Copernicus Sentinel Imagery + description: Catalog of Copernicus Sentinel 1 and 2 imagery. + conformsTo: + - https://api.stacspec.org/v1.0.0/core + links: + - href: http://data.example.org/ + rel: self + type: application/json + title: this document + - href: http://data.example.org/api + rel: service-desc + type: application/vnd.oai.openapi+json;version=3.0 + title: the API definition + - href: http://data.example.org/api.html + rel: service-doc + type: text/html + title: the API documentation + - href: http://data.example.org/catalogs/sentinel-1 + rel: child + type: application/json + title: Sentinel 1 Catalog + - href: http://data.example.org/catalogs/sentinel-2 + rel: child + type: application/json + title: Sentinel 2 Catalog + Error: + description: An error occurred. + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + Collections: + description: >- + The feature collections shared by this API. + + + The dataset is organized as one or more feature collections. This resource + + provides information about and access to the collections. + + + The response contains the list of collections. For each collection, a link + + to the items in the collection (path `/collections/{collectionId}/items`, + + link relation `items`) as well as key information about the collection. + + This information includes: + + + * A local identifier for the collection that is unique for the dataset; + + * A list of coordinate reference systems (CRS) in which geometries may be returned by the server. The first CRS is the default coordinate reference system (the default is always WGS 84 with axis order longitude/latitude); + + * An optional title and description for the collection; + + * An optional extent that can be used to provide an indication of the spatial and temporal extent of the collection - typically derived from the data; + + * An optional indicator about the type of the items in the collection (the default value, if the indicator is not provided, is 'feature'). + content: + application/json: + schema: + $ref: "#/components/schemas/collections" + Collection: + description: >- + Information about the feature collection with id `collectionId`. + + + The response contains a link to the items in the collection + + (path `/collections/{collectionId}/items`, link relation `items`) + + as well as key information about the collection. This information + + includes: + + + * A local identifier for the collection that is unique for the dataset; + + * A list of coordinate reference systems (CRS) in which geometries may be returned by the server. The first CRS is the default coordinate reference system (the default is always WGS 84 with axis order longitude/latitude); + + * An optional title and description for the collection; + + * An optional extent that can be used to provide an indication of the spatial and temporal extent of the collection - typically derived from the data; + + * An optional indicator about the type of the items in the collection (the default value, if the indicator is not provided, is 'feature'). + content: + application/json: + schema: + $ref: "#/components/schemas/collection" + InvalidParameter: + description: A query parameter has an invalid value. + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + NotFound: + description: The requested URI was not found. + ServerError: + description: A server error occurred. + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + ConformanceDeclaration: + description: |- + The URIs of all conformance classes supported by the server. + + To support "generic" clients that want to access multiple + OGC API Features implementations - and not "just" a specific + API / server, the server declares the conformance + classes it implements and conforms to. + content: + application/json: + schema: + $ref: "#/components/schemas/conformanceClasses" + example: + conformsTo: + - http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/core + - http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/oas30 + - http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/geojson + Features: + description: >- + The response is a document consisting of features in the collection. + + The features included in the response are determined by the server + + based on the query parameters of the request. To support access to + + larger collections without overloading the client, the API supports + + paged access with links to the next page, if more features are selected + + that the page size. + + + The `bbox` and `datetime` parameter can be used to select only a + + subset of the features in the collection (the features that are in the + + bounding box or time interval). The `bbox` parameter matches all features + + in the collection that are not associated with a location, too. The + + `datetime` parameter matches all features in the collection that are + + not associated with a time stamp or interval, too. + + + The `limit` parameter may be used to control the subset of the + + selected features that should be returned in the response, the page size. + + Each page may include information about the number of selected and + + returned features (`numberMatched` and `numberReturned`) as well as + + links to support paging (link relation `next`). + content: + application/geo+json: + schema: + $ref: "#/components/schemas/featureCollectionGeoJSON" + Feature: + description: |- + fetch the feature with id `featureId` in the feature collection + with id `collectionId` + content: + application/geo+json: + schema: + $ref: "#/components/schemas/item" + BadRequest: + description: The request was malformed or semantically invalid + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + PreconditionFailed: + description: Some condition specified by the request could not be met in the server + content: + application/json: + schema: + $ref: "#/components/schemas/exception" + parameters: + collectionId: + name: collectionId + in: path + description: local identifier of a collection + required: true + schema: + type: string + bbox: + name: bbox + in: query + description: >- + Only features that have a geometry that intersects the bounding box are selected. + + The bounding box is provided as four or six numbers, depending on + + whether the coordinate reference system includes a vertical axis (height + + or depth): + + + * Lower left corner, coordinate axis 1 + + * Lower left corner, coordinate axis 2 + + * Minimum value, coordinate axis 3 (optional) + + * Upper right corner, coordinate axis 1 + + * Upper right corner, coordinate axis 2 + + * Maximum value, coordinate axis 3 (optional) + + + The coordinate reference system of the values is WGS 84 + + longitude/latitude (http://www.opengis.net/def/crs/OGC/1.3/CRS84). + + + For WGS 84 longitude/latitude the values are in most cases the sequence + + of minimum longitude, minimum latitude, maximum longitude and maximum + + latitude. However, in cases where the box spans the antimeridian the + + first value (west-most box edge) is larger than the third value + + (east-most box edge). + + + If the vertical axis is included, the third and the sixth number are + + the bottom and the top of the 3-dimensional bounding box. + + + If a feature has multiple spatial geometry properties, it is the + + decision of the server whether only a single spatial geometry property + + is used to determine the extent or all relevant geometries. + + + Example: The bounding box of the New Zealand Exclusive Economic Zone in + + WGS 84 (from 160.6°E to 170°W and from 55.95°S to 25.89°S) would be + + represented in JSON as `[160.6, -55.95, -170, -25.89]` and in a query as + + `bbox=160.6,-55.95,-170,-25.89`. + required: false + schema: + type: array + oneOf: + - minItems: 4 + maxItems: 4 + - minItems: 6 + maxItems: 6 + items: + type: number + style: form + explode: false + datetime: + name: datetime + in: query + description: >- + Either a date-time or an interval, open or closed. Date and time expressions + + adhere to RFC 3339. Open intervals are expressed using double-dots. + + + Examples: + + + * A date-time: "2018-02-12T23:20:50Z" + + * A closed interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" + + * Open intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z" + + + Only features that have a temporal property that intersects the value of + + `datetime` are selected. + + + If a feature has multiple temporal properties, it is the decision of the + + server whether only a single temporal property is used to determine + + the extent or all relevant temporal properties. + required: false + schema: + type: string + style: form + explode: false + featureId: + name: featureId + in: path + description: local identifier of a feature + required: true + schema: + type: string + limit: + name: limit + in: query + description: >- + The optional limit parameter recommends the number of items that should be present in the response document. + + + Only items are counted that are on the first level of the collection in the response document. + + Nested objects contained within the explicitly requested items shall not be counted. + + + Minimum = 1. Maximum = 10000. Default = 10. + required: false + schema: + type: integer + minimum: 1 + maximum: 10000 + default: 10 + style: form + explode: false + IfMatch: + name: If-Match + in: header + description: Only take the action if the ETag of the item still matches + required: true + schema: + type: string + IfMatchOptional: + name: If-Match + in: header + description: Only take the action if the ETag of the item still matches + required: false + schema: + type: string + ids: + name: ids + in: query + description: Array of Item ids to return. + required: false + schema: + $ref: "#/components/schemas/ids" + explode: false + collectionsArray: + name: collections + in: query + description: | + Array of Collection IDs to include in the search for items. + Only Item objects in one of the provided collections will be searched + required: false + schema: + $ref: "#/components/schemas/collectionsArray" + explode: false + intersects: + name: intersects + in: query + description: >- + The optional intersects parameter filters the result Items in the same was as bbox, only with + + a GeoJSON Geometry rather than a bbox. + required: false + schema: + $ref: "#/components/schemas/geometryGeoJSON" + style: form + explode: false + fields: + name: fields + x-stac-api-fragment: fields + in: query + description: |- + **Extension:** Fields + + Determines the shape of the features in the response + required: false + schema: + type: string + example: id,type,-geometry,bbox,properties,-links,-assets + style: form + explode: false + sortby: + name: sortby + x-stac-api-fragment: sort + in: query + description: |- + **Extension:** Sort + + An array of property names, prefixed by either "+" for ascending or + "-" for descending. If no prefix is provided, "+" is assumed. + required: false + schema: + type: string + example: +id,-properties.eo:cloud_cover + style: form + explode: false diff --git a/stac-server/src/redoc.html b/stac-server/src/redoc.html new file mode 100644 index 00000000..8482c86e --- /dev/null +++ b/stac-server/src/redoc.html @@ -0,0 +1,21 @@ + + + + stac-server API documentation + + + + + + + + + + + + diff --git a/stac-server/src/routes.rs b/stac-server/src/routes.rs new file mode 100644 index 00000000..ac786ef1 --- /dev/null +++ b/stac-server/src/routes.rs @@ -0,0 +1,389 @@ +//! Routes for serving API endpoints. + +use crate::{Api, Backend, APPLICATION_GEO_JSON, APPLICATION_OPENAPI_3_0}; +use axum::{ + extract::{rejection::JsonRejection, Path, Query, State}, + http::{header::CONTENT_TYPE, HeaderValue, StatusCode}, + response::{Html, IntoResponse, Response}, + routing::{get, post}, + Json, Router, +}; +use http::Method; +use stac_api::{GetItems, GetSearch, Items, Search}; + +/// Creates an [axum::Router] from an [Api]. +/// +/// # Examples +/// +/// ``` +/// use stac_server::{Api, MemoryBackend, routes}; +/// +/// let api = Api::new(MemoryBackend::new(), "http://stac.test").unwrap(); +/// let router = routes::from_api(api); +/// ``` +pub fn from_api(api: Api) -> Router { + Router::new() + .route("/", get(root)) + .route("/api", get(service_desc)) + .route("/api.html", get(service_doc)) + .route("/conformance", get(conformance)) + .route("/collections", get(collections)) + .route("/collections/:collection_id", get(collection)) + .route("/collections/:collection_id/items", get(items)) + .route("/collections/:collection_id/items/:item_id", get(item)) + .route("/search", get(get_search)) + .route("/search", post(post_search)) + .with_state(api) +} + +/// Returns the `/` endpoint from the [core conformance +/// class](https://github.com/radiantearth/stac-api-spec/tree/release/v1.0.0/core#endpoints). +pub async fn root(State(api): State>) -> Response { + match api.root().await { + Ok(root) => Json(root).into_response(), + Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, format!("{}", err)).into_response(), + } +} + +/// Returns the `/api` endpoint from the [core conformance +/// class](https://github.com/radiantearth/stac-api-spec/tree/release/v1.0.0/core#endpoints). +pub async fn service_desc() -> Response { + // The OpenAPI definition is completely stolen from [stac-server](https://github.com/stac-utils/stac-server/blob/dd7e3acbf47485425e2068fd7fbbceeafe4b4e8c/src/lambdas/api/openapi.yaml). + // + // TODO add a script to update the definition in this library. + ( + [(CONTENT_TYPE, APPLICATION_OPENAPI_3_0)], + include_str!("openapi.yaml"), + ) + .into_response() +} + +/// Returns the `/api.html` endpoint from the [core conformance +/// class](https://github.com/radiantearth/stac-api-spec/tree/release/v1.0.0/core#endpoints). +pub async fn service_doc() -> Response { + // The redoc file is completely stolen from [stac-server](https://github.com/stac-utils/stac-server/blob/dd7e3acbf47485425e2068fd7fbbceeafe4b4e8c/src/lambdas/api/redoc.html). + Html(include_str!("redoc.html")).into_response() +} + +/// Returns the `/conformance` endpoint from the [ogcapi-features conformance +/// class](https://github.com/radiantearth/stac-api-spec/blob/release/v1.0.0/ogcapi-features/README.md#endpoints). +pub async fn conformance(State(api): State>) -> Response { + Json(api.conformance()).into_response() +} + +/// Returns the `/collections` endpoint from the [ogcapi-features conformance +/// class](https://github.com/radiantearth/stac-api-spec/blob/release/v1.0.0/ogcapi-features/README.md#endpoints). +pub async fn collections(State(api): State>) -> Response { + match api.collections().await { + Ok(collections) => Json(collections).into_response(), + Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, format!("{}", err)).into_response(), + } +} + +/// Returns the `/collections/{collectionId}` endpoint from the [ogcapi-features +/// conformance +/// class](https://github.com/radiantearth/stac-api-spec/blob/release/v1.0.0/ogcapi-features/README.md#endpoints). +pub async fn collection( + State(api): State>, + Path(collection_id): Path, +) -> Response { + match api.collection(&collection_id).await { + Ok(option) => { + if let Some(collection) = option { + Json(collection).into_response() + } else { + ( + StatusCode::NOT_FOUND, + format!("no collection with id='{}'", collection_id), + ) + .into_response() + } + } + Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, format!("{}", err)).into_response(), + } +} + +/// Returns the `/collections/{collectionId}/items` endpoint from the +/// [ogcapi-features conformance +/// class](https://github.com/radiantearth/stac-api-spec/tree/release/v1.0.0/ogcapi-features#collection-items-collectionscollectioniditems) +pub async fn items( + State(api): State>, + Path(collection_id): Path, + items: Query, +) -> Response { + match Items::try_from(items.0).and_then(Items::valid) { + Ok(items) => match api.items(&collection_id, items).await { + Ok(option) => { + if let Some(items) = option { + let mut response = Json(items).into_response(); + let _ = response + .headers_mut() + .insert(CONTENT_TYPE, HeaderValue::from_static(APPLICATION_GEO_JSON)); + response + } else { + ( + StatusCode::NOT_FOUND, + format!("no collection with id='{}'", collection_id), + ) + .into_response() + } + } + Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, format!("{}", err)).into_response(), + }, + Err(err) => (StatusCode::BAD_REQUEST, format!("invalid query: {}", err,)).into_response(), + } +} + +/// Returns the `/collections/{collectionId}/items/{itemId}` endpoint from the +/// [ogcapi-features conformance +/// class](https://github.com/radiantearth/stac-api-spec/tree/release/v1.0.0/ogcapi-features#collection-items-collectionscollectioniditems) +pub async fn item( + State(api): State>, + Path((collection_id, item_id)): Path<(String, String)>, +) -> Response { + match api.item(&collection_id, &item_id).await { + Ok(option) => { + if let Some(item) = option { + let mut response = Json(item).into_response(); + let _ = response + .headers_mut() + .insert(CONTENT_TYPE, HeaderValue::from_static(APPLICATION_GEO_JSON)); + response + } else { + ( + StatusCode::NOT_FOUND, + format!( + "no item with id='{}' in collection='{}'", + item_id, collection_id + ), + ) + .into_response() + } + } + Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, format!("{}", err)).into_response(), + } +} + +/// Returns the GET `/search` endpoint from the [item search conformance +/// class](https://github.com/radiantearth/stac-api-spec/tree/release/v1.0.0/item-search) +pub async fn get_search( + State(api): State>, + search: Query, +) -> Response { + match Search::try_from(search.0).and_then(Search::valid) { + Ok(search) => match api.search(search, Method::GET).await { + Ok(item_collection) => { + let mut response = Json(item_collection).into_response(); + let _ = response + .headers_mut() + .insert(CONTENT_TYPE, HeaderValue::from_static(APPLICATION_GEO_JSON)); + response + } + Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, format!("{}", err)).into_response(), + }, + Err(err) => (StatusCode::BAD_REQUEST, format!("invalid query: {}", err,)).into_response(), + } +} + +/// Returns the POST `/search` endpoint from the [item search conformance +/// class](https://github.com/radiantearth/stac-api-spec/tree/release/v1.0.0/item-search) +pub async fn post_search( + State(api): State>, + search: Result, JsonRejection>, +) -> Response { + match search + .map_err(|err| err.to_string()) + .and_then(|search| search.0.valid().map_err(|err| err.to_string())) + { + Ok(search) => match api.search(search, Method::POST).await { + Ok(item_collection) => { + let mut response = Json(item_collection).into_response(); + let _ = response + .headers_mut() + .insert(CONTENT_TYPE, HeaderValue::from_static(APPLICATION_GEO_JSON)); + response + } + Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, format!("{}", err)).into_response(), + }, + Err(err) => (StatusCode::BAD_REQUEST, format!("invalid query: {}", err,)).into_response(), + } +} + +#[cfg(test)] +mod tests { + use crate::{Api, Backend, MemoryBackend}; + use axum::{ + body::Body, + http::{header::CONTENT_TYPE, Request, Response, StatusCode}, + }; + use stac::{Collection, Item}; + use tower::util::ServiceExt; + + async fn get(backend: MemoryBackend, uri: &str) -> Response { + let router = super::from_api( + Api::new(backend, "http://stac.test/") + .unwrap() + .id("an-id") + .description("a description"), + ); + router + .oneshot(Request::builder().uri(uri).body(Body::empty()).unwrap()) + .await + .unwrap() + } + + async fn post(backend: MemoryBackend, uri: &str) -> Response { + let router = super::from_api( + Api::new(backend, "http://stac.test/") + .unwrap() + .id("an-id") + .description("a description"), + ); + router + .oneshot( + Request::builder() + .uri(uri) + .method("POST") + .header("Content-Type", "application/json") + .body("{}".to_string()) + .unwrap(), + ) + .await + .unwrap() + } + + #[tokio::test] + async fn root() { + let response = get(MemoryBackend::new(), "/").await; + assert_eq!(response.status(), StatusCode::OK); + assert_eq!( + response.headers().get(CONTENT_TYPE).unwrap(), + "application/json" + ); + } + + #[tokio::test] + async fn service_description() { + let response = get(MemoryBackend::new(), "/api").await; + assert_eq!(response.status(), StatusCode::OK); + assert_eq!( + response.headers().get(CONTENT_TYPE).unwrap(), + "application/vnd.oai.openapi+json;version=3.0" + ); + } + + #[tokio::test] + async fn service_doc() { + let response = get(MemoryBackend::new(), "/api.html").await; + assert_eq!(response.status(), StatusCode::OK); + assert_eq!( + response.headers().get(CONTENT_TYPE).unwrap(), + "text/html; charset=utf-8" + ); + } + + #[tokio::test] + async fn conformance() { + let response = get(MemoryBackend::new(), "/conformance").await; + assert_eq!(response.status(), StatusCode::OK); + assert_eq!( + response.headers().get(CONTENT_TYPE).unwrap(), + "application/json" + ); + } + + #[tokio::test] + async fn collections() { + let response = get(MemoryBackend::new(), "/collections").await; + assert_eq!(response.status(), StatusCode::OK); + assert_eq!( + response.headers().get(CONTENT_TYPE).unwrap(), + "application/json" + ); + } + + #[tokio::test] + async fn collection() { + let response = get(MemoryBackend::new(), "/collections/an-id").await; + assert_eq!(response.status(), StatusCode::NOT_FOUND); + let mut backend = MemoryBackend::new(); + backend + .add_collection(Collection::new("an-id", "A description")) + .await + .unwrap(); + let response = get(backend, "/collections/an-id").await; + assert_eq!(response.status(), StatusCode::OK); + assert_eq!( + response.headers().get(CONTENT_TYPE).unwrap(), + "application/json" + ); + } + + #[tokio::test] + async fn items() { + let response = get(MemoryBackend::new(), "/collections/collection-id/items").await; + assert_eq!(response.status(), StatusCode::NOT_FOUND); + + let mut backend = MemoryBackend::new(); + backend + .add_collection(Collection::new("collection-id", "A description")) + .await + .unwrap(); + backend + .add_item(Item::new("item-id").collection("collection-id")) + .await + .unwrap(); + let response = get(backend, "/collections/collection-id/items").await; + assert_eq!(response.status(), StatusCode::OK); + assert_eq!( + response.headers().get(CONTENT_TYPE).unwrap(), + "application/geo+json" + ); + } + + #[tokio::test] + async fn item() { + let response = get( + MemoryBackend::new(), + "/collections/collection-id/items/item-id", + ) + .await; + assert_eq!(response.status(), StatusCode::NOT_FOUND); + + let mut backend = MemoryBackend::new(); + backend + .add_collection(Collection::new("collection-id", "A description")) + .await + .unwrap(); + backend + .add_item(Item::new("item-id").collection("collection-id")) + .await + .unwrap(); + let response = get(backend, "/collections/collection-id/items/item-id").await; + assert_eq!(response.status(), StatusCode::OK); + assert_eq!( + response.headers().get(CONTENT_TYPE).unwrap(), + "application/geo+json" + ); + } + + #[tokio::test] + async fn get_search() { + let response = get(MemoryBackend::new(), "/search").await; + assert_eq!(response.status(), StatusCode::OK); + assert_eq!( + response.headers().get(CONTENT_TYPE).unwrap(), + "application/geo+json" + ); + } + + #[tokio::test] + async fn post_search() { + let response = post(MemoryBackend::new(), "/search").await; + assert_eq!(response.status(), StatusCode::OK); + assert_eq!( + response.headers().get(CONTENT_TYPE).unwrap(), + "application/geo+json" + ); + } +} diff --git a/stac/CHANGELOG.md b/stac/CHANGELOG.md index 1e39fd89..43e5e4ad 100644 --- a/stac/CHANGELOG.md +++ b/stac/CHANGELOG.md @@ -6,9 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Added + +- `Link::method` and `Link::body` ([#244](https://github.com/stac-utils/stac-rs/pull/244)) + ### Changed -- Use `geojson::Geometry` instead of a crate-specific `Geometry` type([#245](https://github.com/stac-utils/stac-rs/pull/245)) +- Use `geojson::Geometry` instead of a crate-specific `Geometry` type ([#245](https://github.com/stac-utils/stac-rs/pull/245)) ### Removed diff --git a/stac/src/link.rs b/stac/src/link.rs index b0e9444a..960333de 100644 --- a/stac/src/link.rs +++ b/stac/src/link.rs @@ -647,6 +647,42 @@ impl Link { pub fn is_relative(&self) -> bool { !is_absolute(&self.href) } + + /// Sets the method attribute on this link. + /// + /// # Examples + /// + /// ``` + /// use stac::Link; + /// let link = Link::new("href", "rel").method("GET"); + /// ``` + pub fn method(mut self, method: impl ToString) -> Link { + self.method = Some(method.to_string()); + self + } + + /// Sets the body attribute on this link. + /// + /// # Examples + /// + /// ``` + /// use stac::Link; + /// use serde_json::json; + /// + /// let link = Link::new("href", "rel").body(json!({"foo": "bar"})).unwrap(); + /// ``` + pub fn body(mut self, body: T) -> Result { + match serde_json::to_value(body)? { + Value::Object(body) => { + self.body = Some(body); + Ok(self) + } + value => Err(Error::IncorrectType { + actual: value.to_string(), + expected: "object".to_string(), + }), + } + } } fn is_absolute(href: &str) -> bool {