Skip to content

API reference ​

Everything the package documents, grouped by the file it lives in. The guide pages link into this one; this one is the exhaustive listing.

STAC.STAC Module
julia
STAC

A typed STAC 1.1.0 client. STAC.read turns a document into a Catalog, Collection, Item, or ItemCollection whose spec fields are concrete and whose remaining keys round-trip through STAC.json.

source

Objects ​

STAC.ComparedByFields Type
julia
STAC.ComparedByFields

The object types that compare field by field: everything a parse builds. They hold vectors and dictionaries, which Base's === fallback for immutable structs reports as unequal across two parses of the same bytes.

source
STAC.STACObject Type
julia
STAC.STACObject

The four document kinds STAC.read produces.

source
STAC.Asset Type
julia
Asset

A file that belongs to an Item or Collection: where it lives (href), what it is (type, roles, bands), and every other key the producer set (metadata).

  • href: The URI of the file, either absolute or relative to the document that carries it.

  • type: The media type of the file, which is what picks the driver that opens it.

  • title: The displayed title, for clients and users.

  • description: A description of the asset in CommonMark, giving details such as how it was processed or created.

  • roles: The semantic roles of the asset — "thumbnail", "overview", "data", "metadata" — used as rel is on a link.

  • bands: The bands the file holds, one Band each, in file order.

  • metadata: The keys of this asset that no field above names, in document order. Common metadata that overrides the item's (datetime, gsd, platform) and extension keys (eo:cloud_cover, proj:code) both land here.

source
STAC.Band Type
julia
Band

One band description from an Asset's or Item's bands array. The spectral and statistical keys extensions add (eo:common_name, raster:scale, …) stay in metadata, where get(band, EO) reads them from.

  • name: The name of the band ("B01", "band2", "red"), unique across the bands of the object that lists it.

  • description: A description that fully explains the band, in CommonMark.

  • data_type: The data type of the band's values, spelled as the raster data types are: "uint8", "int16", "float32", "cfloat64", and the rest.

  • unit: The unit of measurement of the values, preferably a UDUNITS-2 unit.

  • metadata: The keys of this band that no field above names, in document order.

source
STAC.Catalog Type
julia
Catalog{M}

A STAC Catalog: an id, a description, and the links that form the tree. M is Metadata or NoMetadata, and says whether the parse kept the keys no field names.

  • id: The identifier of the catalog.

  • stac_extensions: The schema URIs of the extensions the catalog declares, which is what STAC.declares answers from.

  • title: A short descriptive one-line title for the catalog.

  • description: A description of the catalog in CommonMark, long enough to fully explain it.

  • links: The references to other documents: the child and item links a traversal walks, and the self, root, and parent links that place this one.

  • metadata: The top-level keys that no field above names, in document order, stac_version among them.

  • href: The absolute location the document was read from, which every relative link resolves against. A catalog built in memory has nothing.

source
STAC.Collection Type
julia
Collection{M}

A STAC Collection: a Catalog that also states what it covers (extent), under what terms (license), and who made it (providers).

  • id: The identifier of the collection, unique within the catalog that holds it, and what STAC.collection and a search's collections filter name.

  • stac_extensions: The schema URIs of the extensions the collection declares, which is what STAC.declares answers from.

  • title: A short descriptive one-line title for the collection.

  • description: A description of the collection in CommonMark, long enough to fully explain it.

  • license: The license of the data, as an SPDX identifier, an SPDX expression, or "other".

  • extent: The space and time the collection covers.

  • keywords: Keywords describing the collection.

  • providers: The organizations that captured, produced, processed, or host the data, in that order.

  • summaries: What the collection's items hold, one entry per property: a set of values, a range, or a JSON Schema. Producers use it to drive faceted search interfaces.

  • assets: The files that belong to the collection as a whole — an overview thumbnail, a license document — keyed as the producer keyed them.

  • links: The references to other documents: the child and item links a traversal walks, and the self, root, and parent links that place this one.

  • metadata: The top-level keys that no field above names, in document order, stac_version and item_assets among them.

  • href: The absolute location the document was read from, which every relative link resolves against. A collection built in memory has nothing.

source
STAC.CollectionExtent Type
julia
CollectionExtent

The space and time a Collection covers.

  • spatial: Where the collection has data.

  • temporal: When the collection has data.

  • metadata: The keys of this extent that no field above names, in document order.

source
STAC.Item Type
julia
Item{E,G,M}

A STAC Item, and the type everything else in this package is built on. Three parse keywords become the three parameters, so a vector of items has one element type.

ParameterKeywordHolds
Eextensionsa NamedTuple keyed by extension prefix, e.g. @NamedTuple{eo::Union{EO,Nothing}, proj::Union{Projection,Nothing}}
Ggeometrythe geometry types this catalog can produce, e.g. Union{Nothing, GeoJSON.Polygon{2,Float64}, GeoJSON.MultiPolygon{2,Float64}}
MmetadataMetadata or NoMetadata, for both the item's own tail and properties.other
  • id: The provider's identifier for the item, unique within the collection that holds it.

  • stac_extensions: The schema URIs of the extensions the item declares, which is what STAC.declares answers from. It has a field of its own rather than a place in the metadata tail so that metadata = false neither loses it on a write nor makes declares report an extension the document does declare as absent.

  • geometry: The footprint of the item's assets in WGS 84 longitude/latitude, as the GeoJSON.jl geometry G names. An item that states no location has nothing, and the STAC API's spatial filters skip it.

  • bbox: The bounding box of the footprint, 4 numbers ((west, south, east, north)) or 6 ((west, south, min elevation, east, north, max elevation)). It is nothing exactly when geometry is.

  • properties: The item's common metadata, and the tail of property keys no field of it names.

  • links: The references to other documents: the collection, parent, and root links a traversal walks up, and the self link that places this one.

  • assets: The files the item describes, keyed as the producer keyed them ("B01", "visual", "thumbnail"), in document order.

  • collection: The id of the Collection the item belongs to, which the collection link points at.

  • extensions: The extensions parsed eagerly into fields, one per prefix the extensions keyword named: item.extensions.eo.cloud_cover is a concrete field read. An extension whose keys the item carries none of reports nothing.

  • metadata: The top-level keys that no field above names, in document order, stac_version among them. An item's extension keys sit one level down, in properties.other.

  • href: The absolute location the document was read from, which every relative link and asset href resolves against. An item built in memory has nothing.

source
STAC.ItemCollection Type
julia
ItemCollection{E,G,M}
STAC.ItemCollection(features; links, numberMatched, numberReturned, metadata, href)

One page of a search, or any GeoJSON FeatureCollection of STAC items.

The keyword form wraps a vector of items — ItemCollection(items) is a page of them and nothing else. Each keyword defaults to what a hand-built collection carries:

keyworddefault
linksLink[]
numberMatchednothing, since only the endpoint that ran the query knows the total
numberReturnedlength(features)
metadatathe empty tail of M, so STAC.json writes no extra keys
hrefnothing
  • features: The items on this page, in the order the producer returned them.

  • links: The references related to the page, next among them, which is how STAC.pages asks for the one after it.

  • numberMatched: How many items met the search parameters, over every page, as the endpoint counted or estimated them. Endpoints that decline to count report nothing.

  • numberReturned: How many items this page holds.

  • metadata: The top-level keys that no field above names, in document order.

  • href: The absolute location the page was read from, which every relative link resolves against. A page built in memory has nothing.

source
STAC.Link Type
julia
Link

One entry of a STAC object's links array. href is kept exactly as the producer wrote it; resolution against the owning object's origin happens at traversal time, in STAC.resolve.

method, headers, body, and merge turn a link into a request template, which is how STAC API pagination describes the next page.

  • href: The link itself, either absolute or relative to the document that carries it. A trailing slash is significant.

  • rel: The relationship between the linked document and this one: "self", "root", "parent", "child", "item", "next", and whatever else the producer uses.

  • type: The media type of the linked document.

  • title: A human readable title for the link, for rendered displays of it.

  • method: The HTTP method the next request uses, "GET" or "POST"; nothing means "GET".

  • headers: The headers to send with the request, as a Metadata map, since a header value is either a string or a list of strings.

  • body: The body to send with a POST, as the parsed JSON value.

  • merge: Whether the body merges into the original request body (true) or replaces it (false, the default a nothing stands for).

  • metadata: The keys of this link that no field above names, in document order.

source
STAC.Properties Type
julia
Properties{M}

The common metadata of an Item: the properties object, with a typed slot for every field the STAC common metadata names. Keys from extensions with no struct and producer-specific keys land in other, whose type M is Metadata or NoMetadata.

  • datetime: The searchable instant of the item's assets, in UTC. nothing says the item covers a span instead, which start_datetime and end_datetime give.

  • start_datetime: The first instant of the span the item covers, in UTC.

  • end_datetime: The last instant of the span the item covers, in UTC.

  • created: When the metadata was created, in UTC.

  • updated: When the metadata was last updated, in UTC.

  • title: A human-readable one-line title for the item.

  • description: A description of the item in CommonMark, long enough to fully explain it.

  • platform: The name of the specific platform the instrument rides on, such as "landsat-8".

  • instruments: The instruments or sensors the data came from, such as ["oli", "tirs"].

  • constellation: The constellation the platform belongs to, such as "sentinel-2".

  • mission: The mission the data was collected for.

  • gsd: The ground sample distance at the sensor, in metres, greater than zero.

  • license: The license of the data, as an SPDX identifier, an SPDX expression, or "other".

  • providers: The organizations that captured, produced, processed, or host the data, in that order.

  • keywords: Keywords describing the item.

  • bands: The bands the item's assets hold, one Band each.

  • other: The property keys that no field above names, in document order: extension keys with no eager slot, and everything the producer invented.

source
STAC.Provider Type
julia
Provider

An organization that captured, produced, processed, or hosts the data.

  • name: The name of the organization or the individual.

  • description: Further provider information, in CommonMark: processing details for a processor or producer, hosting details for a host, contact information for anyone.

  • roles: What the provider did, drawn from "licensor", "producer", "processor", and "host". The last element is the one that supplied the data at this location.

  • url: The homepage on which the provider describes the dataset and publishes contact information.

  • metadata: The keys of this provider that no field above names, in document order.

source
STAC.SpatialExtent Type
julia
SpatialExtent

Where a Collection has data.

  • bbox: The bounding boxes the collection covers, each of 4 numbers ([west, south, east, north]) or 6 ([west, south, min elevation, east, north, max elevation]) in WGS 84. The first box is the overall extent; any that follow describe it more precisely. A box that crosses the antimeridian has a west greater than its east.

  • metadata: The keys of this extent that no field above names, in document order.

source
STAC.TemporalExtent Type
julia
TemporalExtent

When a Collection has data.

  • interval: The intervals the collection covers, each of two instants in UTC. The first interval is the overall extent; any that follow describe it more precisely. An open end is nothing.

  • metadata: The keys of this extent that no field above names, in document order.

source
STAC.fieldsequal Method
julia
STAC.fieldsequal(a::T, b::T) -> Bool
STAC.fieldsisequal(a::T, b::T) -> Bool
STAC.fieldshash(x, h::UInt) -> UInt

Field-by-field ==, isequal, and hash for an immutable struct, unrolled over its fields at compile time: getfield(x, i) over a runtime i infers as Any and boxes every field.

The three keep the semantics their names promise, which for a struct holding Float64 fields means == and isequal part ways on NaN, exactly as they do on the numbers themselves:

xx == xisequal(x, x)
an item whose bbox is finitetruetrue
an item whose bbox holds a NaNfalsetrue

isequal and fieldshash agree, so an object is usable as a Dict key and unique over a vector of them means what it says.

source
STAC.AnyMetadata Type
julia
STAC.AnyMetadata

The tail of a STAC object — the keys no struct field names — as an AbstractDict{String,Any}. Two types inhabit it, and they are the two values the M parameter of Item, Catalog, Collection, and Properties takes:

TypeParsed withHolds
Metadatametadata = trueevery unnamed key, in document order
NoMetadatametadata = falsenothing, and proves it in the type

Both answer the AbstractDict interface, so a tail indexes, iterates as key => value, and passes to anything that takes a dictionary.

source
STAC.Metadata Type
julia
STAC.Metadata(data::JSON.Object{String,Any})
STAC.Metadata()

The keys of a STAC object that no struct field names, kept in document order so that STAC.json writes them back where the producer put them. Extension keys with no struct, producer-specific keys, and stac_version all land here.

julia
julia> using JSON

julia> m = STAC.Metadata(JSON.Object{String,Any}("s2:mgrs_tile" => "59UNT"))
Metadata("s2:mgrs_tile")

julia> m["s2:mgrs_tile"], get(m, "eo:cloud_cover", nothing)
("59UNT", nothing)
source
STAC.NoMetadata Type
julia
STAC.NoMetadata()

The tail of an object parsed with metadata = false: unnamed keys were skipped during the parse, so the type itself proves that nothing unknown was kept. It is an empty AbstractDict, and a singleton, so carrying one costs no memory.

source

Extensions ​

STAC.Extension Type
julia
STAC.Extension

Supertype of the structs that give a STAC extension typed fields. An extension is one struct whose field names are the keys after the prefix, plus STAC.prefix and STAC.schema:

julia
struct EO <: STAC.Extension
    cloud_cover::Union{Float64,Nothing}
    snow_cover::Union{Float64,Nothing}
end
STAC.prefix(::Type{EO}) = "eo"
STAC.schema(::Type{EO}) = "https://stac-extensions.github.io/eo/v2.0.0/schema.json"

Passing the struct to extensions = makes item.extensions.eo.cloud_cover a concrete field read; see STAC.extensiontype.

source
Base.get Method
julia
get(obj, T::Type{<:Extension}) -> Union{T,Nothing}
T(obj) -> T

The extension T of an Item, Asset, Band, Catalog, or Collection. get reports nothing when the object carries none of T's keys; the constructor form throws instead.

CallSource
item.extensions.eothe eager field, when extensions = named STAC.EO
get(item, STAC.EO)that field when it exists, else a lookup in properties.other
STAC.EO(item)the same, throwing when the item carries no eo: key
STAC.Projection(asset)a lookup in the asset's own metadata

An item parsed with metadata = false kept no tail, so a lookup on one finds nothing: the keys were dropped at parse time rather than being absent from the document.

julia
item = STAC.read("test/fixtures/stac-spec/extended-item.json"; extensions = (STAC.EO,))
item.extensions.eo.cloud_cover    # 1.2, the eager field
get(item, STAC.View)              # STAC.View(3.8, …), read from the tail
STAC.View(item).off_nadir         # 3.8, or a `STAC.MissingExtension` if there is none
get(item, STAC.Sat) === nothing   # true: the item carries no `sat:` key
source
STAC.declares Method
julia
STAC.declares(obj, T::Type{<:Extension}) -> Bool
STAC.declares(obj, uri::AbstractString) -> Bool

Whether an Item, Catalog, or Collection lists the extension in its stac_extensions. The version segment of the schema URI is ignored, as pystac does, so an item declaring eo/v1.1.0 declares EO even though this package types the 2.0.0 fields.

Declaring an extension and carrying its keys are different questions: STAC.declares reads the list, get(obj, T) reads the keys. Producers get both wrong in both directions.

julia
item = STAC.read("test/fixtures/stac-spec/extended-item.json")
STAC.declares(item, STAC.EO)                 # true, even though the item lists eo v2.0.0
STAC.declares(item, STAC.schema(STAC.EO))    # the same question, asked by URI
STAC.declares(item, STAC.Sat)                # false: `stac_extensions` never names it
source
STAC.extensiontype Method
julia
STAC.extensiontype(extensions::Tuple) -> Type

The E parameter of Item for a tuple of extension structs: a NamedTuple type keyed by each struct's STAC.prefix, with Union{T,Nothing} values so an item that carries none of an extension's keys reports nothing.

julia
julia> STAC.extensiontype((STAC.EO, STAC.Projection))
@NamedTuple{eo::Union{Nothing, STAC.EO}, proj::Union{Nothing, STAC.Projection}}

An empty tuple gives Any, the dynamic form in which every prefixed key stays in properties.other.

source
STAC.exttail Method
julia
STAC.exttail(obj) -> AnyMetadata

Where obj keeps the extension keys no field of it names, which is where an extension with no eager slot is read from.

ObjectTail
Itemproperties.other, since an item's extension keys live inside properties
Asset, Band, Catalog, Collectionmetadata, the object's own unnamed keys
source
STAC.fromtail Method
julia
STAC.fromtail(T, tail) -> Union{T,Nothing}

The extension T built by looking each of its fields up as "prefix:field" in tail, or nothing when the tail holds none of them. This is the one function behind every access path that is not an eager field read.

A field whose key is present is lifted to the field's type through the parse style, so a DateTime field reads an RFC 3339 string and a Float64 field reads a JSON integer. Every field of an extension struct is therefore Union{…,Nothing}: an absent key has to be representable.

source
STAC.prefix Function
julia
STAC.prefix(::Type{<:Extension}) -> String

The prefix: an extension's keys carry inside properties, without the colon.

source
STAC.schema Function
julia
STAC.schema(::Type{<:Extension}) -> String

The schema URI an object lists in stac_extensions to declare the extension.

source
STAC.schemaparts Method
julia
STAC.schemaparts(uri) -> (head, rest)

A schema URI split around its version segment, or (uri, "") when it has none. The two halves are what STAC.declares compares, so that any version of the same schema matches.

source
STAC.EO Type
julia
EO

The Electro-Optical extension, version 2.0.0. Band descriptions moved into core bands in STAC 1.1, leaving the two cloud and snow fractions.

source
STAC.Projection Type
julia
Projection

The Projection extension, version 2.0.0: the native grid an item's assets are on.

code ("EPSG:32610") is the 2.0.0 spelling and epsg the 1.x one; producers still emit either, so both are read. shape and transform are what a reader needs to place the grid without opening a file.

source
STAC.Raster Type
julia
Raster

The Raster extension, version 2.0.0: how the pixels of one band map onto the values they stand for.

These are band and asset keys rather than item keys, so Raster(asset) and Raster(band) are the access paths that find them; an item carrying none reports nothing. Two shapes stay on the tail: raster:histogram, a nested object, and raster:bands, the 1.1.0 array whose entries moved into the core bands field in STAC 1.1.

Raster is not exported, because Rasters.jl exports a Raster of its own and Raster(asset) opening a COG is the call that matters in a session where both are loaded.

source
STAC.Sat Type
julia
Sat

The Satellite extension, version 1.1.0: which satellite took the scene and where it was on its orbit.

orbit_state is one of "ascending", "descending", or "geostationary". sat:orbit_state_vectors, an array of position objects, has no typed slot and stays on the tail, from where STAC.json writes it back unchanged.

source
STAC.View Type
julia
View

The View Geometry extension, version 1.0.0: where the sensor and the sun were when the scene was taken, every angle in degrees.

off_nadir, incidence_angle, and azimuth describe the sensor, sun_azimuth and sun_elevation the illumination.

source
STAC.Scientific Type
julia
Scientific

The Scientific Citation extension, version 1.0.0: how to cite the data.

sci:publications, a list of {doi, citation} objects, has no typed slot and stays on the tail. Collections carry these keys at the top level, so Scientific(collection) reads them from the collection's metadata while Scientific(item) reads them from its properties.

source

Documents, traversal, and the API client ​

STAC.doctype Method
julia
STAC.doctype(doc::JSON.LazyValue) -> String

The value of a document's type key, which is what selects the struct a parse targets.

The scan is a callable sink for the reason the parse sinks are: applyeach forwards its function argument, and a closure there compiles unspecialized.

source
STAC.parse Method
julia
STAC.parse(bytes; extensions, geometry, metadata) -> Catalog | Collection | Item | ItemCollection
STAC.parse(bytes, T::Type)
STAC.parse(bytes, opts::ParseOptions)

A STAC document from JSON bytes, a String, or a JSON.LazyValue sub-document. The one- argument form reads the document's type key and dispatches on it; passing T names the target type instead and is inferable.

The keywords are ParseOptions's.

source
STAC.read Method
julia
STAC.read(href; io = STAC.default_io(), extensions, geometry, metadata)
    -> Catalog | Collection | Item | ItemCollection

The STAC document at href, with its origin recorded so children and items can resolve its relative links. href is a local path, an https:// URL, or anything else the io stack routes; a local path is made absolute first.

The document's type key selects the struct; the keywords are ParseOptions's.

julia
item = STAC.read("test/fixtures/stac-spec/extended-item.json")
item.id                             # "20201211_223832_CS2"
item.extensions.eo.cloud_cover      # 1.2
item.properties.datetime            # DateTime("2020-12-14T18:02:31.437")

cat = STAC.read("test/fixtures/static/self-contained/catalog.json")
[c.id for c in STAC.children(cat)]  # ["simple-collection", "empty-collection"]
source
STAC.read Method
julia
STAC.read(asset::Asset; io = STAC.default_io())

The GeoJSON an asset holds, as the GeoJSON.jl object its type key names: a FeatureCollection for a footprint file, a Feature or a geometry for a single shape.

The bytes come through the IO stack, so an asset behind credentials reads with them and an asset on s3:// reads through whatever route the stack has for that scheme. A raster asset raises a STAC.NotGeoJSONAsset naming the driver that does open it.

julia
asset = STAC.Asset("/data/footprint.geojson", "application/geo+json",
                   nothing, nothing, ["metadata"], nothing, STAC.NoMetadata())
fc = STAC.read(asset)               # GeoJSON.FeatureCollection
GeoInterface.nfeature(fc)           # however many shapes the file holds
source
STAC.rebuild Method
julia
STAC.rebuild(obj, Val(:field), value) -> obj

obj with one field replaced. Only the outer struct is rebuilt; every other field is shared with the original, and the field is chosen at compile time, so this costs one allocation.

julia
item = STAC.read("test/fixtures/stac-spec/simple-item.json")
STAC.rebuild(item, Val(:links), STAC.Link[]).id == item.id    # true
source
STAC.sethref Method
julia
STAC.sethref(obj, href) -> obj

obj with its origin set to href. Only the outer struct is rebuilt; every field is shared with the original.

source
STAC.LinkIterator Type
julia
STAC.LinkIterator{T}(links, base, io, opts)

The lazy iterator behind children and items. Nothing is fetched until an element is reached, so length costs no requests and first costs exactly one.

base is the origin of the object the links came from, which is what STAC.resolve resolves each relative href against.

source
STAC.RecursiveItems Type
julia
STAC.RecursiveItems

The depth-first walk behind items(obj; recursive = true). It carries the child hrefs it has yet to visit rather than the fetched objects, so a container is fetched only when the walk reaches it.

source
Base.parent Method
julia
parent(obj, opts::ParseOptions; io = STAC.default_io())
parent(obj; io = STAC.default_io(), extensions, geometry, metadata)

The catalog or collection obj's parent link points at, or nothing when it has none.

julia
col = STAC.read("test/fixtures/static/self-contained/simple-collection/collection.json")
parent(col).id                      # "examples", the catalog above it
parent(parent(col)) === nothing     # true: the root has no parent
source
STAC.children Method
julia
STAC.children(obj; io = STAC.default_io(), extensions, geometry, metadata) -> LinkIterator
STAC.children(obj, opts::ParseOptions; io = STAC.default_io())

The child links of a Catalog or Collection, as a lazy iterator of the catalogs and collections they point at. Each element's struct is chosen by that document's own type key.

The keywords are ParseOptions's, plus io, the AbstractIO that fetches.

julia
cat = STAC.read("test/fixtures/static/self-contained/catalog.json")
length(STAC.children(cat))              # 2, from the link count, before any request
[c.id for c in STAC.children(cat)]      # ["simple-collection", "empty-collection"]
source
STAC.items Method
julia
STAC.items(obj; recursive = false, io = STAC.default_io(), extensions, geometry, metadata)
STAC.items(obj, opts::ParseOptions; recursive = false, io = STAC.default_io())

The Items of a catalog or collection, as a lazy iterator.

recursiveYields
falsethe item links of obj itself
truethe same, then every descendant's, depth first through children

The recursive form fetches one document per object it reaches and no more, so a walk of a rate-limited catalog costs exactly as many requests as it visits documents.

julia
cat = STAC.read("test/fixtures/static/self-contained/catalog.json")
[i.id for i in STAC.items(cat)]                         # ["collectionless-item"]
length(collect(STAC.items(cat; recursive = true)))      # 4, the descendants' as well
first(STAC.items(cat; recursive = true)).properties.datetime
source
STAC.read Method
julia
STAC.read(T, href, io, opts) -> T

The document at href, fetched through io, parsed as T, and stamped with href as its origin. This is the one fetch every traversal call goes through.

source
STAC.readdoc Method
julia
STAC.readdoc(T, bytes, opts) -> T

bytes parsed as T. A concrete T is the parse target directly; anything wider (the Union{Catalog{M},Collection{M}} a child link can point at) is decided by the document's own type key.

source
STAC.rellinks Method
julia
STAC.rellinks(obj, rel) -> Vector{Link}

The links of obj whose rel is rel, in document order.

source
STAC.root Method
julia
STAC.root(obj, opts::ParseOptions; io = STAC.default_io())
STAC.root(obj; io = STAC.default_io(), extensions, geometry, metadata)

The catalog or collection obj's root link points at, or nothing when it has none.

julia
col = STAC.read("test/fixtures/static/self-contained/simple-collection/collection.json")
STAC.root(col).id                   # "examples", however deep `col` sits
source
STAC.GENERIC_HOST Constant
julia
STAC.GENERIC_HOST

The spec's own limits, used for an endpoint no STAC.HOST_DEFAULTS pattern matches.

source
STAC.HOST_DEFAULTS Constant
julia
STAC.HOST_DEFAULTS

The recorded quirks of the endpoints this package was probed against, most specific pattern first. Add to it from an __init__ to teach the package about another deployment.

source
STAC.Client Type
julia
STAC.Client(url; auth = STAC.NoAuth(), io = STAC.defaultstack(auth), host = nothing)

A STAC API, opened by reading its landing page once. The client holds that catalog, the conformsTo list it advertises, the AbstractIO every later call fetches through, and the HostDefaults matched from url.

The landing page is always parsed keeping its metadata tail, because conformsTo is not a Catalog field; the parse options of search and collections are per call.

julia
client = STAC.Client("https://planetarycomputer.microsoft.com/api/stac/v1")
client.root.id                                  # "microsoft-pc"
STAC.conforms(client, "item-search")            # true
client.host.max_limit                           # 1000, from the recorded host table
first(STAC.search(client; collections = ["sentinel-2-l2a"], limit = 10)).id

A credentialed endpoint takes an STAC.AbstractAuth through auth =, and every later call fetches with it.

source
STAC.HostDefaults Type
julia
STAC.HostDefaults(max_limit, default_limit, reports_matched, dotdot_ok)

What one endpoint does with the four things STAC API 1.0.0 leaves to the server. A Client matches one from STAC.HOST_DEFAULTS at construction, and a caller who knows better passes their own as host =.

FieldMeaning
max_limitthe largest limit the endpoint accepts; search clamps to it
default_limitthe page size to ask for when the caller names none
reports_matchedwhether a page carries a total, so matched is worth a request
dotdot_okwhether a .. segment in a path survives the endpoint's gateway
source
STAC.collection Method
julia
STAC.collection(client, id; extensions, geometry, metadata) -> Collection

One collection by id, from <data href>/<id>.

julia
client = STAC.Client("https://earth-search.aws.element84.com/v1")
col = STAC.collection(client, "sentinel-2-l2a")
col.extent.spatial.bbox[1]          # the collection's footprint, as a bbox
first(STAC.items(client, col)).id   # its first item, through /collections/<id>/items
source
STAC.collections Method
julia
STAC.collections(client; extensions, geometry, metadata) -> Vector{Collection}

Every collection the endpoint's data link lists, each stamped with its own self href.

The keywords are ParseOptions's. Endpoints page /collections; this reads the first page only, which is every collection on all six endpoints probed.

julia
client = STAC.Client("https://earth-search.aws.element84.com/v1")
cols = STAC.collections(client)
[c.id for c in cols]                # "sentinel-2-l2a", "landsat-c2-l2", …
first(cols).href                    # its own `self` href, so its links resolve
source
STAC.conformanceclasses Method
julia
STAC.conformanceclasses(root::Catalog) -> Vector{String}

The conformsTo array of a landing page, which the parse leaves in the catalog's metadata tail. An endpoint that publishes none gives an empty vector.

The two isa checks name the concrete types the parse stores, Vector{Any} of String: a tail value is Any, so a check against AbstractVector would leave the loop over it a dynamic dispatch, which --trim=safe reports as an unresolved call.

source
STAC.conforms Method
julia
STAC.conforms(client, class) -> Bool

Whether the endpoint advertises a conformance class. A full URI must match an entry exactly; a short name such as "item-search" or "item-search#filter" matches any version, since endpoints publish the same class under v1.0.0, v1.0.0-rc.2, and the OGC URIs side by side.

julia
STAC.conforms(client, "item-search")                            # any version
STAC.conforms(client, "https://api.stacspec.org/v1.0.0/core")   # exactly this one
source
STAC.host_defaults Method
julia
STAC.host_defaults(url) -> HostDefaults

The HostDefaults recorded for url's host, or STAC.GENERIC_HOST.

source
STAC.itemshref Method
julia
STAC.items(client, collection_id; limit, datetime, bbox, extensions, geometry, metadata)
STAC.items(client, collection::Collection; …)
STAC.items(client, collection_id, opts::ParseOptions; …)

The items of one collection through the OGC API - Features endpoint (/collections/<id>/items), as an AbstractItemSearch: a lazy iterator of Items that follows next links.

This is the GET twin of search and takes the same spatial and temporal keywords; collections and ids are not among them, since the path already names the collection.

source
STAC.linkhref Method
julia
STAC.linkhref(obj, rel; method = nothing) -> Union{String,Nothing}

The href of obj's first link with this rel, resolved against obj's origin. When method is given, a link that names a different one is skipped, which is how the two search links of a landing page are told apart.

source
STAC.selfhref Method
julia
STAC.selfhref(obj) -> Union{String,Nothing}

The absolute self href obj publishes, or nothing. This is the origin an object fetched as part of a larger document (one entry of /collections) gets stamped with.

source
STAC.AbstractItemSearch Type
julia
STAC.AbstractItemSearch

A prepared item search. A backend implements pages, which yields ItemCollection values lazily, and everything a caller does with the search — iterating items, Iterators.take, collect — derives from it.

MethodContract
STAC.pages(s)an iterator of ItemCollection, one per request; required
STAC.matched(s)the total the endpoint reports, or nothing; optional

IteratorSize is SizeUnknown(), so first and take fetch only the pages they reach.

julia
first(s)                          # one item, one request
collect(Iterators.take(s, 5))     # five items, however many pages that takes
collect(STAC.pages(s))            # every page, to the end of the result set
source
STAC.ItemSearchState Type
julia
STAC.ItemSearchState

Where a search is inside its pages: the page iterator and its state, the page in hand, and how many of that page's items have been yielded.

source
STAC.TimeInterval Type
julia
STAC.TimeInterval

The window a static search keeps items inside: NTuple{2,Union{DateTime,Nothing}}, with nothing for an open side.

source
STAC.build_body Method
julia
STAC.build_body(; collections, ids, intersects, datetime, query, filter, filter_lang,
                sortby, fields, limit) -> JSON.Object{String,Any}

The POST body of one item search, with only the keys the caller named plus limit. This is the request the paging loop merges each next link into.

source
STAC.classify Method
julia
STAC.classify(intersects) -> (kind, value)

What a spatial argument becomes in a request body: (:none, nothing), (:bbox, numbers), or (:intersects, geojson). Supplying both a bbox and an intersects is a 400 at every endpoint, so one argument carries both and its type decides.

Argumentkind
nothing:none
Extents.Extent with X/Y, optionally Z:bbox
a tuple or vector of 4 or 6 numbers:bbox
any GeoInterface geometry:intersects
julia
STAC.classify(Extent(X = (-123, -122), Y = (37, 38)))    # (:bbox, [-123.0, 37.0, -122.0, 38.0])
STAC.classify((-123, 37, -122, 38))                      # the same bbox, as four numbers
STAC.classify(GeoJSON.read(read("aoi.geojson", String))) # (:intersects, a Float64 GeoJSON polygon)
source
STAC.datetime_interval Method
julia
STAC.datetime_interval(x) -> NTuple{2,Union{DateTime,Nothing}}

A datetime argument as the pair of instants a client-side filter compares against, with nothing for an open side. This is the counterpart of STAC.normalize_datetime, which sends the same argument to a server; both read a bare date as the whole day.

julia
STAC.datetime_interval(Date(2024, 6, 1))    # (DateTime(2024, 6, 1), DateTime(2024, 6, 1, 23, 59, 59, 999))
STAC.datetime_interval("2024-06-01/..")     # (DateTime(2024, 6, 1), nothing)
source
STAC.geojsongeometry Method
julia
STAC.geojsongeometry(geom) -> GeoJSON.AbstractGeometry

Any GeoInterface geometry as the Float64 GeoJSON geometry a request body carries. This is what lets intersects = take a geometry from any package in the stack.

numbertype = Float64 is the load-bearing part: GeoJSON.jl reads positions as Float32 by default, and a longitude rounded to seven digits searches a different place than the caller asked for. ndim comes from the geometry, since the reader's own 2D-then-3D retry warns.

source
STAC.intimerange Method
julia
STAC.intimerange(item, interval::STAC.TimeInterval) -> Bool

Whether an item falls in a search's window. An item with a datetime is one instant; an item with start_datetime and end_datetime is a span, and matches when the two spans overlap. An item that carries neither is outside every closed window.

source
STAC.matched Method
julia
STAC.matched(s::AbstractItemSearch) -> Union{Int,Nothing}

The total number of items a search matches, as the endpoint reports it in numberMatched. One request pays for it, the count living on the first page; a STAC.StaticItemSearch counts exactly, its filtered set being in memory.

nothing is the answer from an endpoint that publishes no total. Planetary Computer and CDSE are the two probed here that page without one, and so does any endpoint whose HostDefaults carries reports_matched = false.

WantWrite
the count, either wayn = STAC.matched(s), then branch on n === nothing
to know before paying a requestSTAC.reportsmatched(s)
the items regardlessiterate the search; paging follows next links with or without a total
julia
s = STAC.search(client; collections = ["sentinel-2-l2a"], datetime = Date(2024, 6, 1))
n = STAC.matched(s)
# `n > 100` would be a MethodError on an endpoint that publishes no total.
n === nothing ? "an unknown number of items" : string(n, " items")

Printing s says which of the two answers to expect, and makes no request to find out.

source
STAC.nextlink Method
julia
STAC.nextlink(page::ItemCollection) -> Union{Link,Nothing}

The next link of a page, which is a whole request template: method, headers, body, and merge all describe how to ask for the page after this one.

source
STAC.normalize_datetime Method
julia
STAC.normalize_datetime(x) -> Union{String,Nothing}

A datetime argument as the RFC 3339 string a STAC API takes.

ArgumentSent
nothingnothing; the search is unbounded in time
DateTimethe instant, in UTC, ending in Z
Datethe full-day interval, because four of five endpoints probed reject a date-only string
(start, stop) of DateTime, Date, or nothingstart/stop, an open side written ..
Stringpassed through unchanged
julia
STAC.normalize_datetime(DateTime(2024, 6, 1))            # "2024-06-01T00:00:00Z"
STAC.normalize_datetime(Date(2024, 6, 1))                # "2024-06-01T00:00:00Z/2024-06-01T23:59:59.999Z"
STAC.normalize_datetime((DateTime(2024, 6, 1), nothing)) # "2024-06-01T00:00:00Z/.."
source
STAC.numbermatched Method
julia
STAC.numbermatched(page::ItemCollection) -> Union{Int,Nothing}

The total a page reports, from numberMatched or from the deprecated context.matched that the CMR endpoints still send.

source
STAC.pages Function
julia
STAC.pages(s::AbstractItemSearch)

The pages of a search, as a lazy iterator of ItemCollection. One element is one request: the first is the search itself, each further one follows the previous page's next link.

julia
page = first(STAC.pages(s))       # one request
page.features                     # the items it carried
page.numberReturned               # how many that is
source
STAC.percentencode Method
julia
STAC.percentencode(s::String) -> String

s percent-encoded for one query string field, byte by byte, escaping everything outside RFC 3986's unreserved set.

URIs.escapeuri does the same job through join over a generator, whose annotated-string path costs ten --trim=safe verifier errors; this loop costs none and allocates one buffer.

source
STAC.predicate Method
julia
STAC.predicate(intersects) -> Union{DE9IM.DE9IMPredicate,Nothing}

