Skip to content

PB-1677: sort extension - Add sortby query param - #663

Merged
asteiner-swisstopo merged 5 commits into
developfrom
feat-pb-1677-service-stac-implement-the-sort-extension
Sep 8, 2026
Merged

PB-1677: sort extension - Add sortby query param#663
asteiner-swisstopo merged 5 commits into
developfrom
feat-pb-1677-service-stac-implement-the-sort-extension

Conversation

@asteiner-swisstopo

Copy link
Copy Markdown
Contributor

This allows sorting items with a sortby query parameter as defined in the sort extension:

/collections/my-collection/items?sortby=created,-title

The following properties are sortable:

  • id
  • collection
  • datetime
  • title
  • created
  • updated

As we don't support Collection Search, the only affected endpoints are:

Queries in practice look like this:

# GET /collections/{collectionId}/items
curl -X GET \
  "http://127.0.0.1:8000/api/stac/v1/collections/test-collection/items?sortby=datetime"

# GET /search
curl -X GET \
  "http://127.0.0.1:8000/api/stac/v1/search?ids=test-feature-1,test-feature-2&sortby=datetime"

# POST /search
curl -X POST \
  "http://127.0.0.1:8000/api/stac/v1/search" \
  -H "Content-Type: application/json" \
  -H "Authorization: Token my-token" \
  -d '{
    "query": {
      "title": {
        "startsWith": "test-description-A"
      }
    },
    "sortby": [
      {
        "field": "datetime",
        "direction": "asc"
      }
    ]
  }'

Notes:

  • Fields are referred to as, e.g., created and not properties.created. I would find properties.created better but the "query" parameter in the /search endpoint also refers to the properties without the properties. prefix. So I favored consistency.
  • I extracted tests connected to a STAC extension from test_search_endpoint.py to test_search_endpoint_extensions.py because the file got too long.

Follow-up work:

  • Compatibility with STAC Browser
    • A /sortables endpoint listing the sortable properties
    • Advertising the sort extension in the /conformance endpoint
  • A /sortables endpoint that takes into account which stac_extensions are declared. For the moment, only core properties are supported.

@asteiner-swisstopo asteiner-swisstopo self-assigned this Sep 7, 2026
@github-actions github-actions Bot added the feature New feature or enhancement label Sep 7, 2026

@boecklic boecklic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 🎉

Adding /sortables will be in a separate PR I guess?

class GetPostCursorPagination(CursorPagination):
class SortedCursorPagination(CursorPagination):
'''Pagination class that supports sorting via the sortby parameter'''
ordering = 'name'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this declaration and initialisation correct? below it's defined as an array (which by default is empty), here it's a string..?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch but it should be fine. According to the DRF docs both works:

  • ordering = This should be a string, or list of strings, indicating the field against which the cursor based pagination will be applied. For example: ordering = 'slug'. Defaults to -created. This value may also be overridden by using OrderingFilter on the view.

Comment thread app/stac_api/utils.py
return sort_fields


def _resolve_sort_field(field_name, sortable_fields):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the other helper functions are not _* prefixed... why this one?

@asteiner-swisstopo asteiner-swisstopo Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it is only used within the same module.

According to PEP8:

  • _single_leading_underscore: weak “internal use” indicator. E.g. from M import * does not import objects whose names start with an underscore.

The other new functions are used elsewhere, so not just used "internally".

I think that is a common way to mark helper functions, so I keep it as it is.

For the moment, sorting is only allowed for the "core" properties:
- id
- collection
- properties.datetime
- properties.title
- properties.created
- properties.updated

For the other properties coming from STAC extensions we don't allow
sorting for the moment. This will be addressed in PB-2375 when we have a
proper `/sortable` endpoint.
This covers both the GET endpoint where `sortby` is a query parameter
and the POST endpoint where `sortby` is a field in the request body like

```json
{
"sortby": [
{
"field": "properties.created",
"direction": "asc"
},
{
"field": "collection",
"direction": "desc"
}
]
}
```

Also changed how the sortby param is handled in
`/collections/{collectionId}/items`: Like /search, it now validates
`sortby` upfront and stores the deserialized fields on
`view.sort_fields` before pagination. Previously
`SortedCursorPagination.get_ordering()` read and parsed `sortby` from
the request only later in the process.

`test_search_endpoint.py` exceeded pylint's `too-many-lines` (C0302), so
the forecast, CF, and sort test classes were moved to
`test_search_endpoint_extensions.py`.
Don't mention the allowed fields as the /sortable endpoint should list
that.
This is more in line with how the query extension is implemented.

For a "query" to the POST /search endpoint the following field values
are allowed:

- created
- updated
- title
- cf:standard_name
- unit

So it's not, e.g., "properties.updated" but only "updated". The "sortby"
now works the same.

The following fields are allowed for sort:

- id
- collection
- datetime
- title
- created
- updated
@asteiner-swisstopo
asteiner-swisstopo force-pushed the feat-pb-1677-service-stac-implement-the-sort-extension branch from a7bf2aa to 1e6142a Compare September 8, 2026 14:11
@asteiner-swisstopo
asteiner-swisstopo merged commit 14b7bec into develop Sep 8, 2026
7 checks passed
@asteiner-swisstopo
asteiner-swisstopo deleted the feat-pb-1677-service-stac-implement-the-sort-extension branch September 8, 2026 14:38
asteiner-swisstopo added a commit that referenced this pull request Sep 9, 2026
Follow-up of #664: Prepend `properties.` to certain parameters used in
the `sortby` query parameter and in the `/sortables` endpoint:

- `datetime` -> `properties.datetime`
- `title` -> `properties.title`
- `created` -> `properties.created`
- `updated` -> `properties.updated`
- `id` and `collection` stay unchanged (top-level fields)

In #663, we chose to omit the `properties.` prefix for the `sortby`
query parameter. So we refer to `datetime`, not `properties.datetime`.
This was because the "query" parameter of the [POST /search
endpoint](https://data.geo.admin.ch/api/stac/static/spec/v1/apitransactional.html#tag/STAC/operation/postSearchSTAC)
also omits the `properties.` prefix.

Looking into the STAC Browser code, however, I see that the
`properties.` prefix is the assumed default. I think then it would be
better to follow the STAC Browser. The Query extension will anyway be
replaced by the Filter extension (see PB-2392), so the inconsistency is
ok.
asteiner-swisstopo added a commit that referenced this pull request Sep 10, 2026
Follow-up of #664: Prepend `properties.` to certain parameters used in
the `sortby` query parameter and in the `/sortables` endpoint:

- `datetime` -> `properties.datetime`
- `title` -> `properties.title`
- `created` -> `properties.created`
- `updated` -> `properties.updated`
- `id` and `collection` stay unchanged (top-level fields)

In #663, we chose to omit the `properties.` prefix for the `sortby`
query parameter. So we refer to `datetime`, not `properties.datetime`.
This was because the "query" parameter of the [POST /search
endpoint](https://data.geo.admin.ch/api/stac/static/spec/v1/apitransactional.html#tag/STAC/operation/postSearchSTAC)
also omits the `properties.` prefix.

Looking into the STAC Browser code, however, I see that the
`properties.` prefix is the assumed default. I think then it would be
better to follow the STAC Browser. The Query extension will anyway be
replaced by the Filter extension (see PB-2392), so the inconsistency is
ok.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants