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.STACSTAC.CATALOG_TYPESTAC.DEFAULT_EXTENSIONSSTAC.DEFAULT_IOSTAC.EARTHDATA_HOSTSSTAC.GENERIC_HOSTSTAC.HOST_DEFAULTSSTAC.ITEM_TYPESTAC.PC_SAS_URLSTAC.STAC_VERSIONSTAC.USER_AGENTSTAC.VSI_NETWORKSTAC.WGS84STAC.ANY_GEOMETRYSTAC.APIItemSearchSTAC.AbstractAuthSTAC.AbstractDriverSTAC.AbstractIOSTAC.AbstractItemSearchSTAC.AnyMetadataSTAC.ArgumentShapeErrorSTAC.AssetSTAC.BBox4STAC.BBox6STAC.BadBBoxSTAC.BadDateTimeSTAC.BadIntervalSTAC.BadOptionSTAC.BandSTAC.BearerTokenSTAC.CachingIOSTAC.CatalogSTAC.ClientSTAC.CollectionSTAC.CollectionExtentSTAC.ComparedByFieldsSTAC.DEFAULT_GEOMETRYSTAC.DocumentErrorSTAC.DuckDBDriverSTAC.EOSTAC.EarthdataLoginSTAC.EmptyPredicateSTAC.EndpointErrorSTAC.ExtensionSTAC.GDALDriverSTAC.GDALOptionsSTAC.GeoJSONDriverSTAC.GeoParquetDriverSTAC.HTTPIOSTAC.HeadersSTAC.HostDefaultsSTAC.ItemSTAC.ItemCollectionSTAC.ItemColumnSTAC.ItemColumnsSTAC.ItemLinesSTAC.ItemRowSTAC.ItemRowsSTAC.ItemSearchStateSTAC.LinkSTAC.LinkIteratorSTAC.LookupErrorSTAC.MetadataSTAC.MethodUnsupportedSTAC.MissingAssetSTAC.MissingCollectionsSTAC.MissingColumnSTAC.MissingDatetimeSTAC.MissingExtensionSTAC.MissingFieldSTAC.MissingLinkSTAC.MissingRootHrefSTAC.MixedResolutionSTAC.NetCDFDriverSTAC.NoAuthSTAC.NoConformanceSTAC.NoDriverPackageSTAC.NoMetadataSTAC.NoOriginSTAC.NoRouteSTAC.NoTokenSTAC.NotAGeometrySTAC.NotARasterAssetSTAC.NotGeoJSONAssetSTAC.NotQueryableSTAC.NotSTACDocumentSTAC.PageIteratorSTAC.PageStateSTAC.ParseOptionsSTAC.PathIOSTAC.PlanetaryComputerSASSTAC.ProjectionSTAC.PropertiesSTAC.ProviderSTAC.RasterSTAC.RecursiveItemsSTAC.RequestHeadersSTAC.STACErrorSTAC.STACObjectSTAC.STACStyleSTAC.STACTableSTAC.SatSTAC.ScientificSTAC.SpatialExtentSTAC.SpatialIndexSTAC.StaticItemSearchSTAC.StaticPagesSTAC.StreamRouterIOSTAC.TailedObjectSTAC.TemporalExtentSTAC.TimeIntervalSTAC.UnknownGeometryTypeSTAC.ViewSTAC.WrongDocumentTypeSTAC.WrongJSONTypeSTAC.ZarrDriverBase.empty!Base.getBase.parentDataAPI.colmetadatakeysDataAPI.metadataDataAPI.metadatakeysExtents.extentSTAC.S3IOSTAC.absolutehrefSTAC.afterschemeSTAC.assetSTAC.assethrefSTAC.authforSTAC.basemediatypeSTAC.bboxextentSTAC.bestpathSTAC.blobpartsSTAC.build_bodySTAC.catalogtypeSTAC.check_conformanceSTAC.childrenSTAC.childtypeSTAC.classifySTAC.collectionSTAC.collectionsSTAC.collectiontypeSTAC.conformanceclassesSTAC.conformsSTAC.datetime_intervalSTAC.declaresSTAC.default_ioSTAC.defaultstackSTAC.doctypeSTAC.documentnameSTAC.driverSTAC.extensiontypeSTAC.exttailSTAC.featuresearchSTAC.fetchsastokenSTAC.fieldsequalSTAC.filterpageSTAC.float64geometrySTAC.format_rfc3339STAC.fromtailSTAC.gdal_configSTAC.geojsongeometrySTAC.headersSTAC.host_defaultsSTAC.hrefdirSTAC.hrefextensionSTAC.intimerangeSTAC.iochildrenSTAC.iosummarySTAC.isabsolutehrefSTAC.isearthdataSTAC.isvsinetworkSTAC.itemcollectiontypeSTAC.itemcolumnsSTAC.itemsSTAC.itemshrefSTAC.itemtypeSTAC.jsonSTAC.leaf_extentSTAC.liftSTAC.linkhrefSTAC.localpathSTAC.matchedSTAC.nextbodySTAC.nextlinkSTAC.normalize_datetimeSTAC.numbermatchedSTAC.packageSTAC.pagesSTAC.parentdirSTAC.parseSTAC.parse_rfc3339STAC.pathhrefSTAC.percentencodeSTAC.pointextentSTAC.predicateSTAC.prefixSTAC.prefixesSTAC.querySTAC.querystringSTAC.queryvalueSTAC.readSTAC.readSTAC.readSTAC.read_geoparquetSTAC.read_ndjsonSTAC.readdocSTAC.rebuildSTAC.relativepathSTAC.rellinksSTAC.reportsmatchedSTAC.republishSTAC.requestSTAC.requestheadersSTAC.resolveSTAC.rewriteSTAC.rootSTAC.routeSTAC.sastokenSTAC.schemaSTAC.schemapartsSTAC.searchSTAC.searchSTAC.selfhrefSTAC.sethrefSTAC.spatialindexSTAC.sphereboxSTAC.staticitemsSTAC.tailkeysSTAC.urischemeSTAC.vsi_pathSTAC.vsi_prefixSTAC.withSTAC.writeSTAC.write_geoparquetSTAC.write_ndjsonSTAC.writedocumentTables.schema
STAC.STAC Module
STACA 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.
Objects
STAC.ComparedByFields Type
STAC.ComparedByFieldsThe 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.
STAC.Asset Type
AssetA 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 asrelis on a link.bands: The bands the file holds, oneBandeach, 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.
STAC.Band Type
BandOne 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.
STAC.Catalog Type
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 whatSTAC.declaresanswers 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: thechildanditemlinks a traversal walks, and theself,root, andparentlinks that place this one.metadata: The top-level keys that no field above names, in document order,stac_versionamong them.href: The absolute location the document was read from, which every relative link resolves against. A catalog built in memory hasnothing.
STAC.Collection Type
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 whatSTAC.collectionand a search'scollectionsfilter name.stac_extensions: The schema URIs of the extensions the collection declares, which is whatSTAC.declaresanswers 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: thechildanditemlinks a traversal walks, and theself,root, andparentlinks that place this one.metadata: The top-level keys that no field above names, in document order,stac_versionanditem_assetsamong them.href: The absolute location the document was read from, which every relative link resolves against. A collection built in memory hasnothing.
STAC.CollectionExtent Type
CollectionExtentThe 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.
STAC.Item Type
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.
| Parameter | Keyword | Holds |
|---|---|---|
E | extensions | a NamedTuple keyed by extension prefix, e.g. @NamedTuple{eo::Union{EO,Nothing}, proj::Union{Projection,Nothing}} |
G | geometry | the geometry types this catalog can produce, e.g. Union{Nothing, GeoJSON.Polygon{2,Float64}, GeoJSON.MultiPolygon{2,Float64}} |
M | metadata | Metadata 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 whatSTAC.declaresanswers from. It has a field of its own rather than a place in the metadata tail so thatmetadata = falseneither loses it on a write nor makesdeclaresreport 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 geometryGnames. An item that states no location hasnothing, 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 isnothingexactly whengeometryis.properties: The item's common metadata, and the tail of property keys no field of it names.links: The references to other documents: thecollection,parent, androotlinks a traversal walks up, and theselflink 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 theCollectionthe item belongs to, which thecollectionlink points at.extensions: The extensions parsed eagerly into fields, one per prefix theextensionskeyword named:item.extensions.eo.cloud_coveris a concrete field read. An extension whose keys the item carries none of reportsnothing.metadata: The top-level keys that no field above names, in document order,stac_versionamong them. An item's extension keys sit one level down, inproperties.other.href: The absolute location the document was read from, which every relative link and asset href resolves against. An item built in memory hasnothing.
STAC.ItemCollection Type
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:
| keyword | default |
|---|---|
links | Link[] |
numberMatched | nothing, since only the endpoint that ran the query knows the total |
numberReturned | length(features) |
metadata | the empty tail of M, so STAC.json writes no extra keys |
href | nothing |
features: The items on this page, in the order the producer returned them.links: The references related to the page,nextamong them, which is howSTAC.pagesasks 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 reportnothing.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 hasnothing.
STAC.Link Type
LinkOne 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";nothingmeans"GET".headers: The headers to send with the request, as aMetadatamap, since a header value is either a string or a list of strings.body: The body to send with aPOST, as the parsed JSON value.merge: Whether the body merges into the original request body (true) or replaces it (false, the default anothingstands for).metadata: The keys of this link that no field above names, in document order.
STAC.Properties Type
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.nothingsays the item covers a span instead, whichstart_datetimeandend_datetimegive.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, oneBandeach.other: The property keys that no field above names, in document order: extension keys with no eager slot, and everything the producer invented.
STAC.Provider Type
ProviderAn 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.
STAC.SpatialExtent Type
SpatialExtentWhere 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 awestgreater than itseast.metadata: The keys of this extent that no field above names, in document order.
STAC.TemporalExtent Type
TemporalExtentWhen 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 isnothing.metadata: The keys of this extent that no field above names, in document order.
STAC.fieldsequal Method
STAC.fieldsequal(a::T, b::T) -> Bool
STAC.fieldsisequal(a::T, b::T) -> Bool
STAC.fieldshash(x, h::UInt) -> UIntField-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:
x | x == x | isequal(x, x) |
|---|---|---|
an item whose bbox is finite | true | true |
an item whose bbox holds a NaN | false | true |
isequal and fieldshash agree, so an object is usable as a Dict key and unique over a vector of them means what it says.
STAC.AnyMetadata Type
STAC.AnyMetadataThe 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:
| Type | Parsed with | Holds |
|---|---|---|
Metadata | metadata = true | every unnamed key, in document order |
NoMetadata | metadata = false | nothing, 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.
STAC.Metadata Type
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> 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)STAC.NoMetadata Type
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.
Extensions
STAC.Extension Type
STAC.ExtensionSupertype 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:
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.
Base.get Method
get(obj, T::Type{<:Extension}) -> Union{T,Nothing}
T(obj) -> TThe 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.
| Call | Source |
|---|---|
item.extensions.eo | the 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.
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:` keySTAC.declares Method
STAC.declares(obj, T::Type{<:Extension}) -> Bool
STAC.declares(obj, uri::AbstractString) -> BoolWhether 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.
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 itSTAC.extensiontype Method
STAC.extensiontype(extensions::Tuple) -> TypeThe 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> 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.
STAC.exttail Method
STAC.exttail(obj) -> AnyMetadataWhere obj keeps the extension keys no field of it names, which is where an extension with no eager slot is read from.
| Object | Tail |
|---|---|
Item | properties.other, since an item's extension keys live inside properties |
Asset, Band, Catalog, Collection | metadata, the object's own unnamed keys |
STAC.fromtail Method
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.
STAC.prefix Function
STAC.prefix(::Type{<:Extension}) -> StringThe prefix: an extension's keys carry inside properties, without the colon.
STAC.schema Function
STAC.schema(::Type{<:Extension}) -> StringThe schema URI an object lists in stac_extensions to declare the extension.
STAC.schemaparts Method
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.
STAC.EO Type
EOThe Electro-Optical extension, version 2.0.0. Band descriptions moved into core bands in STAC 1.1, leaving the two cloud and snow fractions.
STAC.Projection Type
ProjectionThe 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.
STAC.Raster Type
RasterThe 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.
STAC.Sat Type
SatThe 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.
STAC.View Type
ViewThe 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.
STAC.Scientific Type
ScientificThe 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.
Documents, traversal, and the API client
STAC.doctype Method
STAC.doctype(doc::JSON.LazyValue) -> StringThe 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.
STAC.parse Method
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.
STAC.read Method
STAC.read(href; io = STAC.default_io(), extensions, geometry, metadata)
-> Catalog | Collection | Item | ItemCollectionThe 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.
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"]STAC.read Method
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.
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 holdsSTAC.rebuild Method
STAC.rebuild(obj, Val(:field), value) -> objobj 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.
item = STAC.read("test/fixtures/stac-spec/simple-item.json")
STAC.rebuild(item, Val(:links), STAC.Link[]).id == item.id # trueSTAC.sethref Method
STAC.sethref(obj, href) -> objobj with its origin set to href. Only the outer struct is rebuilt; every field is shared with the original.
STAC.LinkIterator Type
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.
STAC.RecursiveItems Type
STAC.RecursiveItemsThe 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.
Base.parent Method
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.
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 parentSTAC.children Method
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.
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"]STAC.items Method
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.
recursive | Yields |
|---|---|
false | the item links of obj itself |
true | the 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.
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.datetimeSTAC.read Method
STAC.read(T, href, io, opts) -> TThe 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.
STAC.readdoc Method
STAC.readdoc(T, bytes, opts) -> Tbytes 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.
STAC.rellinks Method
STAC.rellinks(obj, rel) -> Vector{Link}The links of obj whose rel is rel, in document order.
STAC.root Method
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.
col = STAC.read("test/fixtures/static/self-contained/simple-collection/collection.json")
STAC.root(col).id # "examples", however deep `col` sitsSTAC.GENERIC_HOST Constant
STAC.GENERIC_HOSTThe spec's own limits, used for an endpoint no STAC.HOST_DEFAULTS pattern matches.
STAC.HOST_DEFAULTS Constant
STAC.HOST_DEFAULTSThe 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.
STAC.Client Type
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.
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)).idA credentialed endpoint takes an STAC.AbstractAuth through auth =, and every later call fetches with it.
STAC.HostDefaults Type
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 =.
| Field | Meaning |
|---|---|
max_limit | the largest limit the endpoint accepts; search clamps to it |
default_limit | the page size to ask for when the caller names none |
reports_matched | whether a page carries a total, so matched is worth a request |
dotdot_ok | whether a .. segment in a path survives the endpoint's gateway |
STAC.collection Method
STAC.collection(client, id; extensions, geometry, metadata) -> CollectionOne collection by id, from <data href>/<id>.
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>/itemsSTAC.collections Method
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.
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 resolveSTAC.conformanceclasses Method
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.
STAC.conforms Method
STAC.conforms(client, class) -> BoolWhether 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.
STAC.conforms(client, "item-search") # any version
STAC.conforms(client, "https://api.stacspec.org/v1.0.0/core") # exactly this oneSTAC.host_defaults Method
STAC.host_defaults(url) -> HostDefaultsThe HostDefaults recorded for url's host, or STAC.GENERIC_HOST.
STAC.itemshref Method
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.
STAC.linkhref Method
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.
STAC.selfhref Method
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.
Search
STAC.AbstractItemSearch Type
STAC.AbstractItemSearchA 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.
| Method | Contract |
|---|---|
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.
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 setSTAC.ItemSearchState Type
STAC.ItemSearchStateWhere 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.
sourceSTAC.TimeInterval Type
STAC.TimeIntervalThe window a static search keeps items inside: NTuple{2,Union{DateTime,Nothing}}, with nothing for an open side.
STAC.build_body Method
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.
STAC.classify Method
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.
| Argument | kind |
|---|---|
nothing | :none |
Extents.Extent with X/Y, optionally Z | :bbox |
| a tuple or vector of 4 or 6 numbers | :bbox |
| any GeoInterface geometry | :intersects |
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)STAC.datetime_interval Method
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.
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)STAC.geojsongeometry Method
STAC.geojsongeometry(geom) -> GeoJSON.AbstractGeometryAny 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.
STAC.intimerange Method
STAC.intimerange(item, interval::STAC.TimeInterval) -> BoolWhether 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.
STAC.matched Method
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.
| Want | Write |
|---|---|
| the count, either way | n = STAC.matched(s), then branch on n === nothing |
| to know before paying a request | STAC.reportsmatched(s) |
| the items regardless | iterate the search; paging follows next links with or without a total |
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.
STAC.nextlink Method
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.
STAC.normalize_datetime Method
STAC.normalize_datetime(x) -> Union{String,Nothing}A datetime argument as the RFC 3339 string a STAC API takes.
| Argument | Sent |
|---|---|
nothing | nothing; the search is unbounded in time |
DateTime | the instant, in UTC, ending in Z |
Date | the full-day interval, because four of five endpoints probed reject a date-only string |
(start, stop) of DateTime, Date, or nothing | start/stop, an open side written .. |
String | passed through unchanged |
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/.."STAC.numbermatched Method
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.
STAC.pages Function
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.
page = first(STAC.pages(s)) # one request
page.features # the items it carried
page.numberReturned # how many that isSTAC.percentencode Method
STAC.percentencode(s::String) -> Strings 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.
STAC.predicate Method
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.
STAC.querystring Method
STAC.querystring(body) -> StringA search body as the query string its GET form takes: lists comma-joined, anything nested (intersects, filter, query) as JSON, everything percent-encoded.
STAC.querystring(STAC.build_body(; collections = "sentinel-2-l2a", limit = 2))
# "collections=sentinel-2-l2a&limit=2"STAC.queryvalue Method
STAC.queryvalue(v) -> StringOne 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.
STAC.reportsmatched Method
STAC.reportsmatched(s::AbstractItemSearch) -> BoolWhether 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.
STAC.APIItemSearch Type
STAC.APIItemSearchA 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.
STAC.PageIterator Type
STAC.PageIteratorThe paging loop of an STAC.APIItemSearch: one element per request, each one the next link of the previous page.
STAC.PageState Type
STAC.PageStateThe request the next iterate of a STAC.PageIterator will make, rewritten in place from each page's next link.
STAC.StaticItemSearch Type
STAC.StaticItemSearchA 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.
STAC.StaticPages Type
STAC.StaticPagesThe pages of a STAC.StaticItemSearch: the matching items cut into chunks of limit, each one an ItemCollection reporting the exact total.
STAC.check_conformance Method
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 given | Class required |
|---|---|
| any search | item-search |
filter | item-search#filter |
query | item-search#query |
sortby | item-search#sort |
fields | item-search#fields |
STAC.featuresearch Method
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.
STAC.filterpage Method
STAC.filterpage(predicate, page::ItemCollection) -> ItemCollectionpage 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.
STAC.nextbody Method
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.
STAC.search Method
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.
| Keyword | Takes |
|---|---|
collections, ids | a string or a list of strings |
intersects | a GeoInterface geometry, an Extents.Extent, a bbox of 4 or 6 numbers, or a DE-9IM predicate wrapping any of those |
datetime | see STAC.normalize_datetime |
query, filter, filter_lang, fields | the extension bodies, passed through |
sortby | "-datetime", "+id", a list of those, or the spec's {field, direction} objects |
limit | the page size, clamped to the host's cap; the host default when omitted |
method | "POST" (the default) or "GET" |
extensions, geometry, metadata | ParseOptions'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.
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 100STAC.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.
STAC.search Method
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.
| Keyword | Takes |
|---|---|
collections, ids | a string or a list of strings |
intersects | a GeoInterface geometry, an Extents.Extent, a bbox of 4 or 6 numbers, a SphericalCap, or a DE-9IM predicate wrapping any of those |
datetime | see STAC.datetime_interval |
limit | the page size; the spec's default of 100 when omitted |
manifold | Spherical() (the default) or Planar(), the space the index is built in |
io | the AbstractIO the walk fetches through |
extensions, geometry, metadata | ParseOptions's, fixing the item type |
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)))STAC.staticitems Method
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.
sourceGeometry and the spatial index
STAC.WGS84 Constant
STAC.WGS84The coordinate reference system of every STAC geometry. GeoJSON fixes longitude/latitude on WGS 84, and STAC inherits it.
sourceExtents.extent Method
Extents.extent(item::Item) -> Union{Extents.Extent,Nothing}The item's bbox as an Extents.Extent, in the key order STAC writes it.
bbox | Keys |
|---|---|
| 4 numbers | X = (west, east), Y = (south, north) |
| 6 numbers | the same, plus Z = (low, high) |
| absent | GeoInterface.extent of the geometry, or nothing when there is no geometry either |
STAC.bboxextent Method
STAC.bboxextent(bbox) -> Extents.ExtentA STAC bbox tuple as an extent, keeping the elevation interval a 6-number box carries.
STAC.float64geometry Method
STAC.float64geometry(x) -> xx 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.
STAC.leaf_extent Method
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.
STAC.lift Method
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.
| Input | Planar() | Spherical() |
|---|---|---|
Extents.Extent with X/Y | the same box | the 3D box of STAC.spherebox |
| a bbox of 4 or 6 numbers | X/Y; elevation is dropped | as above |
| a GeoInterface geometry | Extents.extent(Planar(), geom), the vertex rectangle | Extents.extent(Spherical(), geom), which follows the great circle between two vertices |
Extents.Extent with X/Y/Z | X/Y | unchanged: already on the unit sphere |
SphericalCap, UnitSphericalPoint | unsupported | unchanged |
nothing | nothing | nothing |
STAC.pointextent Method
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.
STAC.spherebox Method
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.
STAC.SpatialIndex Type
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.
STAC.query Method
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.
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"]STAC.spatialindex Method
STAC.spatialindex(manifold, items) -> SpatialIndex
STAC.spatialindex(items; manifold = GeometryOps.Spherical()) -> SpatialIndexAn 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.
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"Tables, metadata, and printing
STAC.STACTable Type
STAC.STACTableThe two things a vector of items can arrive as: the vector, and the ItemCollection page holding one.
STAC.BBox4 Type
STAC.BBox4A 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.
STAC.BBox6 Type
STAC.BBox6A 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.
STAC.ItemColumn Type
STAC.ItemColumnOne 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.
STAC.ItemColumns Type
STAC.ItemColumnsThe columns of one item table, built once and shared by every row, with a name lookup for Tables.getcolumn(row, ::Symbol).
STAC.ItemRow Type
STAC.ItemRowOne item presented as a Tables.jl row: the item itself plus the columns its table settled on.
sourceSTAC.ItemRows Type
STAC.ItemRowsA vector of Items as a Tables.jl row table. Build one with Tables.rows(items).
STAC.itemcolumns Method
STAC.itemcolumns(items) -> STAC.ItemColumnsThe 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.
| Columns | Type |
|---|---|
id, stac_extensions, geometry, collection | the item's own field types |
bbox | STAC.BBox4 or STAC.BBox6 |
every Properties field but other | the 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.other | Any |
links, assets | Vector{Link}, OrderedDict{String,Asset} |
| the keys seen in the items' own tails | Any |
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.
STAC.tailkeys Method
STAC.tailkeys(items, tailof) -> Vector{String}Every key the items' tails carry, in the order they are first seen.
sourceTables.schema Method
Tables.schema(items::AbstractVector{<:Item})
Tables.schema(page::ItemCollection)The column layout of STAC.itemcolumns, as a Tables.Schema.
STAC.TailedObject Type
STAC.TailedObjectThe objects whose unnamed keys are reachable through DataAPI.metadata: everything that carries a tail of its own.
DataAPI.colmetadatakeys Method
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.
DataAPI.metadata Method
DataAPI.metadata(obj, key[, default]; style = false) -> valueOne key of obj's metadata tail. The style is always :note, which is the style DataFrames propagates through its operations.
DataAPI.metadata(collection, "item_assets")
DataAPI.metadata(item, "s2:mgrs_tile", missing)DataAPI.metadatakeys Method
DataAPI.metadatakeys(obj) -> keysThe 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.
STAC.iochildren Method
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.
STAC.iosummary Method
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.
sourceSTAC.prefixes Method
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.
Fetching and credentials
STAC.AbstractIO Type
STAC.AbstractIOSupertype 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.
| Method | Contract |
|---|---|
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.
STAC.RequestHeaders Type
STAC.RequestHeadersThe header list a request carries: name => value pairs in the order they are sent.
STAC.authfor Method
STAC.authfor(io, href) -> AbstractAuthThe 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.
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()STAC.request Method
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.
STAC.EARTHDATA_HOSTS Constant
STAC.EARTHDATA_HOSTSThe 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.
STAC.PC_SAS_URL Constant
STAC.PC_SAS_URLThe Planetary Computer's SAS token service, which mints a read token per storage account and container.
sourceSTAC.AbstractAuth Type
STAC.AbstractAuthSupertype 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:
| Method | Answers |
|---|---|
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.
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 hrefSTAC.BearerToken Type
STAC.BearerToken(token)Authorization: Bearer <token> on every request. STAC.Headers covers an endpoint that wants a differently named header.
STAC.headers(STAC.BearerToken("s3cret"), "https://example.com")
# ["Authorization" => "Bearer s3cret"]A Client takes one through auth =, and every later call carries it.
STAC.EarthdataLogin Type
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".
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)STAC.GDALOptions Type
STAC.GDALOptionsThe GDAL configuration options one fetch needs: name => value pairs, applied to the path prefix they belong to rather than to the process.
STAC.Headers Type
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.
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 themSTAC.NoAuth Type
STAC.NoAuth()Anonymous access: no headers, no rewriting. The default of every stack STAC.default_io builds.
STAC.headers(STAC.NoAuth(), "https://example.com") # Pair{String,String}[]STAC.PlanetaryComputerSAS Type
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.
| Keyword | Meaning |
|---|---|
subscription_key | the account key sent as Ocp-Apim-Subscription-Key on the token request |
url | the token service; <url>/<account>/<container> is what one request asks for |
io | the transport the token request goes through |
margin | how 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:
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)STAC.blobparts Method
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> 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
trueSTAC.fetchsastoken Method
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.
STAC.gdal_config Method
STAC.gdal_config(auth, href) -> STAC.GDALOptionsThe 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:
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.
STAC.headers Function
STAC.headers(auth, href) -> STAC.RequestHeadersThe headers auth adds to a request for href, empty when it does not apply to that host.
STAC.isearthdata Method
STAC.isearthdata(href) -> BoolWhether href names a NASA Earthdata host, which is where EarthdataLogin sends its token.
STAC.rewrite Method
STAC.rewrite(auth, href) -> Stringhref as a reader should see it. An auth that signs a URL returns the signed form; every other auth returns href unchanged.
STAC.sastoken Method
STAC.sastoken(auth::PlanetaryComputerSAS, account, container) -> StringThe 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.
sourceSTAC.absolutehref Method
STAC.absolutehref(href) -> Stringhref as an origin worth recording: a local path becomes absolute and /-separated, anything with a scheme is left alone.
STAC.isabsolutehref Method
STAC.isabsolutehref(href) -> BoolWhether href can be fetched on its own: it carries a scheme, or it is an absolute path on this filesystem.
STAC.pathhref Method
STAC.pathhref(path) -> Stringpath 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> STAC.pathhref("catalogs/a/catalog.json")
"catalogs/a/catalog.json"STAC.resolve Method
STAC.resolve(link::Link, base) -> String
STAC.resolve(href::AbstractString, base) -> Stringhref made absolute against base, the origin of the object whose links it came from.
href | base | Result |
|---|---|---|
| carries a scheme | anything | href, unchanged |
| any | a href with a scheme | RFC 3986 reference resolution |
| an absolute path | a local path, or none | href, unchanged |
| relative | a local path | pathhref(normpath(joinpath(dirname(base), href))) |
| relative | nothing | a 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.
STAC.urischeme Method
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.
href | Scheme | Why |
|---|---|---|
"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> STAC.urischeme("https://example.com/catalog.json")
"https"
julia> STAC.urischeme("./item.json")
""STAC.PathIO Type
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.
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, typedSTAC.localpath Method
STAC.localpath(href) -> StringThe filesystem path href names, whether it was written as a plain path or as a file:// URL.
STAC.USER_AGENT Constant
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.
STAC.HTTPIO Type
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.
| Keyword | Meaning |
|---|---|
client | an HTTP.Client to pool connections through; nothing uses HTTP.jl's shared default |
retries | attempts after the first, for transient failures and retryable 4xx/5xx statuses |
connect_timeout | seconds to establish a connection; 0 disables |
request_timeout | seconds 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.
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)STAC.requestheaders Method
STAC.requestheaders(auth, href, extra) -> STAC.RequestHeadersThe 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.
STAC.CachingIO Type
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.
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 hrefBase.empty! Method
empty!(io::STAC.CachingIO)Drop every cached body, so the next read of each href goes back to the inner IO.
STAC.StreamRouterIO Type
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.
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" oneAn href whose scheme no route matches raises a STAC.NoRoute naming it.
STAC.S3IO Function
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.
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) # 35STAC.DEFAULT_IO Constant
STAC.DEFAULT_IOThe ScopedValue holding the AbstractIO that STAC.default_io returns. Rebind it for a block with STAC.with.
STAC.default_io Method
STAC.default_io() -> AbstractIOThe 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.
STAC.defaultstack Function
STAC.defaultstack(auth = STAC.NoAuth()) -> AbstractIOA 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.
STAC.with Method
STAC.with(f, io::AbstractIO)Run f() with io as STAC.default_io.
stack = STAC.CachingIO(STAC.StreamRouterIO(("https" => STAC.HTTPIO(STAC.BearerToken(tok)),)))
STAC.with(stack) do
STAC.read("https://example.com/catalog.json")
endParsing and writing JSON
STAC.ANY_GEOMETRY Type
STAC.ANY_GEOMETRYEvery 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.
STAC.DEFAULT_EXTENSIONS Constant
STAC.DEFAULT_EXTENSIONSThe 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.
STAC.DEFAULT_GEOMETRY Type
STAC.DEFAULT_GEOMETRYThe 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.
STAC.STAC_VERSION Constant
STAC.STAC_VERSIONThe stac_version written on objects whose tail carries none.
STAC.ParseOptions Type
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.
| Keyword | Accepts | Becomes |
|---|---|---|
extensions | a tuple of STAC.Extension structs; () for none | E |
geometry | a geometry type, a union of them, or GeoJSON.AbstractGeometry for STAC.ANY_GEOMETRY | G |
metadata | true to keep unnamed keys, false to skip them | M |
STAC.catalogtype Method
STAC.catalogtype(opts::ParseOptions) -> Type{<:Catalog}The Catalog{M} these options name.
STAC.childtype Method
STAC.childtype(opts::ParseOptions) -> TypeWhat 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.
STAC.collectiontype Method
STAC.collectiontype(opts::ParseOptions) -> Type{<:Collection}The Collection{M} these options name.
STAC.itemcollectiontype Method
STAC.itemcollectiontype(opts::ParseOptions) -> Type{<:ItemCollection}The ItemCollection{E,G,M} these options name.
STAC.itemtype Method
STAC.itemtype(opts::ParseOptions) -> Type{<:Item}The Item{E,G,M} these options name.
STAC.STACStyle Type
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
liftforDateTime, accepting any number of fractional digits and both theZand±HH:MMoffset forms;makemethods 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 (seeparse/sinks.jl).
STAC.format_rfc3339 Method
STAC.format_rfc3339(dt::DateTime) -> StringA 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.
STAC.parse_rfc3339 Method
STAC.parse_rfc3339(s::AbstractString) -> DateTimeAn 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.
sourceSTAC.json Method
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.
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")Drivers and bulk formats
STAC.VSI_NETWORK Constant
STAC.VSI_NETWORKThe 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.
STAC.AbstractDriver Type
STAC.AbstractDriverSupertype 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.
| Driver | Opens | Package |
|---|---|---|
STAC.GDALDriver | GeoTIFF, JPEG 2000, and everything else GDAL reads, local or remote | Rasters, ArchGDAL |
STAC.NetCDFDriver | a local NetCDF or HDF5 file | Rasters, NCDatasets |
STAC.ZarrDriver | a Zarr store | Rasters, ZarrDatasets |
STAC.GeoJSONDriver | GeoJSON, through STAC.read and the IO stack | STAC itself |
STAC.GeoParquetDriver | a flat GeoParquet file | GeoParquet |
STAC.DuckDBDriver | a stac-geoparquet file, whose nested columns need SQL | DuckDB |
STAC.DuckDBDriver Type
STAC.DuckDBDriver()A stac-geoparquet file, whose links and assets columns are nested structs that SQL reads and a flat parquet reader does not.
STAC.GDALDriver Type
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.
STAC.GeoJSONDriver Type
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.
STAC.GeoParquetDriver Type
STAC.GeoParquetDriver()A flat GeoParquet file, one row per feature with a WKB geometry column.
sourceSTAC.NetCDFDriver Type
STAC.NetCDFDriver()The NetCDF library reads the asset. Local files only: a NetCDF or HDF5 asset behind a URL goes to STAC.GDALDriver.
STAC.ZarrDriver Type
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.
STAC.afterscheme Method
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.
STAC.asset Method
STAC.asset(item, key) -> AssetThe 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.
STAC.assethref Method
STAC.assethref(asset) -> StringThe 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.
STAC.basemediatype Method
STAC.basemediatype(type) -> StringA 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.
STAC.driver Method
STAC.driver(asset) -> AbstractDriverThe 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:
| Rule | Why |
|---|---|
a NetCDF or HDF5 asset behind a URL goes to STAC.GDALDriver | GDAL range-reads it; the NetCDF library downloads the file whole |
| the media type wins over the extension | producers publish .tif assets that are really application/x-netcdf subdatasets |
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()STAC.hrefextension Method
STAC.hrefextension(href) -> StringThe 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.
STAC.isvsinetwork Method
STAC.isvsinetwork(filename) -> BoolWhether GDAL would fetch this path over the network.
julia> STAC.isvsinetwork("/vsis3/usgs-landsat/c2/B4.TIF")
true
julia> STAC.isvsinetwork("/data/B4.tif")
falseSTAC.package Method
STAC.package(driver) -> StringThe 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> STAC.package(STAC.GDALDriver())
"Rasters, ArchGDAL"STAC.read_geoparquet Function
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.
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)STAC.route Method
STAC.route(driver, asset, io) -> (; filename, source, config)
STAC.route(asset, io)What the opener needs to read asset, as three values:
| Field | Holds |
|---|---|
filename | the path or URL the opener takes, signed and in GDAL's virtual filesystem spelling |
source | the Rasters.jl backend symbol: :gdal, :netcdf, :zarr, or :geojson for the core reader |
config | the 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.
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 # :gdalThe 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.
STAC.vsi_path Method
STAC.vsi_path(scheme, href) -> Stringhref as GDAL's virtual filesystem names it.
| Scheme | Path |
|---|---|
"" | 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 else | href unchanged, for GDAL's own prefixes such as NETCDF: |
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"STAC.vsi_prefix Method
STAC.vsi_prefix(filename) -> StringThe 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> 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/"STAC.write_geoparquet Function
STAC.write_geoparquet(path, items) -> Stringitems 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.
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)))STAC.ItemLines Type
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.
STAC.read_ndjson Method
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.
| Source | Handle |
|---|---|
| a path | opened 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 IO | yours: the iterator picks up where the stream stands and leaves it open |
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)))STAC.write_ndjson Method
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.
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")]STAC.CATALOG_TYPE Constant
STAC.CATALOG_TYPEThe media type of a catalog or collection document, which is what the hierarchy links STAC.write writes carry.
STAC.ITEM_TYPE Constant
STAC.ITEM_TYPEThe 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.
STAC.bestpath Method
STAC.bestpath(obj, parentdir, isroot) -> StringWhere 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.
obj | Path |
|---|---|
| the root of the tree | catalog.json, collection.json, or <id>.json |
| a child catalog or collection | <parentdir>/<id>/catalog.json, …/collection.json |
| an item | <parentdir>/<id>/<id>.json |
STAC.documentname Method
STAC.documentname(obj) -> StringThe file name the best-practices layout gives a document: catalog.json, collection.json, or <item-id>.json.
STAC.hrefdir Method
STAC.hrefdir(href) -> StringEverything up to and including the last / of href: the directory a relative link beside it resolves against. An href with no / gives "".
STAC.parentdir Method
STAC.parentdir(path) -> StringThe directory of a /-separated relative path, "" for a document at the top of the tree.
STAC.relativepath Method
STAC.relativepath(to, fromdir) -> StringThe /-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> STAC.relativepath("catalog.json", "simple-collection")
"../catalog.json"
julia> STAC.relativepath("simple-collection/simple-item.json", "simple-collection")
"./simple-item.json"STAC.republish Method
STAC.republish(p, obj, path, parent, collection, root, childpaths, itempaths) -> objobj 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.
STAC.write Method
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.
dest | Writes |
|---|---|
a path ending in .json | obj alone, exactly as STAC.json renders it |
| any other path | obj 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.
layout | Puts |
|---|---|
:best (default) | catalog.json, then <collection-id>/collection.json, then <item-id>/<item-id>.json |
:keep | each object where it was read from, relative to the root's origin |
(obj, parent_dir) -> path | wherever the function says, as a /-separated path under dest. parent_dir is nothing for the root and the parent's directory below it |
links | Writes |
|---|---|
:self_contained (default) | no self links; every hierarchy link relative. The tree moves anywhere |
:relative_published | one absolute self on the root; every hierarchy link relative |
:absolute_published | an 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.
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)))STAC.writedocument Method
STAC.writedocument(path, obj) -> Stringobj written to path as one indented STAC JSON document, and the path it went to. Missing directories are created.
Errors
STAC.ArgumentShapeError Type
STAC.ArgumentShapeErrorAn 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.
STAC.BadBBox Type
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.
STAC.BadDateTime Type
STAC.BadDateTime(value)A date-time string RFC 3339 rejects, from a document's datetime or from a datetime = argument.
STAC.BadInterval Type
STAC.BadInterval(n)A datetime = interval of n values, where an interval is a start and a stop.
STAC.BadOption Type
STAC.BadOption(option, value, allowed)A keyword given a value outside the set it takes. allowed lists the set, spelled as the values themselves.
STAC.DocumentError Type
STAC.DocumentErrorThe 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.
STAC.EmptyPredicate Type
STAC.EmptyPredicate(predicate)A DE-9IM predicate wrapping no geometry, which is the Within() singleton rather than the Within(polygon) a search compares against.
STAC.EndpointError Type
STAC.EndpointErrorThe 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.
sourceSTAC.LookupError Type
STAC.LookupErrorA 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.
STAC.MethodUnsupported Type
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.
STAC.MissingAsset Type
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").
STAC.MissingCollections Type
STAC.MissingCollections(href)The document a data link points at carries no collections array, so collections has nothing to read.
STAC.MissingColumn Type
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.
sourceSTAC.MissingDatetime Type
STAC.MissingDatetime(id)The item states neither datetime nor start_datetime, so it takes no place on the time axis of a RasterSeries.
STAC.MissingExtension Type
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.
STAC.MissingField Type
STAC.MissingField(type, field)A field the spec requires is absent from the document and the struct has no nothing to put there.
STAC.MissingLink Type
STAC.MissingLink(url, rel)The landing page of url publishes no link with this rel, so the call has nothing to fetch.
STAC.MissingRootHref Type
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.
STAC.MixedResolution Type
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.
sourceSTAC.NoConformance Type
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.
STAC.NoDriverPackage Type
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.
STAC.NoOrigin Type
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.
sourceSTAC.NoRoute Type
STAC.NoRoute(scheme, href)A StreamRouterIO with no child for this href's scheme.
STAC.NoToken Type
STAC.NoToken(url)The token service answered without a token key, so there is no signature to append to an href.
STAC.NotAGeometry Type
STAC.NotAGeometry(got)An intersects = argument that describes no place. got is the type that arrived.
STAC.NotARasterAsset Type
STAC.NotARasterAsset(driver, href)Raster(asset) was given a GeoJSON asset. STAC.read is what parses one.
STAC.NotGeoJSONAsset Type
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.
STAC.NotQueryable Type
STAC.NotQueryable(got)A STAC.query argument the index cannot turn into a box. got is the type that arrived.
STAC.NotSTACDocument Type
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).
STAC.STACError Type
STAC.STACErrorSupertype of every exception this package raises, so one catch clause covers the package.
| Group | Raised when |
|---|---|
STAC.DocumentError | a document is not the STAC the call expected |
STAC.LookupError | a link, key, column, or extension the call needs is absent |
STAC.ArgumentShapeError | an argument has the wrong type or the wrong number of values |
STAC.EndpointError | an endpoint does not offer what the call needs |
try
STAC.resolve("./item.json", nothing)
catch e
e isa STAC.STACError || rethrow() # true: it is a `STAC.NoOrigin`
@warn "cannot resolve" exception = e
endSTAC.UnknownGeometryType Type
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.
STAC.WrongDocumentType Type
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.
STAC.WrongJSONType Type
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.