Getting Started

Reading STAC Objects

You can read any STAC objects from URL by STAC.from_url:

catalog = STAC.from_url('https://raw.githubusercontent.com/radiantearth/stac-spec/master/examples/catalog.json')
catalog.class #=> STAC::Catalog
catalog.type #=> "Catalog"

collection = STAC.from_url('https://raw.githubusercontent.com/radiantearth/stac-spec/master/examples/collection.json')
collection.class #=> STAC::Collection
collection.type #=> "Collection"

item = STAC.from_item('https://raw.githubusercontent.com/radiantearth/stac-spec/master/examples/core-item.json')
item.class #=> STAC::Item
item.type #=> "Feature"

Also, from a local file by STAC.from_file:

catalog = STAC.from_file('/path/to/local/catalog.json')
collection = STAC.from_file('/path/to/local/collection.json')
item = STAC.from_file('/path/to/local/item.json')

STAC Object Classes

There are 3 core STAC object classes: STAC::Catalog, STAC::Collection, and STAC::Item.

They have a class method from_hash(hash), which returns its instance converted from the given Hash.

catalog = STAC::Catalog.from_hash(
  {
    'stac_version' => '1.0.0',
    'type' => 'Catalog',
    'id' => '20201211_223832_CS2',
    'description' => 'A simple catalog example',
    'links' => [],
  }
)

And they have the following instance methods in common:

Followings are shorthand methods for core links:

STAC::Catalog

STAC::Catalog has the following attributes:

catalog.id = 'awesome_catalog'
catalog.id #=> "awesome_catalog"

See STAC Catalog Specification for the details.

STAC::Catalog also has methods to crawl its links:

Note that the first 5 methods return {Enumerator::Lazy}. This is to prevent making a large number of HTTP requests when calling the methods.

catalog.collections.each do |collection|
  puts collection.id
end
collection = catalog.find_child('awesome_collection')

catalog.all_items.first(100).each do |item|
  puts item.id
end
item = catalog.find_item('awesome_item', recursive: true)

Exporting Catalog

Furthermore, STAC::Catalog has methods to create a new static STAC catalog:

catalog = STAC::Catalog.new(id: 'root', description: 'The root catalog')
catalog.self_href = 'https://example.com/catalog.json'
catalog.root = catalog

item = STAC::Item.from_hash(
  {
    'stac_version' => '1.0.0',
    'type' => 'Feature',
    'id' => 'item',
    'geometry' => nil,
    'properties' => {
      'datetime' => Time.now.iso8601
    },
    'links' => [],
    'assets' => {}
  }
)

# Add rel="item" link to catalog with href="#{item.id}.json" (based on best practice).
# And add rel="self", rel="root", and rel="parent" links to item.
catalog.add_item(item)

item.links.each { |l| puts "#{l.rel}: #{l.href}" }
# self: https://example.com/item.json
# root: https://example.com/catalog.json
# parent: https://example.com/catalog.json

sub_catalog = STAC::Catalog.new(id: 'sub-catalog', description: 'The sub catalog')

# Add rel="child" link to catalog with href="#{catalog.id}/catalog.json".
# Also add rel="self", rel="root", and rel="parent" links to sub-catalog.
catalog.add_child(sub_catalog)

sub_catalog.add_item(item.deep_dup.update(id: 'sub-item'))
sub_catalog.links.each { |l| puts "#{l.rel}: #{l.href}" }
# self: https://example.com/sub-catalog/catalog.json
# root: https://example.com/catalog.json
# parent: https://example.com/catalog.json
# item: https://example.com/sub-catalog/sub-item.json

catalog.links.each { |l| puts "#{l.rel}: #{l.href}" }
# self: https://example.com/catalog.json
# root: https://example.com/catalog.json
# item: https://example.com/item.json
# child: https://example.com/sub-catalog/catalog.json

# Exports the catalog and its children/item recursively to the given directory.
catalog.export('path/to/dest')

# $ tree path/to/dest
# path/to/dest
# ├── catalog.json
# ├── item.json
# └── sub-catalog
#     ├── catalog.json
#     └── sub-item.json

