Open-EO / openeo-api

The openEO API specification
http://api.openeo.org
Apache License 2.0
91 stars 11 forks source link

Conformance classes instead of endpoint list #506

Open m-mohr opened 1 year ago

m-mohr commented 1 year ago

I'm wondering whether we can "easily" align better with OGC APIs by deprecating the endpoints entry in GET / and replace it with conformance classes in the long-term (2.0). In the short term (1.x) we would deprecate the existing functionality and add the new one.

I could imaging it working like this: Instead of specifying the method and path, you use the operation ID specified in the OpenAPI document.

For this I'm wondering, what the endpoint list is currently used for and by which software component.

Example

Before

{
  "conformsTo": [
    "https://api.openeo.org/1.2.0",
    "https://api.openeo.org/extensions/commercial-data/0.1.0",
    "https://api.openeo.org/extensions/federation/0.1.0",
    "https://api.stacspec.org/v1.0.0/collections"
  ],
  "endpoints": [
    {
      "path": "/collections",
      "methods": [
        "GET"
      ]
    },
    {
      "path": "/collections/{collection_id}",
      "methods": [
        "GET"
      ]
    },
    {
      "path": "/processes",
      "methods": [
        "GET"
      ]
    },
    {
      "path": "/jobs",
      "methods": [
        "GET",
        "POST"
      ]
    },
    {
      "path": "/jobs/{job_id}",
      "methods": [
        "GET",
        "DELETE",
        "PATCH"
      ]
    },
    {
      "path": "/credentials/basic",
      "methods": [
        "GET"
      ]
    }
  ]
}

After

{
  "conformsTo": [
    "https://api.openeo.org/1.2.0",
    "https://api.openeo.org/1.2.0/operations/list-collections",
    "https://api.openeo.org/1.2.0/operations/describe-collection",
    "https://api.openeo.org/1.2.0/operations/list-processes",
    "https://api.openeo.org/1.2.0/operations/list-jobs",
    "https://api.openeo.org/1.2.0/operations/create-job",
    "https://api.openeo.org/1.2.0/operations/describe-job",
    "https://api.openeo.org/1.2.0/operations/update-job",
    "https://api.openeo.org/1.2.0/operations/delete-job",
    "https://api.openeo.org/1.2.0/operations/authenticate-basic",
    "https://api.openeo.org/extensions/commercial-data/0.1.0",
    "https://api.openeo.org/extensions/federation/0.1.0",
    "https://api.stacspec.org/v1.0.0/collections"
  ]
}

Thoughts?

soxofaan commented 1 year ago

In python client, there are two explicit cases of checking the endpoints:

Apart from that, there is also a user facing API to list and check endpoints (e.g. RESTCapabilities.list_features()), But it dates back from very early in the project (2018), I haven't it seen being used, I actually just found out by researching it for this issue, and it is not listed in the official API docs. I think we can safely consider this being completely unused.

soxofaan commented 1 year ago

In the aggregator:

The aggregator generates its own endpoint listing independently from the endpoint listings of upstream backends.

Apart from that I couldn't find anything else that could be relevant here

soxofaan commented 1 year ago

In general, I kind of like the old style with explicit "path": "...", "methods": [ ...] listings as it is fully self-contained. With the "conformsTo" URLs, the client is kind of required to request and parse a whole bunch of additional URLs to get the same information.

m-mohr commented 3 weeks ago

I think we'll need to adopt this at some point for alignment with OGC APIs and deprecate our endpoint list.

We can probably simplify it, so that it's easier to translate endpoints to URLs 1:1 (i.e. it uses a template https://api.openeo.org/{apiVersion}/endpoints/{httpMethod}/{endpoint})

So for example:

{
  "conformsTo": [
    "https://api.openeo.org/1.2.0",
    "https://api.openeo.org/1.2.0/endpoints/get/collections",
    "https://api.openeo.org/1.2.0/endpoints/get/collections/{collection_id}",
    "https://api.openeo.org/1.2.0/endpoints/get/processes",
    "https://api.openeo.org/1.2.0/endpoints/get/jobs",
    "https://api.openeo.org/1.2.0/endpoints/post/jobs",
    "https://api.openeo.org/1.2.0/endpoints/get/jobs/{job_id}",
    "https://api.openeo.org/1.2.0/v/delete/jobs/{job_id}",
    "https://api.openeo.org/1.2.0/endpoints/patch/jobs/{job_id}",
    "https://api.openeo.org/1.2.0/endpoints/get/credentials/basic",
    "https://api.openeo.org/extensions/commercial-data/0.1.0",
    "https://api.openeo.org/extensions/federation/0.1.0",
    "https://api.stacspec.org/v1.0.0/collections"
  ]
}

so for example if you have supports(method: str, path: str) : bool you could simply so something like:

def supports(method: str, path: str) -> bool:
  escaped_path = path.replace("{", "\{").replace("}", "\}")
  method = method.lower()
  pattern = f"https://api.openeo.org/[^/]+/{method}/{escaped_path}"
  for c in conformsTo:
    if c.match(pattern):
      return True
  return False

supports("GET", "/collections")
soxofaan commented 3 weeks ago

I'm fine with this if it's acceptable to just (naively) parse the listed conformsTo URLs, without having to actually request them and inspect their responses

m-mohr commented 3 weeks ago

Sure, conformance classes often don't resovle in OGC land anyway. They will likely just give 404s or resolve to something that's not overly useful...