diff --git a/doc/open-discover/open-discover.md b/doc/open-discover/open-discover.md new file mode 100644 index 0000000000000000000000000000000000000000..b588f3993c53b5ee6993d19ef42706022871616f --- /dev/null +++ b/doc/open-discover/open-discover.md @@ -0,0 +1,108 @@ +# Open Discover + +## Overview + +The Open Discover Service API (`open-api-disc`) lets a client retrieve the Service APIs currently published at the CCF, filtered by a range of optional criteria. + +It is called "Open" because, unlike the regular Discover Service API, it does not require the caller to be an onboarded API Invoker. OpenCAPIF still requires a bearer token to call it (see [Authentication](#authentication) below), but that token only needs a Register Service account — no invoker onboarding. + +## Endpoint + +``` +GET https:///open-api-disc/v1/service-apis +``` + +`` is your CCF host (for example `capifcore` inside the OpenCAPIF docker/Helm deployment). + +## Authentication + +Every request to this endpoint must carry a bearer token: + +``` +Authorization: Bearer +``` + +To obtain a token: + +1. Register a user account with the [Register Service](../register/register.md) (or use an account you already have). +2. Call `GET /getauth` on the Register Service, authenticating with HTTP Basic Auth (the username/password you registered). The response contains: + - `access_token`: a JWT to use as your bearer token. + - `ca_root`: the CA certificate to verify the CCF's TLS certificate. + - a set of convenience URLs, including `ccf_open_discover_url` (`open-api-disc/v1/service-apis`). +3. Send `access_token` as the `Authorization: Bearer` header on your Open Discover requests, verifying TLS against `ca_root`. + +Two things worth knowing about how this is enforced, so you are not surprised by the failure mode: + +- The reverse proxy in front of the CCF only checks that the `Authorization` header is present and syntactically looks like `Bearer `; it does not validate the token itself. If the header is missing entirely, you get a `401` directly from the proxy (see [Errors](#errors)). +- The Open Discover service itself validates the token's signature (RS256) but does not check that the token belongs to a specifically onboarded API Invoker — any valid token issued by the Register Service for any registered user is accepted for this endpoint. If the token is missing, expired, or has an invalid signature once it reaches the service, you get a different `401` response shape than the proxy-level one (see below). + +Unlike several other CAPIF endpoints in this platform, this route does not require a mutual-TLS client certificate. + +## Query parameters + +All parameters are optional; omitting all of them returns every published Service API. Array-valued parameters use OpenAPI "form" style with `explode: false`: pass multiple values as one comma-separated parameter, for example `api-names=service_1,service_2` — not `api-names[]=...` or bracket/JSON array syntax. + +| Parameter | Type | Description | Multiple values mean | +|---|---|---|---| +| `api-names` | array(string) | Name(s) of the target Service API(s). | Any of these names | +| `api-ids` | array(string) | Identifier(s) of the target Service APIs. | Any of these IDs | +| `api-cats` | array(string) | Category(ies) of the target Service API(s). | Any of these categories | +| `api-prov-names` | array(string) | Name(s) of the provider(s) of the target Service API(s). | Any of these provider names | +| `api-versions` | map(array(string)) | Major version(s) of the target API(s), keyed by API name (only relevant together with `api-names`). | Currently requires the API to support **all** listed versions, not just one — see caveat below | +| `comm-type` | string | Communication type supported by the target API(s) (e.g. `REQUEST_RESPONSE`). | n/a (single value only) | +| `protocols` | array(string) | Protocol(s) supported by the target API(s) (e.g. `HTTP_1_1`, `HTTP_2`). | Currently requires the API to support **all** listed protocols — see caveat below | +| `data-format` | string | Data format supported by the target API(s) (e.g. `JSON`). | n/a (single value only) | +| `preferred-aef-loc` | object | Preferred AEF location; ignored if there is no matching record. Send as a JSON object, e.g. `preferred-aef-loc={"dcId":"dc1"}`. | n/a | +| `api-supported-features` | map(object) | Feature(s) supported by the API(s) named in `api-names`, keyed by API name. Only valid together with `api-names`. | Any of the listed (API name, feature) pairs | +| `service-kpis` | object | Service characteristics of the target API(s) (e.g. `maxReqRate`, `availability`). | n/a | +| `res-ops` | array(object) | Supported resource(s)/operation(s), e.g. `{"resource":"...","operations":["GET"]}`. | n/a | +| `supported-features` | string | Client-side feature negotiation bitmap. Send only when negotiating a feature. | n/a | +| vendor-specific parameters | — | Vendor-specific query parameters, used in addition to the parameters above. | — | + +**Caveat on `api-versions` and `protocols`:** as of this writing, requesting more than one value for these two parameters returns only APIs that satisfy every listed value, rather than any one of them. Whether "any" or "all" is the intended semantics has not been confirmed against a project decision; treat this as current behaviour, not a guaranteed contract, until it is confirmed. + +**Fixed 2026-08:** `api-names`, `api-ids`, `api-cats`, and `api-prov-names` previously returned no results at all (`404`) whenever more than one value was requested, because the values were combined as if an API had to match every one simultaneously — impossible for these single-valued attributes. This has been corrected so that a multi-value request returns any API matching at least one of the listed values. + +## Errors + +All error responses use the CAPIF `ProblemDetails` shape (`title`, `status`, `detail`, `cause`, and optionally `invalidParams`). + +| Status | Cause | When it happens | +|---|---|---| +| 401 Unauthorized | `detail: "Access token not present"`, `cause: "Bearer token is required for this API route"` | No `Authorization` header sent at all (rejected by the reverse proxy, before reaching the service). | +| 401 Unauthorized / 422 | (default `flask-jwt-extended` error body, not the ProblemDetails shape) | An `Authorization: Bearer` header is present but the token is missing, malformed, expired, or has an invalid signature once it reaches the service. | +| 400 Bad Request | `detail: "Invalid query parameter format"`, `cause: "preferred-aef-loc must be sent as an application/json query parameter"` | `preferred-aef-loc` sent using bracket notation instead of a JSON object. | +| 400 Bad Request | `detail: "Invalid query parameter format"`, `cause: ` | Any other query parameter value that cannot be parsed as required (e.g. malformed JSON for an object-shaped parameter). | +| 404 Not Found | `detail: "No API Published accomplish filter conditions"` | The request is well formed, but no published Service API matches the given filters (or none are published at all). | +| 500 Internal Server Error | `detail: "An exception occurred in open discover services"`, `cause: ` | An unexpected server-side error. | + +## Example requests + +Retrieve every published Service API: + +```bash +curl -s https://capifcore/open-api-disc/v1/service-apis \ + --cacert ca_root.crt \ + -H "Authorization: Bearer $ACCESS_TOKEN" +``` + +Filter by one or more API names: + +```bash +curl -s "https://capifcore/open-api-disc/v1/service-apis?api-names=service_1,service_2" \ + --cacert ca_root.crt \ + -H "Authorization: Bearer $ACCESS_TOKEN" +``` + +Filter by preferred AEF location: + +```bash +curl -s 'https://capifcore/open-api-disc/v1/service-apis?preferred-aef-loc={"dcId":"dc1"}' \ + --cacert ca_root.crt \ + -H "Authorization: Bearer $ACCESS_TOKEN" +``` + +## Related pages + +- [Register Service](../register/register.md) — how to register a user and obtain the bearer token used above. +- [Open Discover Service API test plan](../testing/testplan/api_open_discover_service/README.md) — the automated test scenarios covering this endpoint. diff --git a/doc/releasenotes.md b/doc/releasenotes.md index 1acc8039b13b7e6a45c2b463e42f146cd6aeb280..beeb5c4c2c8921caa3caa09f06f6800a8709fee4 100644 --- a/doc/releasenotes.md +++ b/doc/releasenotes.md @@ -63,6 +63,7 @@ Additionally, this change includes minor improvements such as correctly setting ### **Testing** - 2 New tests related with use of same apiName across different AEFs. +- 6 new tests related with the new service OpenDiscover. - Duplicate test name capif_api_provider_management-10 changed. #### **Security Issues** @@ -72,10 +73,12 @@ Additionally, this change includes minor improvements such as correctly setting ### **Documentation** - 2 New tests added to [OCF Publish API test plan documentation], related with apiName. +- 6 New tests added to [OCF Open Discover API test plan documentation](https://ocf.etsi.org/documentation/latest/testing/testplan/api_open_discover_service/), related with the new service Open Discover - Changed name of capif_api_provider_management-10 to Update Registered Api Provider Without SuppFeat field - Updated expected **ProblemDetails** `detail` and `cause` error messages in test plan documentation for Discover, Events, Invoker Management, Provider Management, and Publish services to align responses with current certificate and ID validation behavior. - New test plan section related with OpenCAPIF Interconnection. - New OpenCAPIF Interconnection section under features section. +- New [Open Discover](./open-discover/open-discover.md) section added under Features, with a developer guide on how to call the Open Discover Service API (authentication, query parameters and error responses). ## **Release 4.0.0** @@ -589,6 +592,7 @@ This Release also includes a Robot Test Suite for all those services and a Postm [CICD Wiki]: https://labs.etsi.org/rep/ocf/community/-/wikis/OCF-CICD "CI/CD Wiki" [Upgrade Release 17 to 18 Wiki]: https://labs.etsi.org/rep/ocf/community/-/wikis/3GPP-Release-18-upgrade "Upgrade Release 17 to 18 Wiki" [OCF Publish API test plan documentation]: https://ocf.etsi.org/documentation/latest/testing/testplan/api_publish_service/ "OCF Publish API test plan documentation" +[OCF Open Discover API test plan documentation]: https://ocf.etsi.org/documentation/latest/testing/testplan/api_open_discover_service/ "OCF Open Discover API test plan documentation" [How to Deploy Using Helm]: ./gettingstarted/howtodeploy.md "How to Deploy Using Helm" [Download Repository]: ./gettingstarted/download.md "Download Repository" diff --git a/mkdocs.yml b/mkdocs.yml index 92f8764b8bdebfebb3a779cf4943a10967faaa34..d439508c8bb9a001a51321b956734c097354ef39 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -100,6 +100,7 @@ nav: - Event Reporting Information: ./event-req/event-req.md - Vault Certificate Management: ./vault/vault.md - OpenCAPIF Interconnection: ./interconnection/interconnection.md + - Open Discover: ./open-discover/open-discover.md - SDK: - Introduction: ./sdk/sdk_introduction.md - Requirements: ./sdk/sdk_requirements.md