The DE-9IM predicate an intersects argument carries, or nothing when it is a plain geometry, extent, or bbox. A search that has one runs it over every page it receives.

source
STAC.querystring Method
julia
STAC.querystring(body) -> String

A search body as the query string its GET form takes: lists comma-joined, anything nested (intersects, filter, query) as JSON, everything percent-encoded.

julia
STAC.querystring(STAC.build_body(; collections = "sentinel-2-l2a", limit = 2))
# "collections=sentinel-2-l2a&limit=2"
source
STAC.queryvalue Method
julia
STAC.queryvalue(v) -> String

One value of a search body as a query string spells it: a list of scalars comma-joined, anything nested as JSON, a scalar as itself.

This is one method over a ladder of isa checks rather than one method per type, because the values of a body are Any: a set of methods makes every read of one a dynamic dispatch, which --trim=safe reports as an unresolved call.

source
STAC.reportsmatched Method
julia
STAC.reportsmatched(s::AbstractItemSearch) -> Bool

Whether matched answers this search with a number. A backend knows before it asks — an API search from its host's reports_matched flag, a static search from its own walk — so this costs no request.

source
STAC.APIItemSearch Type
julia
STAC.APIItemSearch

A search against a STAC API, as one prepared request plus the parse options its pages are read with. Build one with search or items; iterate it for items, or pages it for whole ItemCollections.

predicate holds the DE-9IM predicate an intersects = argument carried, and every page is filtered through it on the sphere before the caller sees it.

source
STAC.PageIterator Type
julia
STAC.PageIterator

The paging loop of an STAC.APIItemSearch: one element per request, each one the next link of the previous page.

source
STAC.PageState Type
julia
STAC.PageState

The request the next iterate of a STAC.PageIterator will make, rewritten in place from each page's next link.

source
STAC.StaticItemSearch Type
julia
STAC.StaticItemSearch

A search over a catalog on disk or on a plain web server, as the walk it will make plus the filters it will apply. It answers the same pages protocol as STAC.APIItemSearch, so iteration, Iterators.take, and matched behave the same on both. Build one with search.

The walk, the filters, and the index run once, on the first page asked for, and the result is kept: STAC.matched(s) after collect(s) costs nothing.

source
STAC.StaticPages Type
julia
STAC.StaticPages

The pages of a STAC.StaticItemSearch: the matching items cut into chunks of limit, each one an ItemCollection reporting the exact total.

source
STAC.check_conformance Method
julia
STAC.check_conformance(client; filter, query, sortby, fields)

Raise unless the endpoint advertises every conformance class the request needs. The error names the missing class, so a request that cannot work fails at the call site rather than as a 400 pages later.

Argument givenClass required
any searchitem-search
filteritem-search#filter
queryitem-search#query
sortbyitem-search#sort
fieldsitem-search#fields
source
STAC.featuresearch Method
julia
STAC.featuresearch(client, href; …) -> APIItemSearch
STAC.featuresearch(client, href, opts::ParseOptions; …)

A GET search against an OGC API - Features items endpoint, which is what STAC.items(client, collection) returns. The keywords are search's, minus the ones the path already fixes.

source
STAC.filterpage Method
julia
STAC.filterpage(predicate, page::ItemCollection) -> ItemCollection

page with only the items the predicate holds for, evaluated on the sphere. numberMatched stays as the endpoint reported it, since that is a property of the request rather than of what survived; numberReturned counts what is left.

source
STAC.nextbody Method
julia
STAC.nextbody(link, original) -> Union{JSON.Object{String,Any},Nothing}

The body of the request a next link describes. merge: true means the link carries only the keys that changed, so they go on top of the search's original body; the default, merge: false, means the link's body is the whole request.

source
STAC.search Method
julia
STAC.search(client; collections, ids, intersects, datetime, query, filter, filter_lang,
            sortby, fields, limit, method, extensions, geometry, metadata) -> APIItemSearch
STAC.search(client, opts::ParseOptions; …)

A prepared item search. Nothing is fetched until the result is iterated, so building a search costs no request.

KeywordTakes
collections, idsa string or a list of strings
intersectsa GeoInterface geometry, an Extents.Extent, a bbox of 4 or 6 numbers, or a DE-9IM predicate wrapping any of those
datetimesee STAC.normalize_datetime
query, filter, filter_lang, fieldsthe extension bodies, passed through
sortby"-datetime", "+id", a list of those, or the spec's {field, direction} objects
limitthe page size, clamped to the host's cap; the host default when omitted
method"POST" (the default) or "GET"
extensions, geometry, metadataParseOptions's, fixing the item type

The request is checked against the endpoint's conformsTo before it is built, so a filter an endpoint cannot answer raises here rather than 400ing later.

julia
client = STAC.Client("https://earth-search.aws.element84.com/v1")

# a collection, an area, and a window
s = STAC.search(client; collections = ["sentinel-2-l2a"],
                intersects = Extent(X = (-123, -122), Y = (37, 38)),
                datetime = (DateTime(2024, 6, 1), DateTime(2024, 6, 5)), limit = 100)
STAC.matched(s)                   # the total, on an endpoint that reports one

# a geometry goes as `intersects`, in Float64 whatever precision it arrived in
aoi = GeoJSON.read(read("aoi.geojson", String))
STAC.search(client; intersects = aoi, datetime = Date(2024, 6, 1))

# pages arrive as they are reached
collect(Iterators.take(s, 5))     # five items, from one request of 100

STAC.search(client, opts::ParseOptions; …) is the explicit form, matching STAC.children(obj, opts; io). It is what a --trim=safe program calls: the options are a type there, and building one from three keywords inside the call leaves the item type to a runtime computation over DataType values.

source
STAC.search Method
julia
search(catalog; collections, ids, intersects, datetime, limit, manifold, io,
       extensions, geometry, metadata) -> STAC.StaticItemSearch
STAC.search(catalog, opts::ParseOptions; …)

A search over a static Catalog or Collection, with the spatial and temporal keywords STAC.search(client; …) takes. Nothing is fetched until the result is iterated.

KeywordTakes
collections, idsa string or a list of strings
intersectsa GeoInterface geometry, an Extents.Extent, a bbox of 4 or 6 numbers, a SphericalCap, or a DE-9IM predicate wrapping any of those
datetimesee STAC.datetime_interval
limitthe page size; the spec's default of 100 when omitted
manifoldSpherical() (the default) or Planar(), the space the index is built in
iothe AbstractIO the walk fetches through
extensions, geometry, metadataParseOptions's, fixing the item type
julia
cat = STAC.read("catalog.json")

# the walk runs on the first item asked for, and a box across the antimeridian is one box
s = STAC.search(cat; collections = "edges", intersects = Extent(X = (170, -170), Y = (60, 70)))
STAC.matched(s)                   # exact: the filtered set is in memory
first(s).id

# a DE-9IM predicate keeps only the items it holds for, evaluated on the sphere
aoi = GeoJSON.read(read("aoi.geojson", String); numbertype = Float64)
collect(STAC.search(cat; intersects = Within(aoi), datetime = Date(2024, 6, 4)))
source
STAC.staticitems Method
julia
STAC.staticitems(s::StaticItemSearch) -> Vector{Item}

Every item the search matches, in catalog order. The first call walks the catalog — one request per document reached — filters by collection, id, and time, then runs the spatial argument against an index of what is left; later calls read the kept vector.

source

Geometry and the spatial index ​

STAC.WGS84 Constant
julia
STAC.WGS84

The coordinate reference system of every STAC geometry. GeoJSON fixes longitude/latitude on WGS 84, and STAC inherits it.

source
Extents.extent Method
julia
Extents.extent(item::Item) -> Union{Extents.Extent,Nothing}

The item's bbox as an Extents.Extent, in the key order STAC writes it.

bboxKeys
4 numbersX = (west, east), Y = (south, north)
6 numbersthe same, plus Z = (low, high)
absentGeoInterface.extent of the geometry, or nothing when there is no geometry either
source
STAC.bboxextent Method
julia
STAC.bboxextent(bbox) -> Extents.Extent

A STAC bbox tuple as an extent, keeping the elevation interval a 6-number box carries.

source
STAC.float64geometry Method
julia
STAC.float64geometry(x) -> x

x with Float64 positions, which is what every spherical pass takes: the great-circle extent and the DE-9IM predicates run on ExactPredicates, and ExactPredicates raises on Float32. A geometry GeoJSON.jl read arrives as Float32 unless the reader was told otherwise, so this is the normalisation STAC.geojsongeometry already does for a request body.

An Extents.Extent or a SphericalCap describes a place without being a geometry and passes through; every pass that takes one works in Float64 already.

source
STAC.leaf_extent Method
julia
STAC.leaf_extent(manifold, item) -> Union{Extents.Extent,Nothing}

One item's box on manifold, or nothing when the item locates itself nowhere.

The bbox comes first, being the footprint the producer published and the one STAC requires of every item whose geometry is non-null. An item that carries only a geometry gets the rectangle its vertices span through STAC.pointextent, so the leaf is the same kind of box either way.

source
STAC.lift Method
julia
STAC.lift(manifold, input) -> Union{Extents.Extent,Nothing}

A query argument as the box the index built on manifold prunes with. Every input reaches the tree pass through this one function, so a geometry, an extent, and a spherical cap all prune against the same leaves.

InputPlanar()Spherical()
Extents.Extent with X/Ythe same boxthe 3D box of STAC.spherebox
a bbox of 4 or 6 numbersX/Y; elevation is droppedas above
a GeoInterface geometryExtents.extent(Planar(), geom), the vertex rectangleExtents.extent(Spherical(), geom), which follows the great circle between two vertices
Extents.Extent with X/Y/ZX/Yunchanged: already on the unit sphere
SphericalCap, UnitSphericalPointunsupportedunchanged
nothingnothingnothing
source
STAC.pointextent Method
julia
STAC.pointextent(geom) -> Extents.Extent{(:X,:Y)}

The longitude/latitude rectangle a geometry's vertices span, reached through GeoInterface's indexed accessors so that one method resolves per nesting level under --trim=safe.

STAC.leaf_extent is the one caller, and a static binary builds its index leaves with it. Every other rectangle in this file comes from Extents.extent(manifold, geom), whose fold over a Flatten generator the trim verifier cannot resolve.

source
STAC.spherebox Method
julia
STAC.spherebox(west, south, east, north) -> Extents.Extent{(:X,:Y,:Z)}

The 3D Cartesian box on the unit sphere covering a longitude/latitude rectangle, which is what a spherical index prunes with.

west > east means the rectangle crosses the antimeridian, as STAC writes it, and the box covers the short way round. A rectangle reaching a pole gets the whole X/Y disc there, because every longitude meets at the pole.

Interval arithmetic on the rectangle's own edges gives the bounds. Its northern and southern edges are parallels of latitude, which lie equatorward of the great circles Extents.extent(GO.Spherical(), geom) bounds a polygon by.

source
STAC.SpatialIndex Type
julia
STAC.SpatialIndex(tree, items, manifold)

An R-tree over a vector of Items together with the items themselves, so a query can run its exact pass and report positions in the original vector. Build one with spatialindex and search it with STAC.query.

tree is a GeometryOps RTree whose leaves are the items' boxes on manifold, or nothing when no item locates itself anywhere.

source
STAC.query Method
julia
STAC.query(idx::SpatialIndex, input) -> Vector{Int}

The positions in idx.items of every item the query matches, ascending and without repeats.

input is lifted onto the index's manifold by STAC.lift and run against the tree. A DE-9IM predicate from DE9IM.jl — Within(poly), Covers(ext), Disjoint(poly) — adds an exact second pass over the survivors, evaluated by GeometryOps on the same manifold.

nothing matches every item, including the ones the tree leaves out.

julia
using DE9IM, Extents

cat = STAC.read("test/fixtures/hand/antimeridian-catalog/catalog.json")
idx = STAC.spatialindex(collect(STAC.items(cat; recursive = true)))

# A box across the antimeridian is one box on the sphere.
[idx.items[i].id for i in STAC.query(idx, Extent(X = (170, -170), Y = (60, 70)))]  # ["straddle"]

region = STAC.read("test/fixtures/hand/antimeridian-catalog/mid/greenwich.json").geometry
[idx.items[i].id for i in STAC.query(idx, Within(region))]                         # ["greenwich"]
source
STAC.spatialindex Method
julia
STAC.spatialindex(manifold, items) -> SpatialIndex
STAC.spatialindex(items; manifold = GeometryOps.Spherical()) -> SpatialIndex