STAC::Collection

STAC::Collection inherits STAC::Catalog.

The followings are STAC::Collection specific attributes:

To add an asset, use:

STAC::Extent, STAC::Provider, and STAC::Asset provide accessors for the corresponding object’s fields.

collection.extent.spatial.bbox = [-180, -90, 180, 90]
collection.extent.spatial.bbox #=> [-180, -90, 180, 90]
collection.extent.temporal.interval = ['2022-12-01T00:00:00Z', null]
collection.extent.temporal.interval #=> ["2022-12-01T00:00:00Z", null]

collection.providers << STAC::Provider.new(name: 'sankichi92')
collection.providers.last.name #=> "sankichi92"

See STAC Collection Specification for the details.

STAC::Item

STAC::Item has the following attributes:

And has the following methods:

See STAC Item Specification for the details.

Common Metadata

STAC::Properties and STAC::Asset includes STAC::CommonMetadata, which provides read/write methods for STAC Common Metadata fields:

These methods are shorthand accessors of #extra hash:

item.properties.extra #=> {}
item.properties.title = 'Awesome Item' # same as `item.properties.extra['title'] = 'Awesome Item'`
item.properties.title #=> "Awesome Item"
item.properties.extra #=> {"title"=>"Awesome Item"}

Extensions

When an extension is added to a STAC object, methods corresponding to the extension will be added dynamically by {Object#extend}.

These methods are also shorthand accessors of extra hash same as STAC::CommonMetadata.

item.stac_extensions #=> []
item.properties.extra #=> {}
item.properties.eo_cloud_cover #=> raises NoMethodError

item.add_extension('https://stac-extensions.github.io/eo/v1.0.0/schema.json')
# same as `item.add_extension(STAC::Extensions::ElectroOptical)`

item.stac_extensions #=> ["https://stac-extensions.github.io/eo/v1.0.0/schema.json"]
item.properties.eo_cloud_cover = 1.2
item.properties.eo_cloud_cover #=> 1.2
item.properties.extra #=> {"eo:cloud_cover"=>1.2}

# item.properties extends STAC::Extensions::ElectroOptical::Properties
item.properties.is_a?(STAC::Extensions::ElectroOptical::Properties) #=> true

Currently, only 4 stable extensions have been implemented:

puts STAC::STACObject.extendables
# STAC::Extensions::ElectroOptical
# STAC::Extensions::Projection
# STAC::Extensions::ScientificCitation
# STAC::Extensions::ViewGeometry

Adding Extensions

You can add custom extensions.

Extension modules must extend STAC::Extension and set identifier and scope. And you must register it by STAC::STACObject.add_extendable(extension_module).

module MyExtension
  extend STAC::Extension

  identifier 'https://sankichi92.github.io/my_extension/v1.0.0/schema.json'
  scope STAC::Item, STAC::Collection
end

STAC::STACObject.add_extendable(MyExtension)

Then you can add methods to STAC::Properties, STAC::Asset, and STAC::Collection by defining modules with corresponding names under the extension namespace:

module MyExtension
  module Properties
    def my_field
      extra['my:field']
    end

    def my_field(val)
      extra['my:field'] = val
    end
  end

  module Asset
    include Properties
  end
end

See {lib/stac/extensions} for examples.

Using Custom HTTP Client

Custom HTTP client class must implement get: (URI | String url) -> Hash[String, untyped], which returns response JSON as a Hash:

class MyHTTPClient
  def get(url)
    # ...
  end
end

You can pass the custom HTTP client to STAC.from_url for a specific STAC object instance:

catalog = STAC.from_url('https://example.com/catalog.json', http_client: MyHTTPClient.new)

Or you can set it as the global default by STAC.default_http_client=:

STAC.default_http_client = MyHTTPClient.new

If you want to only add custom HTTP headers, you can use STAC::SimpleHTTPClient:

http_client = STAC::SimpleHTTPClient.new({ 'X-Foo' => 'Bar' })
catalog = STAC.from_url('https://example.com/catalog.json', http_client:)
STAC.default_http_client = http_client