---
title: "Using the OData API"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Using the OData API}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
eval_chunks <-
  CopernicusDataspace::dse_has_client_info() &&
  CopernicusDataspace::dse_has_account() &&
  CopernicusDataspace::dse_has_s3_secret()
```

In the Copernicus Data Space Ecosystem (CDSE), OData (Open Data Protocol) is the
primary [RESTful API](https://en.wikipedia.org/wiki/REST) standard used for
searching, discovering, and downloading satellite data products.

Key functions of OData in CDSE are:

 * *Metadata Querying*: You can search for products using complex filters such
   as collection name (e.g., Sentinel-2), geographical area (AOI), acquisition
   dates, and cloud cover percentage.
 * *Data Download*: Once a specific product ID is retrieved via a search, the
   OData API can be used to trigger the actual download of the data files.

This package provides convenient wrappers to access those features, and are
described in this vignette.

The package also offers features for the complementary alternative catalogue via
STAC. For more details on that read `vignette("STAC")`.

## Searching Products

For searching products, you could simply use `dse_odata_products()`,
where you could directly add filters as arguments. But for more sophisticated
queries, you can use `dse_odata_products_request()`. It creates a special
class of `httr2` request object. In essence, it is a request to the API
server, which you can modify with tidyverse operators. This sounds more
complicated than it is.

Once you have created the request, you can add tidyverse operators (like
`filter()`, `arrange()` and `slice_head()`), to modify this request.
You can join those modifications with the pipe operator (`|>` or `%>%`).
You can also query products that intersect with specific spatial features (`sf`)
using `st_intersects()`. 

Each collection will have specific fields which you can use to filter
your product search. To discover which fields you use, call
`dse_odata_attributes()`.

All of this is shown in the example below, where we filter products
that were created after January first of 2025. Where the image overlaps
with the bounding box we specify. We create a descending arrangement of
identifiers, and select only the first 5 results. By calling `collect()`
we ensure that the request is performed and the result is returned in a
human readable form (`data.frame`).

```{r odata-search, message=FALSE, eval=eval_chunks}
library(CopernicusDataspace)
library(dplyr) # Tidiverse package for data manipulation
library(sf)    # package for handling simple (spatial) features

## Define a bounding box for our search query:
bbox <-
  st_bbox(
    c(xmin = 5.261, ymin = 52.680, xmax = 5.319, ymax = 52.715),
    crs = 4326) |>
    st_as_sfc()

## Create an API request:
dse_odata_products_request() |>
  ## Filter content on ContentDate/Start`:
  filter(
    `ContentDate/Start` > "2025-01-01") |>
  ## Only data that intersects with our bounding box:
  st_intersects(bbox) |>
  ## Arrange by descending Id:
  arrange(desc(Id)) |>
  ## Only the first 5 hits:
  slice_head(n = 5) |>
  ## Collect the results:
  collect()
```


## Burst Data

[Bursts](https://documentation.dataspace.copernicus.eu/APIs/Sentinel-1%20SLC%20Burst.html)
is a concept associated with the Sentinel-1 C-SAR instrument.
They have dedicated functions for searching for specific burst data:
`dse_odata_bursts()` and `dse_odata_bursts_request()`. These are the
equivalents of `dse_odata_products()` and `dse_odata_products_request()`.
They work with the same mechanisms and downloading them works the same as
for normal OData products, as shown below. Below a basic example of looking
for and downloading of burst data:

```{r odata-bursts, eval=FALSE}
burst_req <-
  dse_odata_bursts_request(ParentProductId == "879d445c-2c67-5b30-8589-b1f478904269")

## Note that these are large files and may take a while to download:
dse_odata_download(
  burst_req,
  tempdir()
)
```

## Exploring a Product

Once you have identified an interesting product, there are ways to further
explore it. You need the product identifier (ID) to do so. With
`dse_odata_product_nodes()` you can see which files are associated with the
product:

```{r odata-nodes, eval=eval_chunks}
dse_odata_product_nodes("c8ed8edb-9bef-4717-abfd-1400a57171a4",
                        recursive = TRUE)
```

If available you can also get a quick peek at your product by calling
`dse_odata_quicklook()`:

```{r odata-quicklook, eval=FALSE}
dse_odata_quicklook(
    "91822f33-b15c-5b60-aa39-6d9f6f5c773b",
    tempfile(fileext = ".jpg"))
```

## Downloading Data

As shown in the 'exploring' section above, products can contain 'nodes',
which could either represent a file or a directory. If you want to download
all files in such a directory you can call `dse_odata_download_path()`.
It will download all files in the specified node path. This is demonstrated
below:

```{r odata-download-path, eval=FALSE}
if (dse_has_account()) {
  dse_odata_download_path(
    product     = "2f497806-0101-5eea-83fa-c8f68bc56b0c",
    node_path   =
      paste("DEM1_SAR_DTE_90_20101213T034716_20130408T035028_ADS_000000_5033.DEM",
            "Copernicus_DSM_30_S09_00_E026_00", "DEM",
            "Copernicus_DSM_30_S09_00_E026_00_DEM.dt1", sep = "/"),
    destination = tempdir()
    )
}
```

The example above uses an alternative https route and requires a
private access token, which in turn requires your Copernicus Data Space
user id (usually your e-mail address) and password (see
`vignette("Authentication")`).

The formal OData route uses [S3 buckets](https://en.wikipedia.org/wiki/Amazon_S3
and requires S3 authentication (see `vignette("Authentication")`).
You can perform such downloads with `dse_odata_downloads()` as shown below

```{r download-odata, eval=FALSE}
if (dse_has_s3_secret()) {
  dse_odata_download(
      dse_odata_products(
        Name ==
          "S1A_IW_OCN__2SDH_20250707T210608_20250707T210625_059983_07739B_893E.SAFE"),
      destination = tempdir())
}
```