An index over items for spatial queries.

Spherical(), the default, indexes each item by its 3D box on the unit sphere, so a footprint that crosses the antimeridian or covers a pole prunes correctly. Planar() indexes the longitude/latitude box as it stands, which is faster and right for a region well away from both.

Items that locate themselves nowhere — no bbox and no geometry — stay out of the tree and never appear among the hits.

julia
using Extents

cat = STAC.read("test/fixtures/hand/antimeridian-catalog/catalog.json")
idx = STAC.spatialindex(collect(STAC.items(cat; recursive = true)))
length(idx)                                             # 7, every item indexed or not

hits = STAC.query(idx, Extent(X = (-123, -122), Y = (37, 38)))
idx.items[first(hits)].id                               # "bay-area"
source

Tables, metadata, and printing ​

STAC.STACTable Type
julia
STAC.STACTable

The two things a vector of items can arrive as: the vector, and the ItemCollection page holding one.

source
STAC.BBox4 Type
julia
STAC.BBox4

A row's bbox, as the struct column stac-geoparquet defines it: the four planar bounds, in the order STAC writes them. STAC.BBox6 is the 3D case.

source
STAC.BBox6 Type
julia
STAC.BBox6

A row's bbox when the item carries an elevation interval: the six bounds, in the order STAC writes them. STAC.BBox4 is the planar case.

source
STAC.ItemColumn Type
julia
STAC.ItemColumn

One column of an item table: its name, the type the schema declares for it, and the function that reads it out of an item.

The reader is a closure rather than the callable struct the parse routers use: which columns exist is a property of the rows, not of the type, so this list is built at runtime and read through a dynamic call either way. Nothing here is on a --trim=safe path.

source
STAC.ItemColumns Type
julia
STAC.ItemColumns

The columns of one item table, built once and shared by every row, with a name lookup for Tables.getcolumn(row, ::Symbol).

source
STAC.ItemRow Type
julia
STAC.ItemRow

One item presented as a Tables.jl row: the item itself plus the columns its table settled on.

source
STAC.ItemRows Type
julia
STAC.ItemRows

A vector of Items as a Tables.jl row table. Build one with Tables.rows(items).

source
STAC.itemcolumns Method
julia
STAC.itemcolumns(items) -> STAC.ItemColumns

The column layout of a table of items: the typed fields first, then one column per field of each declared extension, then the keys the rows' tails carry.

ColumnsType
id, stac_extensions, geometry, collectionthe item's own field types
bboxSTAC.BBox4 or STAC.BBox6
every Properties field but otherthe field's type, so datetime is a Union{DateTime,Nothing} column
"eo:cloud_cover", "proj:code", …the extension field's type, one column per field of each extension in E
the keys seen in properties.otherAny
links, assetsVector{Link}, OrderedDict{String,Asset}
the keys seen in the items' own tailsAny

The last two groups need one pass over the items, since only the rows say which keys the producer used. A row missing a tail key reports missing. A tail key that spells a column this layout already has — a property named links — is left out rather than shadowing it.

source
STAC.tailkeys Method
julia
STAC.tailkeys(items, tailof) -> Vector{String}

Every key the items' tails carry, in the order they are first seen.

source
Tables.schema Method
julia
Tables.schema(items::AbstractVector{<:Item})
Tables.schema(page::ItemCollection)

The column layout of STAC.itemcolumns, as a Tables.Schema.

source
STAC.TailedObject Type
julia
STAC.TailedObject

The objects whose unnamed keys are reachable through DataAPI.metadata: everything that carries a tail of its own.

source
DataAPI.colmetadatakeys Method
julia
DataAPI.colmetadatakeys(items[, column])
DataAPI.colmetadata(items, column, key[, default]; style = false)

Where a column of an item table comes from. A column named "prefix:field" carries one key, "stac_extension", holding the schema URI of the extension that defines it, so DataFrame(items) says where "eo:cloud_cover" is specified without the caller keeping a prefix table of their own.

source
DataAPI.metadata Method
julia
DataAPI.metadata(obj, key[, default]; style = false) -> value

One key of obj's metadata tail. The style is always :note, which is the style DataFrames propagates through its operations.

julia
DataAPI.metadata(collection, "item_assets")
DataAPI.metadata(item, "s2:mgrs_tile", missing)
source
DataAPI.metadatakeys Method
julia
DataAPI.metadatakeys(obj) -> keys

The keys of obj's metadata tail: the top-level keys no field of it names, in document order. An object parsed with metadata = false has none, since the parse kept none.

source
STAC.iochildren Method
julia
STAC.iochildren(io::AbstractIO) -> Tuple{Vararg{Pair{String}}}

The transports io forwards to, each with the label that says why: a router labels each child with the scheme it answers, a wrapper with one child labels it "", and a transport that fetches for itself has none.

source
STAC.iosummary Method
julia
STAC.iosummary(out::IO, io::AbstractIO)

One AbstractIO on its own, without what it wraps. This is a node of the tree show(out, MIME"text/plain"(), io) draws, and a transport names its credentials by type — BearerToken rather than the token it holds.

Give a transport of your own a method to have it print as itself; the default names the type.

source
STAC.prefixes Method
julia
STAC.prefixes(::Type{<:Item}) -> Tuple{Vararg{Symbol}}

The extension prefixes an item type parses eagerly, which is what its type line shows in place of the three type parameters. An item with extensions = () has none.

source

Fetching and credentials ​

STAC.AbstractIO Type
julia
STAC.AbstractIO

Supertype of everything that fetches bytes. A STAC object holds only its own origin, never a transport, so every fetch goes through an AbstractIO that a caller passes in or that STAC.default_io supplies.

MethodContract
STAC.read(io, href)the bytes at href, as a Vector{UInt8}
STAC.request(io, method, href; headers, body)the body of one request, as a Vector{UInt8}

request defaults to read for GET and errors otherwise, which is the whole implementation for a read-only transport such as PathIO. Wrappers (CachingIO, StreamRouterIO) hold an inner IO and forward both calls.

Every method declares Vector{UInt8}, so the one dynamic dispatch a scoped default costs is confined to the call itself and everything downstream of it is inferred.

source
STAC.RequestHeaders Type
julia
STAC.RequestHeaders

The header list a request carries: name => value pairs in the order they are sent.

source
STAC.authfor Method
julia
STAC.authfor(io, href) -> AbstractAuth

The credentials io would fetch href with. A wrapper asks its inner IO and a router asks the child its scheme picks, so a stack that signs https and stays anonymous on s3 reports the auth that actually applies to the href at hand.

This is how a driver reaches the catalog's credentials without a transport: STAC.route asks the stack for the auth, and then asks the auth to sign the href and to name the GDAL options GDAL will need.

julia
STAC.authfor(STAC.defaultstack(STAC.BearerToken("s3cret")), "https://example.com/b.tif")
# STAC.BearerToken("s3cret")
STAC.authfor(STAC.defaultstack(STAC.BearerToken("s3cret")), "/data/b.tif")   # STAC.NoAuth()
source
STAC.request Method
julia
STAC.request(io, method, href; headers = STAC.NO_HEADERS, body = nothing) -> Vector{UInt8}

The response body of one request through io. This is the call a STAC API search and its next links use; method, headers, and body come from the link the endpoint sent.

The fallback answers GET with STAC.read and rejects every other method, which is the right behaviour for a transport that can only fetch.

source
STAC.EARTHDATA_HOSTS Constant
julia
STAC.EARTHDATA_HOSTS

The host suffixes EarthdataLogin sends its token to. NASA's DAACs redirect a data request to a signed URL on a host that rejects an Authorization header it did not expect, so the token goes to Earthdata hosts alone.

One suffix covers every DAAC that answers under NASA's own domain — cmr.earthdata.nasa.gov and data.lpdaac.earthdatacloud.nasa.gov among them. A DAAC that does not, such as NSIDC's n5eil01u.ecs.nsidc.org or ASF's sentinel1.asf.alaska.edu, takes a STAC.Headers naming the hosts it does answer under.

source
STAC.PC_SAS_URL Constant
julia
STAC.PC_SAS_URL

The Planetary Computer's SAS token service, which mints a read token per storage account and container.

source
STAC.AbstractAuth Type
julia
STAC.AbstractAuth

Supertype of the credentials an HTTPIO carries. An auth answers two questions, both per href, so one stack can hold a token for a catalog's own host and stay anonymous for the buckets its assets live in:

MethodAnswers
STAC.headers(auth, href)the request headers to add
STAC.rewrite(auth, href)the href a reader should see, e.g. one carrying a signed token

rewrite defaults to the identity, so an auth that only adds headers implements headers alone.

julia
struct QueryToken <: STAC.AbstractAuth
    token::String
end
STAC.headers(::QueryToken, ::AbstractString) = STAC.NO_HEADERS
STAC.rewrite(a::QueryToken, href::AbstractString) = href * "?token=" * a.token

STAC.rewrite(QueryToken("abc"), "https://example.com/catalog.json")
# "https://example.com/catalog.json?token=abc"

STAC.HTTPIO(QueryToken("abc"))  # the transport that signs every href
source
STAC.BearerToken Type
julia
STAC.BearerToken(token)

Authorization: Bearer <token> on every request. STAC.Headers covers an endpoint that wants a differently named header.

julia
STAC.headers(STAC.BearerToken("s3cret"), "https://example.com")
# ["Authorization" => "Bearer s3cret"]

A Client takes one through auth =, and every later call carries it.

source
STAC.EarthdataLogin Type
julia
STAC.EarthdataLogin(token)

Authorization: Bearer <token> for NASA Earthdata hosts, both on this package's own requests and, through STAC.gdal_config, on the ones GDAL makes for an asset.

Mint the token at https://urs.earthdata.nasa.gov/profile, under "Generate Token".

julia
auth = STAC.EarthdataLogin(ENV["EARTHDATA_TOKEN"])
STAC.headers(auth, "https://data.lpdaac.earthdatacloud.nasa.gov/x/B04.tif")
# ["Authorization" => "Bearer …"]
STAC.headers(auth, "https://example.com/b.tif")   # Pair{String,String}[]

client = STAC.Client("https://cmr.earthdata.nasa.gov/stac/LPCLOUD"; auth)
source
STAC.GDALOptions Type
julia
STAC.GDALOptions

The GDAL configuration options one fetch needs: name => value pairs, applied to the path prefix they belong to rather than to the process.

source
STAC.Headers Type
julia
STAC.Headers(pairs)
STAC.Headers("X-Api-Key" => "…", …)

A fixed header list added to every request, for the endpoints whose credential is neither a bearer token nor a signed URL.

julia
auth = STAC.Headers("X-Api-Key" => "k", "X-Tenant" => "acme")
STAC.headers(auth, "https://example.com")   # ["X-Api-Key" => "k", "X-Tenant" => "acme"]
STAC.HTTPIO(auth)                           # the transport that sends them
source
STAC.NoAuth Type
julia
STAC.NoAuth()

Anonymous access: no headers, no rewriting. The default of every stack STAC.default_io builds.

julia
STAC.headers(STAC.NoAuth(), "https://example.com")   # Pair{String,String}[]
source
STAC.PlanetaryComputerSAS Type
julia
STAC.PlanetaryComputerSAS(; subscription_key = nothing, url = STAC.PC_SAS_URL,
                          io = STAC.HTTPIO(), margin = Minute(5))

Signs a Microsoft Planetary Computer blob href with a shared access signature, one token per storage account and container, held until it expires.

KeywordMeaning
subscription_keythe account key sent as Ocp-Apim-Subscription-Key on the token request
urlthe token service; <url>/<account>/<container> is what one request asks for
iothe transport the token request goes through
marginhow long before a token's stated expiry it is refreshed

Anonymous token requests work: the service answered one without a subscription key when this fixture was recorded (2026-09-02), giving a token good for 45 minutes. A key raises the rate limit and lengthens that window; a key the service does not recognise is ignored rather than rejected.

STAC.rewrite appends the token to a *.blob.core.windows.net href and returns every other href unchanged, so one stack can sign Planetary Computer assets and stay anonymous for the rest:

julia
auth = STAC.PlanetaryComputerSAS()
STAC.rewrite(auth, "https://sentinel2l2a01.blob.core.windows.net/sentinel2-l2/x/B04.tif")
# "https://sentinel2l2a01.blob.core.windows.net/sentinel2-l2/x/B04.tif?st=…&se=…&sig=…"

STAC.rewrite(auth, "s3://usgs-landsat/collection02/B4.TIF")   # unchanged

client = STAC.Client("https://planetarycomputer.microsoft.com/api/stac/v1"; auth)
source
STAC.blobparts Method
julia
STAC.blobparts(href) -> Union{Tuple{String,String},Nothing}

The storage account and container of an Azure Blob Storage href (https://<account>.blob.core.windows.net/<container>/<path>), or nothing for an href that names no blob. This is what picks the token PlanetaryComputerSAS signs with.

julia
julia> STAC.blobparts("https://sentinel2l2a01.blob.core.windows.net/sentinel2-l2/x/B04.tif")
("sentinel2l2a01", "sentinel2-l2")

julia> STAC.blobparts("https://example.com/b.tif") === nothing
true
source
STAC.fetchsastoken Method
julia
STAC.fetchsastoken(auth, account, container) -> (token, expiry)

One GET <url>/<account>/<container>, parsed into the query string it returns and the instant it stops working.

source
STAC.gdal_config Method
julia
STAC.gdal_config(auth, href) -> STAC.GDALOptions

The GDAL configuration options that let GDAL fetch href with auth's credentials, which is the third question an auth answers, beside STAC.headers and STAC.rewrite.

The default turns whatever headers returns into one GDAL_HTTP_HEADERS option, CRLF separated as GDAL wants it, so an auth that signs with headers needs no method here:

julia
STAC.gdal_config(STAC.BearerToken("s3cret"), "https://example.com/b.tif")
# ["GDAL_HTTP_HEADERS" => "Authorization: Bearer s3cret"]

STAC.gdal_config(STAC.NoAuth(), "https://example.com/b.tif")     # Pair{String,String}[]

An auth that signs the href itself, PlanetaryComputerSAS among them, has nothing to tell GDAL: the credential rides in the URL STAC.rewrite returns.

source
STAC.headers Function
julia
STAC.headers(auth, href) -> STAC.RequestHeaders

The headers auth adds to a request for href, empty when it does not apply to that host.

source
STAC.isearthdata Method
julia
STAC.isearthdata(href) -> Bool

Whether href names a NASA Earthdata host, which is where EarthdataLogin sends its token.

source
STAC.rewrite Method
julia
STAC.rewrite(auth, href) -> String

href as a reader should see it. An auth that signs a URL returns the signed form; every other auth returns href unchanged.

source
STAC.sastoken Method
julia
STAC.sastoken(auth::PlanetaryComputerSAS, account, container) -> String

The query string that signs one container, from the cache when it is still valid and from the token service otherwise. Concurrent callers share one request per container.

source
STAC.absolutehref Method
julia
STAC.absolutehref(href) -> String

href as an origin worth recording: a local path becomes absolute and /-separated, anything with a scheme is left alone.

source
STAC.isabsolutehref Method
julia
STAC.isabsolutehref(href) -> Bool

Whether href can be fetched on its own: it carries a scheme, or it is an absolute path on this filesystem.

source
STAC.pathhref Method
julia
STAC.pathhref(path) -> String

path spelled the way an href is. An href is a URI reference, where / separates the segments on every platform and \ separates nothing at all, so a path Windows handed back is respelled; on every other platform the path is already its own href.

Windows opens a /-separated path as readily as a \-separated one, so the answer stays a path you can read from as well as a href you can write to a document.

julia
julia> STAC.pathhref("catalogs/a/catalog.json")
"catalogs/a/catalog.json"
source
STAC.resolve Method
julia
STAC.resolve(link::Link, base) -> String
STAC.resolve(href::AbstractString, base) -> String

href made absolute against base, the origin of the object whose links it came from.

hrefbaseResult
carries a schemeanythinghref, unchanged
anya href with a schemeRFC 3986 reference resolution
an absolute patha local path, or nonehref, unchanged
relativea local pathpathhref(normpath(joinpath(dirname(base), href)))
relativenothinga STAC.NoOrigin

A trailing slash on base is significant either way: "./item.json" against "/a/b" is "/a/item.json", and against "/a/b/" it is "/a/b/item.json".

A root-relative "/collections/x.json" is a path when the base is one and a host-rooted URL when the base is a URL, which is what RFC 3986 says and what an API that publishes such links means.

The answer is always a href, so a local one is /-separated on Windows too; see STAC.pathhref.

source
STAC.urischeme Method
julia
STAC.urischeme(href) -> SubString{String}

The scheme of href without its colon ("https", "s3"), or an empty string when href carries none, which is how a local path presents itself. This is what StreamRouterIO matches a route on.

URIs.jl does the RFC 3986 parse; two answers are this package's own.

hrefSchemeWhy
"C:/data/catalog.json"""a lone letter before the colon is a Windows drive, not the one-character scheme RFC 3986 allows
"/my catalogs/c.json"""a raw space makes it no URI reference at all, which is to say a local path
julia
julia> STAC.urischeme("https://example.com/catalog.json")
"https"

julia> STAC.urischeme("./item.json")
""
source
STAC.PathIO Type
julia
STAC.PathIO()

The local-filesystem AbstractIO. read is Base.read on the path the href names; a file:// href is accepted and reduced to its path first, so a catalog published with file URLs traverses without a separate route.

julia
STAC.parse(STAC.read(STAC.PathIO(), "test/fixtures/stac-spec/catalog.json")).id  # "examples"
STAC.read("test/fixtures/stac-spec/catalog.json"; io = STAC.PathIO())            # the same, typed
source
STAC.localpath Method
julia
STAC.localpath(href) -> String

The filesystem path href names, whether it was written as a plain path or as a file:// URL.

source
STAC.USER_AGENT Constant
julia
STAC.USER_AGENT[]

The User-Agent every request carries, "STAC.jl/<version>". Assign to it to identify your own tool to an endpoint that asks.

It is a Ref filled when the module is compiled rather than in __init__: formatting a VersionNumber is not a --trim=safe call, and the --trim programs share this code path.

source
STAC.HTTPIO Type
julia
STAC.HTTPIO(auth = STAC.NoAuth(); client = nothing, retries = 3, connect_timeout = 30,
            request_timeout = 300)

The HTTP AbstractIO, over HTTP.jl. auth supplies per-href headers and href rewriting; every request carries a STAC.jl/<version> User-Agent.

KeywordMeaning
clientan HTTP.Client to pool connections through; nothing uses HTTP.jl's shared default
retriesattempts after the first, for transient failures and retryable 4xx/5xx statuses
connect_timeoutseconds to establish a connection; 0 disables
request_timeoutseconds for the whole request; 0 disables

client defaults to nothing because STAC.DEFAULT_IO is built when the module loads: a live connection pool cannot go into a precompile cache, and HTTP.jl's implicit client already pools.

julia
STAC.read("https://stac.itslive.cloud/"; io = STAC.HTTPIO()).id      # "stac-fastapi"

# A slow endpoint behind a token, given more attempts and a longer ceiling.
STAC.HTTPIO(STAC.BearerToken("s3cret"); retries = 5, request_timeout = 600)
source
STAC.requestheaders Method
julia
STAC.requestheaders(auth, href, extra) -> STAC.RequestHeaders

The headers one request sends: the User-Agent, then what auth adds for href, then the caller's own. Later entries win at the server, so a caller can override either.

source
STAC.CachingIO Type
julia
STAC.CachingIO(inner; maxsize = 128)
STAC.CachingIO(inner, cache::LRU{String,Vector{UInt8}})

An AbstractIO that answers a repeated read from an LRU of fetched bytes. A catalog walk reaches the same root and parent documents from every object it visits, so the cache is what keeps that from being one request each.

request passes straight through: a search POST is not addressed by its href alone, and a next link is meant to be fetched exactly once.

julia
io = STAC.CachingIO(STAC.PathIO(); maxsize = 32)
cat = STAC.read("test/fixtures/static/self-contained/catalog.json"; io)
collect(STAC.items(cat; recursive = true, io))  # one fetch per document, however often reached
length(io.cache)                                # 7: the catalog, two children, four items
empty!(io)                                      # back to the inner IO for every href
source
Base.empty! Method
julia
empty!(io::STAC.CachingIO)

Drop every cached body, so the next read of each href goes back to the inner IO.

source
STAC.StreamRouterIO Type
julia
STAC.StreamRouterIO(routes::Tuple)
STAC.StreamRouterIO("https" => STAC.HTTPIO(), "" => STAC.PathIO())

The AbstractIO that picks a child by the href's scheme, with "" meaning a local path. Routing per href rather than per catalog is what lets a catalog on https:// own items on s3://, or a next link point at another host.

The routes are a tuple, so each read resolves to one child's method at compile time, which is what --trim=safe needs.

julia
io = STAC.StreamRouterIO("https" => STAC.HTTPIO(), "" => STAC.PathIO())
STAC.read("test/fixtures/stac-spec/catalog.json"; io)      # the "" route
STAC.read("https://stac.itslive.cloud/"; io)               # the "https" one

An href whose scheme no route matches raises a STAC.NoRoute naming it.

source
STAC.S3IO Function
julia
STAC.S3IO(; config = nothing)

The AbstractIO that reads s3:// hrefs, defined by AWSS3.jl. config is an AWS.AWSConfig; nothing uses the credentials AWS.jl discovers from the environment, the shared credentials file, or the instance metadata service.

A public bucket reads anonymously, with the region named: AWS.jl resolves nothing to the default region, and a bucket that lives elsewhere answers a request sent there with a PermanentRedirect.

julia
import STAC
using AWSS3

io = STAC.S3IO(; config = AWSS3.AWS.AWSConfig(; creds = nothing, region = "us-west-2"))
item = STAC.read("s3://sentinel-cogs/sentinel-s2-l2a-cogs/32/T/QL/2024/6/S2B_32TQL_20240601_0_L2A/S2B_32TQL_20240601_0_L2A.json";
                 io = STAC.StreamRouterIO("s3" => io, "https" => STAC.HTTPIO(),
                                          "" => STAC.PathIO()))
item.id                     # "S2B_32TQL_20240601_0_L2A"
length(item.assets)         # 35
source
STAC.DEFAULT_IO Constant
julia
STAC.DEFAULT_IO

The ScopedValue holding the AbstractIO that STAC.default_io returns. Rebind it for a block with STAC.with.

source
STAC.default_io Method
julia
STAC.default_io() -> AbstractIO

The IO stack a call uses when the caller names none. Reading it is the one dynamic dispatch in the fetch path; read(io, href) declares Vector{UInt8} on every method, so everything below that call is inferred.

source
STAC.defaultstack Function
julia
STAC.defaultstack(auth = STAC.NoAuth()) -> AbstractIO

A fresh copy of the stack STAC.default_io returns: an LRU cache over a scheme router that sends https and http to an HTTPIO carrying auth and everything else to PathIO.

source
STAC.with Method
julia
STAC.with(f, io::AbstractIO)

Run f() with io as STAC.default_io.

julia
stack = STAC.CachingIO(STAC.StreamRouterIO(("https" => STAC.HTTPIO(STAC.BearerToken(tok)),)))
STAC.with(stack) do
    STAC.read("https://example.com/catalog.json")
end
source

Parsing and writing JSON ​

STAC.ANY_GEOMETRY Type
julia
STAC.ANY_GEOMETRY

Every GeoJSON geometry type, in Float64 longitude/latitude, for a catalog whose items you have not seen: geometry = STAC.ANY_GEOMETRY accepts points and lines as well as the two STAC.DEFAULT_GEOMETRY allows.

The wider the union, the more dispatch the parse does per item and the more code a --trim=safe program carries, which is why it is not the default.

source
STAC.DEFAULT_EXTENSIONS Constant
julia
STAC.DEFAULT_EXTENSIONS

The extension structs parsed eagerly when a caller names none: the six this package ships. An extension outside the set is not lost — its keys stay in properties.other, where get(item, T) still finds them.

source
STAC.DEFAULT_GEOMETRY Type
julia
STAC.DEFAULT_GEOMETRY

The geometry types an item can hold when a caller names none: the two STAC item geometries that occur in practice, in Float64 longitude/latitude, plus nothing for the items whose footprint is unknown.

source
STAC.STAC_VERSION Constant
julia
STAC.STAC_VERSION

The stac_version written on objects whose tail carries none.

source
STAC.ParseOptions Type
julia
STAC.ParseOptions(; extensions = STAC.DEFAULT_EXTENSIONS,
                  geometry = STAC.DEFAULT_GEOMETRY, metadata = true)

The three choices that fix the concrete types a parse produces, carried as type parameters so STAC.itemtype is known at compile time.

KeywordAcceptsBecomes
extensionsa tuple of STAC.Extension structs; () for noneE
geometrya geometry type, a union of them, or GeoJSON.AbstractGeometry for STAC.ANY_GEOMETRYG
metadatatrue to keep unnamed keys, false to skip themM
source
STAC.catalogtype Method
julia
STAC.catalogtype(opts::ParseOptions) -> Type{<:Catalog}

The Catalog{M} these options name.

source
STAC.childtype Method
julia
STAC.childtype(opts::ParseOptions) -> Type

What a child, parent, or root link resolves to: Union{Catalog{M}, Collection{M}}, narrowed to one of the two by the document's own type key.

source
STAC.collectiontype Method
julia
STAC.collectiontype(opts::ParseOptions) -> Type{<:Collection}

The Collection{M} these options name.

source
STAC.itemcollectiontype Method
julia
STAC.itemcollectiontype(opts::ParseOptions) -> Type{<:ItemCollection}

The ItemCollection{E,G,M} these options name.

source
STAC.itemtype Method
julia
STAC.itemtype(opts::ParseOptions) -> Type{<:Item}

The Item{E,G,M} these options name.

source
STAC.STACStyle Type
julia
STACStyle()

The JSON.JSONStyle every STAC.parse, STAC.read, and STAC.json call passes to JSON.jl. It contributes two things to StructUtils' machinery:

  • an RFC 3339 lift for DateTime, accepting any number of fractional digits and both the Z and ±HH:MM offset forms;

  • make methods for the types this package owns, which route each key to a typed field, an extension slot, or the object's metadata tail in one forward pass (see parse/sinks.jl).

source
STAC.format_rfc3339 Method
julia
STAC.format_rfc3339(dt::DateTime) -> String

A DateTime as the UTC RFC 3339 string STAC requires, always ending in Z and carrying milliseconds only when they are non-zero.

The three milliseconds digits are spelled out rather than padded: lpad reaches Base.repeat, which --trim=safe reports as an unresolved invoke.

source
STAC.parse_rfc3339 Method
julia
STAC.parse_rfc3339(s::AbstractString) -> DateTime

An RFC 3339 date-time in UTC. Fractional seconds of any length are accepted and truncated to the millisecond DateTime holds; Z, z, and ±HH:MM offsets are all applied.

StructUtils' own ISO parser caps the fraction at three digits, which rejects the six-digit timestamps Planetary Computer and the stac-spec examples carry.

source
STAC.json Method
julia
STAC.json(obj; kw...) -> String
STAC.json(io, obj; kw...)

obj as a STAC JSON document. type and stac_version are put back, declared extensions are written under their prefixes inside properties, and every key the parse kept in a metadata tail returns in the order the producer wrote it.

Keywords are JSON.jl's, so pretty = 2 gives an indented document.

julia
item = STAC.read("test/fixtures/stac-spec/simple-item.json")
STAC.parse(STAC.json(item)).id == item.id    # true: what is written parses back
STAC.json(item; pretty = 2)                  # the same document, indented
open(io -> STAC.json(io, item), "item.json", "w")
source

Drivers and bulk formats ​

STAC.VSI_NETWORK Constant
julia
STAC.VSI_NETWORK

The GDAL virtual filesystem prefixes that fetch over the network, which is what decides whether a route needs credentials and a certificate store. /vsizip/ and its siblings read local bytes and are absent from this list.

source
STAC.AbstractDriver Type
julia
STAC.AbstractDriver

Supertype of the openers an Asset can be read through. STAC.driver picks one from the asset's media type and href, and STAC.route turns the pair into the (; filename, source, config) the opener takes.

DriverOpensPackage
STAC.GDALDriverGeoTIFF, JPEG 2000, and everything else GDAL reads, local or remoteRasters, ArchGDAL
STAC.NetCDFDrivera local NetCDF or HDF5 fileRasters, NCDatasets
STAC.ZarrDrivera Zarr storeRasters, ZarrDatasets
STAC.GeoJSONDriverGeoJSON, through STAC.read and the IO stackSTAC itself
STAC.GeoParquetDrivera flat GeoParquet fileGeoParquet
STAC.DuckDBDrivera stac-geoparquet file, whose nested columns need SQLDuckDB
source
STAC.DuckDBDriver Type
julia
STAC.DuckDBDriver()

A stac-geoparquet file, whose links and assets columns are nested structs that SQL reads and a flat parquet reader does not.

source
STAC.GDALDriver Type
julia
STAC.GDALDriver()

GDAL reads the asset, over /vsicurl/, /vsis3/, /vsigs/, or /vsiaz/ when it lives somewhere other than this filesystem. This is the driver for every raster media type that has no more specific reader, and for remote NetCDF and HDF5, which GDAL range-reads where the NetCDF library would have to download the file whole.

source
STAC.GeoJSONDriver Type
julia
STAC.GeoJSONDriver()

GeoJSON, read as bytes through the IO stack and parsed by GeoJSON.jl. This is the one driver core carries: STAC.read(asset) needs no weak dependency.

source
STAC.GeoParquetDriver Type
julia
STAC.GeoParquetDriver()

A flat GeoParquet file, one row per feature with a WKB geometry column.

source
STAC.NetCDFDriver Type
julia
STAC.NetCDFDriver()

The NetCDF library reads the asset. Local files only: a NetCDF or HDF5 asset behind a URL goes to STAC.GDALDriver.

source
STAC.ZarrDriver Type
julia
STAC.ZarrDriver()

A Zarr store, read from its URL as it stands. Public stores over https and s3 work anonymously; a private one needs the store object the bridge for its cloud builds.

source
STAC.afterscheme Method
julia
STAC.afterscheme(href) -> SubString{String}

What follows <scheme>:// in an href: the bucket and key of an s3:// URL, the container and blob of an az:// one.

source
STAC.asset Method
julia
STAC.asset(item, key) -> Asset

The asset item publishes under key, which is a String or a Symbol. An absent key raises a STAC.MissingAsset listing the keys the item does carry, because producers name the same band "B04", "red", and "B4" on three different endpoints.

source
STAC.assethref Method
julia
STAC.assethref(asset) -> String

The absolute href of an asset. A producer that wrote a relative one raises a STAC.NoOrigin, since an Asset carries no origin of its own to resolve against.

source
STAC.basemediatype Method
julia
STAC.basemediatype(type) -> String

A media type without its parameters, lowercased: "image/tiff; application=geotiff; profile=cloud-optimized" is "image/tiff". The parameters distinguish a plain GeoTIFF from a cloud-optimized one, which the same driver opens either way.

source
STAC.driver Method
julia
STAC.driver(asset) -> AbstractDriver

The driver that opens asset: its media type when that names one, and its file extension otherwise. GDAL is the fallback, as it is in Rasters.jl, because GDAL reads more formats than any table can list.

Two rules make the choice more than a lookup:

RuleWhy
a NetCDF or HDF5 asset behind a URL goes to STAC.GDALDriverGDAL range-reads it; the NetCDF library downloads the file whole
the media type wins over the extensionproducers publish .tif assets that are really application/x-netcdf subdatasets
julia
julia> STAC.driver(STAC.Asset("s3://b/x.nc", "application/x-netcdf", nothing, nothing,
                              nothing, nothing, STAC.NoMetadata()))
STAC.GDALDriver()

julia> STAC.driver(STAC.Asset("/data/x.nc", nothing, nothing, nothing, nothing, nothing,
                              STAC.NoMetadata()))
STAC.NetCDFDriver()
source
STAC.hrefextension Method
julia
STAC.hrefextension(href) -> String

The lowercased file extension of an href, with its query string and fragment removed first, so a signed .../B04.tif?st=…&sig=… still reads as a GeoTIFF.

source
STAC.isvsinetwork Method
julia
STAC.isvsinetwork(filename) -> Bool

Whether GDAL would fetch this path over the network.

julia
julia> STAC.isvsinetwork("/vsis3/usgs-landsat/c2/B4.TIF")
true

julia> STAC.isvsinetwork("/data/B4.tif")
false
source
STAC.package Method
julia
STAC.package(driver) -> String

The packages that open what this driver routes, spelled as the import list that loads them: import * package(d) is a statement a user can paste.

julia
julia> STAC.package(STAC.GDALDriver())
"Rasters, ArchGDAL"
source
STAC.read_geoparquet Function
julia
STAC.read_geoparquet(path; extensions, geometry, metadata) -> Vector{Item}

The items of a stac-geoparquet file, one per row, defined by DuckDB.jl. The keywords are ParseOptions's.

DuckDB does the reading because a stac-geoparquet row is nested: assets is a struct of structs and links a list of them, which SQL reads and a flat parquet reader does not.

julia
import STAC
using DuckDB

its = STAC.read_geoparquet("test/fixtures/geoparquet/items.parquet")
[i.id for i in its]
# ["collectionless-item", "core-item", "extended-item", "simple-item"]
its[3].extensions.eo.cloud_cover            # 1.2: the typed extension slots are filled
idx = STAC.spatialindex(its)
source
STAC.route Method
julia
STAC.route(driver, asset, io) -> (; filename, source, config)
STAC.route(asset, io)

What the opener needs to read asset, as three values:

FieldHolds
filenamethe path or URL the opener takes, signed and in GDAL's virtual filesystem spelling
sourcethe Rasters.jl backend symbol: :gdal, :netcdf, :zarr, or :geojson for the core reader
configthe GDAL options the fetch needs, from STAC.gdal_config

The credentials come from io: STAC.authfor reports the auth that stack would fetch this href with, and that auth both signs the href and names the options.

julia
asset = STAC.Asset("https://sentinel2l2a01.blob.core.windows.net/sentinel2-l2/x/B04.tif",
                   "image/tiff; application=geotiff; profile=cloud-optimized",
                   nothing, nothing, ["data"], nothing, STAC.NoMetadata())
r = STAC.route(STAC.driver(asset), asset, STAC.defaultstack(STAC.PlanetaryComputerSAS()))
r.filename   # "/vsicurl/https://sentinel2l2a01.blob.core.windows.net/…?st=…&sig=…"
r.source     # :gdal

The two-argument form picks the driver with STAC.driver first.

A driver whose route comes from a package the session has not loaded raises a STAC.NoDriverPackage naming that package.

source
STAC.vsi_path Method
julia
STAC.vsi_path(scheme, href) -> String

href as GDAL's virtual filesystem names it.

SchemePath
""href, which is already a path on this filesystem
"file"the path the file:// URL names
"http", "https"/vsicurl/ and the URL whole, query string included
"s3"/vsis3/<bucket>/<key>
"gs"/vsigs/<bucket>/<key>
"az", "abfs", "abfss"/vsiaz/<container>/<blob>
anything elsehref unchanged, for GDAL's own prefixes such as NETCDF:
julia
julia> STAC.vsi_path("s3", "s3://usgs-landsat/collection02/B4.TIF")
"/vsis3/usgs-landsat/collection02/B4.TIF"

julia> STAC.vsi_path("https", "https://example.com/B4.tif?sig=abc")
"/vsicurl/https://example.com/B4.tif?sig=abc"
source
STAC.vsi_prefix Method
julia
STAC.vsi_prefix(filename) -> String

The longest prefix of a GDAL virtual path that names a whole bucket, container, or host, so one set of credentials covers every file under it. Path-specific options are set against this rather than against each file.

julia
julia> STAC.vsi_prefix("/vsis3/usgs-landsat/collection02/B4.TIF")
"/vsis3/usgs-landsat/"

julia> STAC.vsi_prefix("/vsicurl/https://example.com/a/B4.tif?sig=abc")
"/vsicurl/https://example.com/"
source
STAC.write_geoparquet Function
julia
STAC.write_geoparquet(path, items) -> String

items written to path as a stac-geoparquet file, and the path it went to. Defined by DuckDB.jl.

The file carries the two key-value metadata entries the format is read by: geo, naming the WKB geometry column, and stac-geoparquet, naming the specification version.

julia
import STAC
using DuckDB

cat = STAC.read("test/fixtures/static/self-contained/catalog.json")
STAC.write_geoparquet("items.parquet", collect(STAC.items(cat; recursive = true)))
source
STAC.ItemLines Type
julia
STAC.ItemLines{T}

The lazy iterator behind STAC.read_ndjson. One line is read and parsed per iterate, so a million-line file costs one line's work to look at its first item.

A file source opens a fresh handle per iteration, closed when the lines run out, so the same ItemLines reads twice. A stream source picks up where the stream stands, that being what a stream offers.

source
STAC.read_ndjson Method
julia
STAC.read_ndjson(path; extensions, geometry, metadata) -> STAC.ItemLines
STAC.read_ndjson(io::IO; extensions, geometry, metadata)

The Items of a newline-delimited JSON file, as a lazy iterator of one item per line. The keywords are ParseOptions's.

Nothing is read until an element is reached, so first costs one line and Iterators.take(items, 10) costs ten.

SourceHandle
a pathopened per iteration and closed when the lines run out, so the same iterator reads twice. An iteration abandoned part way leaves the handle to the garbage collector
an IOyours: the iterator picks up where the stream stands and leaves it open
julia
lines = STAC.read_ndjson("corpus.ndjson")
first(lines).id                                 # one line read
sum(1 for _ in lines)                           # the whole file, one line at a time
idx = STAC.spatialindex(collect(Iterators.take(lines, 1000)))
source
STAC.write_ndjson Method
julia
STAC.write_ndjson(path, items) -> Int
STAC.write_ndjson(io::IO, items)

items as newline-delimited JSON, one STAC.json document per line, and the number of lines written. items is anything iterable: a vector, a search, or another file's STAC.read_ndjson, which streams one item at a time.

julia
cat = STAC.read("test/fixtures/static/self-contained/catalog.json")
STAC.write_ndjson("items.ndjson", STAC.items(cat; recursive = true))    # 4
[i.id for i in STAC.read_ndjson("items.ndjson")]
source
STAC.CATALOG_TYPE Constant
julia
STAC.CATALOG_TYPE

The media type of a catalog or collection document, which is what the hierarchy links STAC.write writes carry.

source
STAC.ITEM_TYPE Constant
julia
STAC.ITEM_TYPE

The media type of an item document. An item link gets this rather than STAC.CATALOG_TYPE: an item is a GeoJSON Feature, and the best-practices document asks producers to say so.

source
STAC.bestpath Method
julia
STAC.bestpath(obj, parentdir, isroot) -> String

Where the STAC best-practices layout puts obj under a parent directory: a catalog or collection in a directory named after its id, an item in a directory of its own beside its own name.

objPath
the root of the treecatalog.json, collection.json, or <id>.json
a child catalog or collection<parentdir>/<id>/catalog.json, …/collection.json
an item<parentdir>/<id>/<id>.json
source
STAC.documentname Method
julia
STAC.documentname(obj) -> String

The file name the best-practices layout gives a document: catalog.json, collection.json, or <item-id>.json.

source
STAC.hrefdir Method
julia
STAC.hrefdir(href) -> String

Everything up to and including the last / of href: the directory a relative link beside it resolves against. An href with no / gives "".

source
STAC.parentdir Method
julia
STAC.parentdir(path) -> String

The directory of a /-separated relative path, "" for a document at the top of the tree.

source
STAC.relativepath Method
julia
STAC.relativepath(to, fromdir) -> String

The /-separated path from directory fromdir to the document to, both relative to the same root, with ../ for each level climbed. The result is spelled as a relative link: "./item.json" for a sibling, "../catalog.json" for the level above.

julia
julia> STAC.relativepath("catalog.json", "simple-collection")
"../catalog.json"

julia> STAC.relativepath("simple-collection/simple-item.json", "simple-collection")
"./simple-item.json"
source
STAC.republish Method
julia
STAC.republish(p, obj, path, parent, collection, root, childpaths, itempaths) -> obj

obj with the links it will be published with: self as the link style asks for, root, parent, collection, and one child or item per document below it, all pointing at where this walk puts them, and every other link carried over with its href made absolute.

collection is the path of the Collection an item belongs to, and nothing for an item whose parent is a plain catalog.

source
STAC.write Method
julia
STAC.write(dest, obj; layout, links, root_href, io, extensions, geometry, metadata)
STAC.write(dest, obj, opts::ParseOptions; layout, links, root_href, io)

obj written as STAC JSON, either as one document or as the whole tree below it.

destWrites
a path ending in .jsonobj alone, exactly as STAC.json renders it
any other pathobj and every catalog, collection, and item it links to, as a directory tree

The tree form takes two decisions, both named after the STAC best practices document: where each document lands, and how the links between them are spelled.

layoutPuts
:best (default)catalog.json, then <collection-id>/collection.json, then <item-id>/<item-id>.json
:keepeach object where it was read from, relative to the root's origin
(obj, parent_dir) -> pathwherever the function says, as a /-separated path under dest. parent_dir is nothing for the root and the parent's directory below it
linksWrites
:self_contained (default)no self links; every hierarchy link relative. The tree moves anywhere
:relative_publishedone absolute self on the root; every hierarchy link relative
:absolute_publishedan absolute self and absolute hierarchy links on every document

The two published forms need root_href, the URL the tree will be reachable at; a missing trailing / is added. Asset hrefs and the producer's own links (license, describedby, via) are made absolute against the origin each object was read from, so they resolve from the new location.

julia
cat = STAC.read("test/fixtures/static/self-contained/catalog.json")
STAC.write("out", cat)                                       # "out/catalog.json"
STAC.write("out", cat; links = :absolute_published, root_href = "https://example.com/out/")
STAC.write("out/one-item.json", first(STAC.items(cat)))
source
STAC.writedocument Method
julia
STAC.writedocument(path, obj) -> String

obj written to path as one indented STAC JSON document, and the path it went to. Missing directories are created.

source

Errors ​

STAC.ArgumentShapeError Type
julia
STAC.ArgumentShapeError

An argument has the wrong type or the wrong number of values — a datetime interval of one instant, a bbox of five numbers, a spatial argument that is no geometry.

source
STAC.BadBBox Type
julia
STAC.BadBBox(n)

A bbox of n numbers, where a STAC bbox is four (west, south, east, north) or six with the elevation interval in the middle.

source
STAC.BadDateTime Type
julia
STAC.BadDateTime(value)

A date-time string RFC 3339 rejects, from a document's datetime or from a datetime = argument.

source
STAC.BadInterval Type
julia
STAC.BadInterval(n)

A datetime = interval of n values, where an interval is a start and a stop.

source
STAC.BadOption Type
julia
STAC.BadOption(option, value, allowed)

A keyword given a value outside the set it takes. allowed lists the set, spelled as the values themselves.

source
STAC.DocumentError Type
julia
STAC.DocumentError

The document differs from the one the call expected: a type key naming something else, a required field the producer left out, or a value the spec's grammar rejects.

source
STAC.EmptyPredicate Type
julia
STAC.EmptyPredicate(predicate)

A DE-9IM predicate wrapping no geometry, which is the Within() singleton rather than the Within(polygon) a search compares against.

source
STAC.EndpointError Type
julia
STAC.EndpointError

The endpoint does not offer what the call needs: a conformance class it never advertised, a scheme the IO stack has no route for, a method a transport cannot make.

source
STAC.LookupError Type
julia
STAC.LookupError

A link with a given rel, a collections array, a table column, or an extension's keys — something the call needed to reach is absent from the object it looked in.

source
STAC.MethodUnsupported Type
julia
STAC.MethodUnsupported(io, method)

A transport asked for a method it cannot make. io names the AbstractIO type; a read-only one such as PathIO answers GET alone.

source
STAC.MissingAsset Type
julia
STAC.MissingAsset(key, available)

The item carries no asset under this key. available lists the keys it does carry, comma separated, since producers name the same band differently on every endpoint ("B04", "red", "B4").

source
STAC.MissingCollections Type
julia
STAC.MissingCollections(href)

The document a data link points at carries no collections array, so collections has nothing to read.

source
STAC.MissingColumn Type
julia
STAC.MissingColumn(name)

A column name no item in the table carries. The column list of an item table comes from the items themselves, so a producer key one page uses may be absent from the next.

source
STAC.MissingDatetime Type
julia
STAC.MissingDatetime(id)

The item states neither datetime nor start_datetime, so it takes no place on the time axis of a RasterSeries.

source
STAC.MissingExtension Type
julia
STAC.MissingExtension(extension, prefix, object)

The object carries none of the extension's prefix: keys, so T(obj) has no struct to build. get(obj, T) reports the same absence as nothing.

source
STAC.MissingField Type
julia
STAC.MissingField(type, field)

A field the spec requires is absent from the document and the struct has no nothing to put there.

source
STAC.MissingLink Type
julia
STAC.MissingLink(url, rel)

The landing page of url publishes no link with this rel, so the call has nothing to fetch.

source
STAC.MissingRootHref Type
julia
STAC.MissingRootHref(links)

A published link style asked for without the URL the tree will be published under. :self_contained is the style that needs none, every link in it being relative.

source
STAC.MixedResolution Type
julia
STAC.MixedResolution(keys, shapes)

The assets named for one stack sit on grids of different sizes. keys and shapes are parallel: shapes[i] is the proj:shape of keys[i], written "rows×columns".

Resampling has a right answer per dataset — nearest for a classification, an average for reflectance — so the caller makes that choice and this says which assets need it.

source
STAC.NoConformance Type
julia
STAC.NoConformance(url, class, argument, nclasses)

The endpoint's landing page lists nclasses conformance classes and class is not among them, so argument cannot be answered. Raised at the call site, ahead of the request.

source
STAC.NoDriverPackage Type
julia
STAC.NoDriverPackage(driver, package, href)

The driver that opens this asset comes from a package the session has not loaded. package names it; importing it defines the method that was missing.

source
STAC.NoOrigin Type
julia
STAC.NoOrigin(href)

A relative href with no base to resolve against, which is what an object built in memory rather than read from somewhere gives its links.

source
STAC.NoRoute Type
julia
STAC.NoRoute(scheme, href)

A StreamRouterIO with no child for this href's scheme.

source
STAC.NoToken Type
julia
STAC.NoToken(url)

The token service answered without a token key, so there is no signature to append to an href.

source
STAC.NotAGeometry Type
julia
STAC.NotAGeometry(got)

An intersects = argument that describes no place. got is the type that arrived.

source
STAC.NotARasterAsset Type
julia
STAC.NotARasterAsset(driver, href)

Raster(asset) was given a GeoJSON asset. STAC.read is what parses one.

source
STAC.NotGeoJSONAsset Type
julia
STAC.NotGeoJSONAsset(driver, package, href)

STAC.read was given an asset that is not GeoJSON. driver names what does open it and package names what to load first, so the message is the whole route to the pixels.

source
STAC.NotQueryable Type
julia
STAC.NotQueryable(got)

A STAC.query argument the index cannot turn into a box. got is the type that arrived.

source
STAC.NotSTACDocument Type
julia
STAC.NotSTACDocument(type)

The document's type key names something other than the four STAC document kinds, or the document carries no type key at all (type === nothing).

source
STAC.STACError Type
julia
STAC.STACError

Supertype of every exception this package raises, so one catch clause covers the package.

GroupRaised when
STAC.DocumentErrora document is not the STAC the call expected
STAC.LookupErrora link, key, column, or extension the call needs is absent
STAC.ArgumentShapeErroran argument has the wrong type or the wrong number of values
STAC.EndpointErroran endpoint does not offer what the call needs
julia
try
    STAC.resolve("./item.json", nothing)
catch e
    e isa STAC.STACError || rethrow()   # true: it is a `STAC.NoOrigin`
    @warn "cannot resolve" exception = e
end
source
STAC.UnknownGeometryType Type
julia
STAC.UnknownGeometryType(type, allowed)

A geometry the declared geometry = union has no member for, or one carrying no type key at all (type === nothing). allowed is the union the parse was told to build.

source
STAC.WrongDocumentType Type
julia
STAC.WrongDocumentType(expected, got)

A link led to a document of the wrong kind: an item link to a catalog, a child link to an item. Both fields are type names.

source
STAC.WrongJSONType Type
julia
STAC.WrongJSONType(expected, target)

A JSON value of the wrong kind where a struct or a vector was being built: expected is :object or :array, and target names the type the parse was filling.

source