From 8227362f257469048ab844a439e33d76bd0080e4 Mon Sep 17 00:00:00 2001 From: Herbert Damker <52109189+hdamker@users.noreply.github.com> Date: Wed, 25 Mar 2026 23:28:10 +0100 Subject: [PATCH 1/3] fix: restructure artifacts directory for $ref consumption (#603) Phase 1 of artifacts restructuring: - Move CAMARA_common.yaml to artifacts/common/ directory - Add api-templates/sample-service.yaml demonstrating $ref consumption - Update documentation references to new path The sample-service template demonstrates two patterns for error responses: - Option A: pure $ref for responses using only generic error codes - Option B: local response definition extending generic errors with API-specific codes (ResourceNotFound404 example) Next steps (after #604 merges): - Add CAMARA_event_common.yaml with CloudEvent/Source/DateTime schemas - Add notification-templates/sample-notification.yaml - Add event-related API templates (implicit events, subscriptions) - Migrate camara-cloudevents/ content to new structure --- README.md | 5 +- artifacts/api-templates/sample-service.yaml | 232 ++++++++++++++++++++ artifacts/{ => common}/CAMARA_common.yaml | 0 documentation/CAMARA-API-Design-Guide.md | 8 +- 4 files changed, 239 insertions(+), 6 deletions(-) create mode 100644 artifacts/api-templates/sample-service.yaml rename artifacts/{ => common}/CAMARA_common.yaml (100%) diff --git a/README.md b/README.md index 59942820..0d296649 100644 --- a/README.md +++ b/README.md @@ -21,10 +21,11 @@ The documents that are relevant for CAMARA API Repositories are found in the `do The `artifacts` directory contains: * templates for creating Github issues -* common data and error formats for CAMARA APIs in [CAMARA_common.yaml](artifacts/CAMARA_common.yaml) +* common data and error formats for CAMARA APIs in [CAMARA_common.yaml](artifacts/common/CAMARA_common.yaml) +* API templates demonstrating `$ref` consumption of common schemas: in [artifacts/api-templates](artifacts/api-templates) folder * notification subscription template: [event-subscription-template.yaml](artifacts/camara-cloudevents/event-subscription-template.yaml) * OAS definition of CAMARA Event using CloudEvents: [notification-as-cloud-event.yaml](artifacts/notification-as-cloud-event.yaml) -* Common artifacts for testing error scenarios for device and phoneNumber: in [artifacts/testing](artifacts/testing) folder +* Common artifacts for testing error scenarios for device and phoneNumber: in [artifacts/testing](artifacts/testing) folder ### Frequently-accessed output documents diff --git a/artifacts/api-templates/sample-service.yaml b/artifacts/api-templates/sample-service.yaml new file mode 100644 index 00000000..0bdacb5b --- /dev/null +++ b/artifacts/api-templates/sample-service.yaml @@ -0,0 +1,232 @@ +openapi: 3.0.3 +info: + title: Sample CAMARA Service API + description: | + Template for a request-response CAMARA API. + + Copy this file to your API repository's `code/API_definitions/` directory + and adapt it to your API's resources and operations. + + This template demonstrates: + - `$ref` to `../common/CAMARA_common.yaml` for shared schemas, error responses, + parameters, headers, and security schemes + - Two options for error responses: + - Option A: Pure `$ref` for responses using only generic error codes + - Option B: Local response definition extending generic errors with API-specific codes + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + version: wip + x-camara-commonalities: 0.7.0 +servers: + - url: "{apiRoot}/sample-service/vwip" + variables: + apiRoot: + default: http://localhost:9091 + description: API root, Apache 2.0 licensed +tags: + - name: Resources + description: Operations on sample resources +security: + - openId: + - sample-service:resource:read + - sample-service:resource:write +paths: + /resources: + post: + tags: + - Resources + summary: Create a resource + description: Creates a new resource with the provided properties. + operationId: createResource + parameters: + - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/CreateResource" + responses: + "201": + description: Resource created + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + $ref: "#/components/schemas/Resource" + "400": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic400" + "401": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic401" + "403": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic403" + "409": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic409" + "422": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic422" + "429": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic429" + "500": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic500" + get: + tags: + - Resources + summary: List resources + description: Returns a list of all resources accessible to the API consumer. + operationId: listResources + parameters: + - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" + responses: + "200": + description: List of resources + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/Resource" + "401": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic401" + "403": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic403" + "500": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic500" + /resources/{resourceId}: + get: + tags: + - Resources + summary: Get a resource by ID + description: Returns the details of a specific resource identified by its ID. + operationId: getResource + parameters: + - $ref: "#/components/parameters/ResourceId" + - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" + responses: + "200": + description: Resource details + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + $ref: "#/components/schemas/Resource" + "401": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic401" + "403": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic403" + # Option A — pure $ref for responses using only generic error codes + "404": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic404" + "500": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic500" + delete: + tags: + - Resources + summary: Delete a resource + description: Deletes a specific resource identified by its ID. + operationId: deleteResource + parameters: + - $ref: "#/components/parameters/ResourceId" + - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" + responses: + "204": + description: Resource deleted + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + "401": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic401" + "403": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic403" + # Option B — local response extending generic errors with API-specific codes + "404": + $ref: "#/components/responses/ResourceNotFound404" + "500": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic500" +components: + securitySchemes: + openId: + $ref: "../common/CAMARA_common.yaml#/components/securitySchemes/openId" + responses: + # Option B example: API-specific error response extending generic error codes. + # Use this pattern when an operation needs API-specific error codes in addition + # to the generic ones defined in CAMARA_common.yaml. + ResourceNotFound404: + description: Resource not found + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 404 + code: + enum: + - NOT_FOUND + - IDENTIFIER_NOT_FOUND + examples: + GENERIC_404_NOT_FOUND: + description: The specified resource was not found + value: + status: 404 + code: NOT_FOUND + message: The specified resource is not found. + RESOURCE_404_IDENTIFIER_NOT_FOUND: + description: API-specific — some identifier cannot be matched to a resource + value: + status: 404 + code: IDENTIFIER_NOT_FOUND + message: Some of the provided identifiers are not found. + parameters: + ResourceId: + name: resourceId + in: path + required: true + description: Identifier of the resource to operate on + schema: + $ref: "#/components/schemas/ResourceId" + schemas: + ResourceId: + type: string + format: uuid + description: Unique identifier for the resource + CreateResource: + description: Properties for creating a new resource + type: object + required: + - name + properties: + name: + type: string + maxLength: 128 + description: Human-readable name for the resource + device: + $ref: "../common/CAMARA_common.yaml#/components/schemas/Device" + Resource: + description: A resource managed by the API + type: object + required: + - resourceId + - name + properties: + resourceId: + $ref: "#/components/schemas/ResourceId" + name: + type: string + maxLength: 128 + description: Human-readable name for the resource + device: + $ref: "../common/CAMARA_common.yaml#/components/schemas/Device" diff --git a/artifacts/CAMARA_common.yaml b/artifacts/common/CAMARA_common.yaml similarity index 100% rename from artifacts/CAMARA_common.yaml rename to artifacts/common/CAMARA_common.yaml diff --git a/documentation/CAMARA-API-Design-Guide.md b/documentation/CAMARA-API-Design-Guide.md index 805d21ba..3db28041 100644 --- a/documentation/CAMARA-API-Design-Guide.md +++ b/documentation/CAMARA-API-Design-Guide.md @@ -87,7 +87,7 @@ that this point is open to continuous evolution over time through the addition o To allow for proper management of this ever-evolving list, an external repository has been defined to that end. This repository is referenced below. -[Link to Common Data Types documentation repository](../artifacts/CAMARA_common.yaml) +[Link to Common Data Types documentation repository](../artifacts/common/CAMARA_common.yaml) ### 2.2. Data Definitions @@ -370,7 +370,7 @@ An error representation MUST NOT differ from the representation of any resource. All these aforementioned fields are mandatory in Error Responses. `status` and `code` fields have normative nature, so as their use has to be standardized (see [3.2.1. Standardized use of CAMARA error responses](#321-standardized-use-of-camara-error-responses)). On the other hand, `message` is informative and within this document an example is shown. -The values of the `status` and `code` fields are normative (i.e. they have a set of allowed values), as defined in [CAMARA_common.yaml](../artifacts/CAMARA_common.yaml). +The values of the `status` and `code` fields are normative (i.e. they have a set of allowed values), as defined in [CAMARA_common.yaml](../artifacts/common/CAMARA_common.yaml). An example of JSON error structure is as follows: @@ -487,7 +487,7 @@ The Following table compiles the guidelines to be adopted: | 5 | An identifier is not included in the request and the device or phone number identification cannot be derived from the 3-legged access token | 422 | MISSING_IDENTIFIER | The device cannot be identified. | **NOTE:** -The `Device` object defined in [CAMARA_common.yaml](/artifacts/CAMARA_common.yaml) allows the API consumer to provide more than one device identifier. This is to allow the API consumer to provide additional information to a given API provider that might be useful for their implementation of the API, or to different API providers who might prefer different identifier types, or might not support all possible device identifiers. +The `Device` object defined in [CAMARA_common.yaml](/artifacts/common/CAMARA_common.yaml) allows the API consumer to provide more than one device identifier. This is to allow the API consumer to provide additional information to a given API provider that might be useful for their implementation of the API, or to different API providers who might prefer different identifier types, or might not support all possible device identifiers. Where an API consumer provides more than one device identifier, it is RECOMMENDED that the API provider include in the response a single device identifier (from those provided) which they are using to fulfil the API. This would apply even if the device identifiers do not all match the same device, as the API provider does not perform any logic to validate/correlate that the indicated device identifiers match the same device. @@ -1398,7 +1398,7 @@ Make the information available: When an API requires a User (as defined by the [ICM Glossary](https://github.com/camaraproject/IdentityAndConsentManagement/blob/r3.3/documentation/CAMARA-API-access-and-user-consent.md#glossary-of-terms-and-concepts)) to be identified in order to get access to that User's data (as Resource Owner), the User can be identified in one of two ways: - If the access token is a Three-Legged Access Token, then the User will already have been associated with that token by the API provider, which in turn may be identified from the physical device that calls the `/authorize` endpoint for the OIDC authorisation code flow, or from the `login_hint` parameter of the OIDC CIBA flow (which can be a device IP, phone number or operator token). The `sub` claim of the ID token returned with the access token will confirm that an association with the User has been made, although this will not identify the User directly given that the `sub` will not be a globally unique identifier nor contain PII as per the [CAMARA Security and Interoperability Profile](https://github.com/camaraproject/IdentityAndConsentManagement/blob/r3.3/documentation/CAMARA-Security-Interoperability.md#id-token-sub-claim) requirements. -- If the access token is a Two-Legged Access Token, no User is associated with the token, and hence an explicit identifier MUST be provided. This is typically either a `Device` object named `device`, or a `PhoneNumber` string named `phoneNumber`. Both of these schema are defined in the [CAMARA_common.yaml](/artifacts/CAMARA_common.yaml) artifact. In both cases, it is the User that is being identified, although the `device` identifier allows this indirectly by identifying an active physical device. +- If the access token is a Two-Legged Access Token, no User is associated with the token, and hence an explicit identifier MUST be provided. This is typically either a `Device` object named `device`, or a `PhoneNumber` string named `phoneNumber`. Both of these schema are defined in the [CAMARA_common.yaml](/artifacts/common/CAMARA_common.yaml) artifact. In both cases, it is the User that is being identified, although the `device` identifier allows this indirectly by identifying an active physical device. If an API provider issues Three-Legged Access Tokens for use with the API, the following error may occur: - **Both a Three-Legged Access Token and an explicit User identifier (device or phone number) are provided by the API consumer.** From 21bfac90cf44e7c280884e4bc4dcaf8c8d71a4ff Mon Sep 17 00:00:00 2001 From: Herbert Damker <52109189+hdamker@users.noreply.github.com> Date: Tue, 31 Mar 2026 14:52:41 +0200 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20Phase=202=20=E2=80=94=20event=20and?= =?UTF-8?q?=20subscription=20schemas=20restructured=20for=20$ref=20consump?= =?UTF-8?q?tion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add artifacts/common/CAMARA_event_common.yaml with CloudEvents envelope, subscription management, protocol settings, credentials, lifecycle data, and subscription-specific error responses - Add artifacts/api-templates/sample-service-subscriptions.yaml (624 lines, down from 1397 — 55% reduction via $ref to common files) - Add artifacts/notification-templates/sample-notification.yaml (77 lines, replacing 345-line notification-as-cloud-event.yaml) - Add DateTime schema to CAMARA_common.yaml - Switch common files to components-only format (no openapi/paths stub) - Move event-subscription-template.feature to artifacts/testing/ - Remove notification-as-cloud-event.yaml and camara-cloudevents/ directory - Update README.md with new directory structure --- README.md | 14 +- .../sample-service-subscriptions.yaml | 624 ++++++++ .../event-subscription-template.yaml | 1397 ----------------- artifacts/common/CAMARA_common.yaml | 20 +- artifacts/common/CAMARA_event_common.yaml | 610 +++++++ artifacts/notification-as-cloud-event.yaml | 344 ---- .../sample-notification.yaml | 77 + .../event-subscription-template.feature | 0 8 files changed, 1335 insertions(+), 1751 deletions(-) create mode 100644 artifacts/api-templates/sample-service-subscriptions.yaml delete mode 100644 artifacts/camara-cloudevents/event-subscription-template.yaml create mode 100644 artifacts/common/CAMARA_event_common.yaml delete mode 100644 artifacts/notification-as-cloud-event.yaml create mode 100644 artifacts/notification-templates/sample-notification.yaml rename artifacts/{camara-cloudevents => testing}/event-subscription-template.feature (100%) diff --git a/README.md b/README.md index 0d296649..368a6f9a 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,15 @@ The documents that are relevant for CAMARA API Repositories are found in the `do The `artifacts` directory contains: * templates for creating Github issues -* common data and error formats for CAMARA APIs in [CAMARA_common.yaml](artifacts/common/CAMARA_common.yaml) -* API templates demonstrating `$ref` consumption of common schemas: in [artifacts/api-templates](artifacts/api-templates) folder -* notification subscription template: [event-subscription-template.yaml](artifacts/camara-cloudevents/event-subscription-template.yaml) -* OAS definition of CAMARA Event using CloudEvents: [notification-as-cloud-event.yaml](artifacts/notification-as-cloud-event.yaml) -* Common artifacts for testing error scenarios for device and phoneNumber: in [artifacts/testing](artifacts/testing) folder +* common data types and error formats for CAMARA APIs in [artifacts/common](artifacts/common): + * [CAMARA_common.yaml](artifacts/common/CAMARA_common.yaml) — shared schemas, error responses, headers, and parameters + * [CAMARA_event_common.yaml](artifacts/common/CAMARA_event_common.yaml) — CloudEvents envelope, subscription management, protocol settings, credentials, and subscription-specific error responses +* API templates demonstrating `$ref` consumption of common schemas in [artifacts/api-templates](artifacts/api-templates): + * [sample-service.yaml](artifacts/api-templates/sample-service.yaml) — request-response CRUD template + * [sample-service-subscriptions.yaml](artifacts/api-templates/sample-service-subscriptions.yaml) — explicit subscription management template +* notification callback template in [artifacts/notification-templates](artifacts/notification-templates): + * [sample-notification.yaml](artifacts/notification-templates/sample-notification.yaml) — receiver-side notification endpoint +* common test scenarios in [artifacts/testing](artifacts/testing) — error handling for device/phoneNumber APIs and subscription APIs ### Frequently-accessed output documents diff --git a/artifacts/api-templates/sample-service-subscriptions.yaml b/artifacts/api-templates/sample-service-subscriptions.yaml new file mode 100644 index 00000000..a6673216 --- /dev/null +++ b/artifacts/api-templates/sample-service-subscriptions.yaml @@ -0,0 +1,624 @@ +openapi: 3.0.3 +info: + title: Sample Service Subscription Template + description: | + This file is a template for CAMARA API explicit subscription endpoint and for Notification model. + Additional information are provided in [CAMARA API Event Subscription and Notification Guide](https://github.com/camaraproject/Commonalities/blob/main/documentation/CAMARA-API-Event-Subscription-and-Notification-Guide.md). + + Note on event name convention: the event type name MUST follow: ``org.camaraproject...`` + + Note on ``security`` - ``openId`` scope: The value in this yaml `api-name:event-type1:grant-level` must be replaced accordingly to the format defined in the guideline document. + + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + version: wip + x-camara-commonalities: 0.8.0 + +externalDocs: + description: Product documentation at CAMARA + url: https://github.com/camaraproject/apiRepository + # {apiRepository} MUST be replaced by the CAMARA Subproject Repository name where the API design based on this template is hosted. +servers: + - url: "{apiRoot}/api-name/vwip" + variables: + apiRoot: + default: http://localhost:9091 + description: API root, defined by the service provider, e.g. `api.example.com` or `api.example.com/somepath` +tags: + - name: Subscription + description: Operations to manage event subscriptions on event-type event + +paths: + /subscriptions: + post: + tags: + - Subscription + summary: "Create a apiName event subscription" + description: Create a apiName event subscription + operationId: createApiNameSubscription + parameters: + - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" + security: + - openId: + - api-name:event-type1:grant-level + - api-name:event-type2:grant-level + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/SubscriptionRequest" + required: true + callbacks: + notifications: + "{$request.body#/sink}": + post: + summary: "notifications callback" + description: | + Important: this endpoint is to be implemented by the API consumer. + The apiName server will call this endpoint whenever a apiName event occurs. + `operationId` value will have to be replaced accordingly with WG API specific semantic + operationId: postNotification + parameters: + - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" + requestBody: + required: true + content: + application/cloudevents+json: + schema: + $ref: "#/components/schemas/NotificationEvent" + responses: + "204": + description: Successful notification + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + "400": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic400" + "401": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic401" + "403": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic403" + "410": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic410" + "429": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic429" + security: + - {} + - notificationsBearerAuth: [] + + responses: + "201": + description: Created + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + $ref: "#/components/schemas/Subscription" + "202": + description: Request accepted to be processed. It applies for async creation process. + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + $ref: "#/components/schemas/SubscriptionAsync" + "400": + $ref: "../common/CAMARA_event_common.yaml#/components/responses/CreateSubscriptionBadRequest400" + "401": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic401" + "403": + $ref: "../common/CAMARA_event_common.yaml#/components/responses/SubscriptionPermissionDenied403" + "409": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic409" + "422": + $ref: "../common/CAMARA_event_common.yaml#/components/responses/CreateSubscriptionUnprocessableEntity422" + "429": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic429" + get: + tags: + - Subscription + summary: "Retrieve a list of apiName event subscription" + description: Retrieve a list of apiName event subscription(s) + operationId: retrieveApiNameSubscriptionList + parameters: + - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" + security: + - openId: + - api-name:read + responses: + "200": + description: List of event subscription details + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + type: array + minItems: 0 + maxItems: 1000 + items: + $ref: "#/components/schemas/Subscription" + "400": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic400" + "401": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic401" + "403": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic403" + /subscriptions/{subscriptionId}: + get: + tags: + - Subscription + summary: "Retrieve a apiName event subscription" + description: retrieve apiName subscription information for a given subscription. + operationId: retrieveApiNameSubscription + security: + - openId: + - api-name:read + parameters: + - $ref: "#/components/parameters/SubscriptionId" + - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" + responses: + "200": + description: OK + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + $ref: "#/components/schemas/Subscription" + "400": + $ref: "../common/CAMARA_event_common.yaml#/components/responses/SubscriptionIdRequired400" + "401": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic401" + "403": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic403" + "404": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic404" + delete: + tags: + - Subscription + summary: "Delete a apiName event subscription" + operationId: deleteApiNameSubscription + description: delete a given apiName subscription. + security: + - openId: + - api-name:delete + parameters: + - $ref: "#/components/parameters/SubscriptionId" + - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" + responses: + "204": + description: apiName subscription deleted + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + "202": + description: Request accepted to be processed. It applies for async deletion process. + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + $ref: "#/components/schemas/SubscriptionAsync" + "400": + $ref: "../common/CAMARA_event_common.yaml#/components/responses/SubscriptionIdRequired400" + "401": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic401" + "403": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic403" + "404": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic404" + +components: + securitySchemes: + openId: + type: openIdConnect + openIdConnectUrl: https://example.com/.well-known/openid-configuration + description: OpenID Connect authentication via discovery metadata. + notificationsBearerAuth: + type: http + scheme: bearer + bearerFormat: "{$request.body#/sinkCredential.credentialType}" + description: | + Bearer token for notification delivery. Token format is determined + by `sinkCredential.credentialType` in the subscription request. + + parameters: + SubscriptionId: + name: subscriptionId + in: path + description: Subscription identifier that was obtained from the create event subscription operation + required: true + schema: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/SubscriptionId" + + schemas: + + # ───────────────────────────────────────────────────────────────────────── + # Subscription management (API-specific due to ApiEventType reference) + # + # SubscriptionRequest and Subscription reference ApiEventType in their + # `types` field, which contains api-name placeholders. Protocol-specific + # request/response schemas extend these via allOf. + # ───────────────────────────────────────────────────────────────────────── + + SubscriptionRequest: + description: The request for creating a event-type event subscription + type: object + required: + - sink + - protocol + - config + - types + properties: + protocol: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/Protocol" + sink: + type: string + format: uri + maxLength: 2048 + pattern: ^https:\/\/.+$ + description: The address to which events shall be delivered using the selected protocol. + example: "https://endpoint.example.com/sink" + sinkCredential: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/SinkCredential" + types: + description: | + Camara Event types eligible to be delivered by this subscription. + References ApiEventType (not the full NotificationEvent union) — + subscription requests target API-specific events only; lifecycle + events are server-initiated and cannot be subscribed to directly. + Note: the maximum number of event types per subscription will be decided at API project level. + type: array + minItems: 1 + maxItems: 1 + items: + $ref: "#/components/schemas/ApiEventType" + config: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/Config" + discriminator: + propertyName: protocol + mapping: + HTTP: "#/components/schemas/HTTPSubscriptionRequest" + MQTT3: "#/components/schemas/MQTTSubscriptionRequest" + MQTT5: "#/components/schemas/MQTTSubscriptionRequest" + AMQP: "#/components/schemas/AMQPSubscriptionRequest" + NATS: "#/components/schemas/NATSSubscriptionRequest" + KAFKA: "#/components/schemas/ApacheKafkaSubscriptionRequest" + + Subscription: + description: Represents a event-type subscription. + type: object + required: + - sink + - protocol + - config + - types + - id + properties: + protocol: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/Protocol" + sink: + type: string + format: uri + maxLength: 2048 + pattern: ^https:\/\/.+$ + description: The address to which events shall be delivered using the selected protocol. + example: "https://endpoint.example.com/sink" + sinkCredential: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/SinkCredential" + types: + description: | + Camara Event types eligible to be delivered by this subscription. + Note: the maximum number of event types per subscription will be decided at API project level + type: array + minItems: 1 + maxItems: 1 + items: + $ref: "#/components/schemas/ApiEventType" + config: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/Config" + id: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/SubscriptionId" + startsAt: + $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" + expiresAt: + $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" + status: + type: string + description: |- + Current status of the subscription - Management of Subscription State engine is not mandatory for now. Note not all statuses may be considered to be implemented. Details: + - `ACTIVATION_REQUESTED`: Subscription creation (POST) is triggered but subscription creation process is not finished yet. + - `ACTIVE`: Subscription creation process is completed. Subscription is fully operative. + - `INACTIVE`: Subscription is temporarily inactive, but its workflow logic is not deleted. + - `EXPIRED`: Subscription is ended (no longer active). This status applies when subscription is ended due to `SUBSCRIPTION_EXPIRED` or `ACCESS_TOKEN_EXPIRED` event. + - `DELETED`: Subscription is ended as deleted (no longer active). This status applies when subscription information is kept (i.e. subscription workflow is no longer active but its meta-information is kept). + enum: + - ACTIVATION_REQUESTED + - ACTIVE + - EXPIRED + - INACTIVE + - DELETED + discriminator: + propertyName: protocol + mapping: + HTTP: "#/components/schemas/HTTPSubscriptionResponse" + MQTT3: "#/components/schemas/MQTTSubscriptionResponse" + MQTT5: "#/components/schemas/MQTTSubscriptionResponse" + AMQP: "#/components/schemas/AMQPSubscriptionResponse" + NATS: "#/components/schemas/NATSSubscriptionResponse" + KAFKA: "#/components/schemas/ApacheKafkaSubscriptionResponse" + + SubscriptionAsync: + description: Response for a event-type subscription request managed asynchronously (Creation or Deletion) + type: object + required: + - id + properties: + id: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/SubscriptionId" + + # ───────────────────────────────────────────────────────────────────────── + # API-specific event type enum (contains api-name placeholders) + # ───────────────────────────────────────────────────────────────────────── + + ApiEventType: + type: string + description: | + Enum of API-specific event type strings for this API project. + The reverse-DNS prefix `org.camaraproject.` makes each value + globally unique, so two different API groups can independently define + identically-named event types without any collision risk. + enum: + - org.camaraproject.api-name.v0.event-type1 + - org.camaraproject.api-name.v0.event-type2 + + # ───────────────────────────────────────────────────────────────────────── + # Subscription lifecycle event group (Commonalities-owned structure, + # but event type strings contain api-name placeholders) + # + # Common to every CAMARA API that supports subscriptions. + # Extends CloudEvent via allOf, constrains `type` to lifecycle values, + # and owns the lifecycle discriminator mapping. + # + # API projects reference this group via NotificationEvent but only update + # the api-name prefix in the event type strings. + # ───────────────────────────────────────────────────────────────────────── + + SubscriptionLifecycleEvent: + description: | + Subscription lifecycle event group, common to all CAMARA APIs that + support explicit subscriptions. + Extends the CloudEvent envelope and constrains `type` to the set of + lifecycle event types managed by Commonalities. + allOf: + - $ref: "../common/CAMARA_event_common.yaml#/components/schemas/CloudEvent" + - type: object + properties: + type: + $ref: "#/components/schemas/SubscriptionLifecycleEventType" + discriminator: + propertyName: type + mapping: + org.camaraproject.api-name.v0.subscription-started: "#/components/schemas/EventSubscriptionStarted" + org.camaraproject.api-name.v0.subscription-updated: "#/components/schemas/EventSubscriptionUpdated" + org.camaraproject.api-name.v0.subscription-ended: "#/components/schemas/EventSubscriptionEnded" + + SubscriptionLifecycleEventType: + type: string + description: | + Enum of subscription lifecycle event type strings. + These are managed by Commonalities and are identical across all CAMARA + APIs that support explicit subscriptions. + Kept as a separate named schema so the set of valid lifecycle type + strings can be referenced independently from the discriminated schema. + enum: + - org.camaraproject.api-name.v0.subscription-started + - org.camaraproject.api-name.v0.subscription-updated + - org.camaraproject.api-name.v0.subscription-ended + + # ───────────────────────────────────────────────────────────────────────── + # API-specific notification event group + # + # Extends CloudEvent via allOf and does exactly two things: + # 1. Constrains `type` to its own ApiEventType enum + # 2. Owns the discriminator mapping from each enum value to a concrete schema + # + # Adding a new event type requires only: adding a value to ApiEventType and + # adding a discriminator mapping entry here. CloudEvent is never touched. + + ApiNotificationEvent: + description: | + API-specific notification event group. + Extends the CloudEvent envelope and constrains `type` to the set of + event types defined by this API project. + Adding a new event type only requires updating ApiEventType and the + discriminator mapping below — the CloudEvent base never changes. + allOf: + - $ref: "../common/CAMARA_event_common.yaml#/components/schemas/CloudEvent" + - type: object + properties: + type: + $ref: "#/components/schemas/ApiEventType" + discriminator: + propertyName: "type" + mapping: + org.camaraproject.api-name.v0.event-type1: "#/components/schemas/EventApiSpecific1" + org.camaraproject.api-name.v0.event-type2: "#/components/schemas/EventApiSpecific2" + + # ───────────────────────────────────────────────────────────────────────── + # Callback union (API project-owned) + # + # oneOf over all valid event groups at the callback endpoint. + # Owns no discriminator and applies no constraints of its own. + # Its only job is to enumerate which groups are valid for this API. + # + # To add a new event group: add it to the oneOf list. That is the only + # change required at this layer. + # ───────────────────────────────────────────────────────────────────────── + + NotificationEvent: + description: | + Union of all valid notification event groups at the callback endpoint. + This schema owns no discriminator — routing within each group is + handled by ApiNotificationEvent and SubscriptionLifecycleEvent + respectively. Its only responsibility is to enumerate which groups + are valid payloads for this API's notification callback. + oneOf: + - $ref: "#/components/schemas/ApiNotificationEvent" + - $ref: "#/components/schemas/SubscriptionLifecycleEvent" + + # ───────────────────────────────────────────────────────────────────────── + # Concrete event schemas — API-specific (API project-owned) + # ───────────────────────────────────────────────────────────────────────── + + EventApiSpecific1: + description: event structure for event-type event 1 + allOf: + - $ref: "#/components/schemas/ApiNotificationEvent" + - type: object + properties: + data: + type: object + description: | + Event-specific payload for event-type1. + Replace with the actual data schema for this event type. + + EventApiSpecific2: + description: event structure for event-type event 2 + allOf: + - $ref: "#/components/schemas/ApiNotificationEvent" + - type: object + properties: + data: + type: object + description: | + Event-specific payload for event-type2. + Replace with the actual data schema for this event type. + + # ───────────────────────────────────────────────────────────────────────── + # Concrete event schemas — Subscription lifecycle (Commonalities-owned) + # Data payloads are referenced from CAMARA_event_common.yaml. + # ───────────────────────────────────────────────────────────────────────── + + EventSubscriptionStarted: + description: event structure for event subscription started + allOf: + - $ref: "#/components/schemas/SubscriptionLifecycleEvent" + - type: object + properties: + data: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/SubscriptionStarted" + + EventSubscriptionUpdated: + description: event structure for event subscription updated + allOf: + - $ref: "#/components/schemas/SubscriptionLifecycleEvent" + - type: object + properties: + data: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/SubscriptionUpdated" + + EventSubscriptionEnded: + description: event structure for event subscription ended + allOf: + - $ref: "#/components/schemas/SubscriptionLifecycleEvent" + - type: object + properties: + data: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/SubscriptionEnded" + + # ───────────────────────────────────────────────────────────────────────── + # Protocol-specific subscription schemas + # Protocol settings are referenced from CAMARA_event_common.yaml. + # ───────────────────────────────────────────────────────────────────────── + + HTTPSubscriptionRequest: + description: Subscription request for HTTP-based event delivery. + allOf: + - $ref: "#/components/schemas/SubscriptionRequest" + - type: object + properties: + protocolSettings: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/HTTPSettings" + + HTTPSubscriptionResponse: + description: Subscription resource returned for HTTP-based event delivery. + allOf: + - $ref: "#/components/schemas/Subscription" + - type: object + properties: + protocolSettings: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/HTTPSettings" + + MQTTSubscriptionRequest: + allOf: + - $ref: "#/components/schemas/SubscriptionRequest" + - type: object + properties: + protocolSettings: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/MQTTSettings" + + MQTTSubscriptionResponse: + allOf: + - $ref: "#/components/schemas/Subscription" + - type: object + properties: + protocolSettings: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/MQTTSettings" + + AMQPSubscriptionRequest: + allOf: + - $ref: "#/components/schemas/SubscriptionRequest" + - type: object + properties: + protocolSettings: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/AMQPSettings" + + AMQPSubscriptionResponse: + allOf: + - $ref: "#/components/schemas/Subscription" + - type: object + properties: + protocolSettings: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/AMQPSettings" + + ApacheKafkaSubscriptionRequest: + allOf: + - $ref: "#/components/schemas/SubscriptionRequest" + - type: object + properties: + protocolSettings: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/ApacheKafkaSettings" + + ApacheKafkaSubscriptionResponse: + allOf: + - $ref: "#/components/schemas/Subscription" + - type: object + properties: + protocolSettings: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/ApacheKafkaSettings" + + NATSSubscriptionRequest: + allOf: + - $ref: "#/components/schemas/SubscriptionRequest" + - type: object + properties: + protocolSettings: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/NATSSettings" + + NATSSubscriptionResponse: + allOf: + - $ref: "#/components/schemas/Subscription" + - type: object + properties: + protocolSettings: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/NATSSettings" + diff --git a/artifacts/camara-cloudevents/event-subscription-template.yaml b/artifacts/camara-cloudevents/event-subscription-template.yaml deleted file mode 100644 index f1846bbf..00000000 --- a/artifacts/camara-cloudevents/event-subscription-template.yaml +++ /dev/null @@ -1,1397 +0,0 @@ -openapi: 3.0.3 -info: - title: Notification Subscription Template - description: | - This file is a template for CAMARA API explicit subscription endpoint and for Notification model. - Additional information are provided in [CAMARA API Event Subscription and Notification Guide](https://github.com/camaraproject/Commonalities/blob/main/documentation/CAMARA-API-Event-Subscription-and-Notification-Guide.md). - - Note on event name convention: the event type name MUST follow: ``org.camaraproject...`` - - Note on ``security`` - ``openId`` scope: The value in this yaml `api-name:event-type1:grant-level` must be replaced accordingly to the format defined in the guideline document. - - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html - version: wip - x-camara-commonalities: 0.7.0 - -externalDocs: - description: Product documentation at CAMARA - url: https://github.com/camaraproject/apiRepository - # {apiRepository} MUST be replaced by the CAMARA Subproject Repository name where the API design based on this template is hosted. -servers: - - url: "{apiRoot}/api-name/vx.y" -- url: "{apiRoot}/api-name/vwip" - variables: - apiRoot: - default: http://localhost:9091 - description: API root, defined by the service provider, e.g. `api.example.com` or `api.example.com/somepath` -tags: - - name: Subscription - description: Operations to manage event subscriptions on event-type event - -paths: - /subscriptions: - post: - tags: - - Subscription - summary: "Create a apiName event subscription" - description: Create a apiName event subscription - operationId: createApiNameSubscription - parameters: - - $ref: "#/components/parameters/x-correlator" - security: - - openId: - - api-name:event-type1:grant-level - - api-name:event-type2:grant-level - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/SubscriptionRequest" - required: true - callbacks: - notifications: - "{$request.body#/sink}": - post: - summary: "notifications callback" - description: | - Important: this endpoint is to be implemented by the API consumer. - The apiName server will call this endpoint whenever a apiName event occurs. - `operationId` value will have to be replaced accordingly with WG API specific semantic - operationId: postNotification - parameters: - - $ref: "#/components/parameters/x-correlator" - requestBody: - required: true - content: - application/cloudevents+json: - schema: - $ref: "#/components/schemas/NotificationEvent" - responses: - "204": - description: Successful notification - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - "400": - $ref: "#/components/responses/Generic400" - "401": - $ref: "#/components/responses/Generic401" - "403": - $ref: "#/components/responses/Generic403" - "410": - $ref: "#/components/responses/Generic410" - "429": - $ref: "#/components/responses/Generic429" - security: - - {} - - notificationsBearerAuth: [] - - responses: - "201": - description: Created - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - $ref: "#/components/schemas/Subscription" - "202": - description: Request accepted to be processed. It applies for async creation process. - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - $ref: "#/components/schemas/SubscriptionAsync" - "400": - $ref: "#/components/responses/CreateSubscriptionBadRequest400" - "401": - $ref: "#/components/responses/Generic401" - "403": - $ref: "#/components/responses/SubscriptionPermissionDenied403" - "409": - $ref: "#/components/responses/Generic409" - "422": - $ref: "#/components/responses/CreateSubscriptionUnprocessableEntity422" - "429": - $ref: "#/components/responses/Generic429" - get: - tags: - - Subscription - summary: "Retrieve a list of apiName event subscription" - description: Retrieve a list of apiName event subscription(s) - operationId: retrieveApiNameSubscriptionList - parameters: - - $ref: "#/components/parameters/x-correlator" - security: - - openId: - - api-name:read - responses: - "200": - description: List of event subscription details - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - type: array - minItems: 0 - maxItems: 1000 - items: - $ref: '#/components/schemas/Subscription' - "400": - $ref: "#/components/responses/Generic400" - "401": - $ref: "#/components/responses/Generic401" - "403": - $ref: "#/components/responses/Generic403" - /subscriptions/{subscriptionId}: - get: - tags: - - Subscription - summary: "Retrieve a apiName event subscription" - description: retrieve apiName subscription information for a given subscription. - operationId: retrieveApiNameSubscription - security: - - openId: - - api-name:read - parameters: - - $ref: "#/components/parameters/SubscriptionId" - - $ref: "#/components/parameters/x-correlator" - responses: - "200": - description: OK - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - $ref: "#/components/schemas/Subscription" - "400": - $ref: "#/components/responses/SubscriptionIdRequired400" - "401": - $ref: "#/components/responses/Generic401" - "403": - $ref: "#/components/responses/Generic403" - "404": - $ref: "#/components/responses/Generic404" - delete: - tags: - - Subscription - summary: "Delete a apiName event subscription" - operationId: deleteApiNameSubscription - description: delete a given apiName subscription. - security: - - openId: - - api-name:delete - parameters: - - $ref: "#/components/parameters/SubscriptionId" - - $ref: "#/components/parameters/x-correlator" - responses: - "204": - description: apiName subscription deleted - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - "202": - description: Request accepted to be processed. It applies for async deletion process. - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - $ref: "#/components/schemas/SubscriptionAsync" - "400": - $ref: "#/components/responses/SubscriptionIdRequired400" - "401": - $ref: "#/components/responses/Generic401" - "403": - $ref: "#/components/responses/Generic403" - "404": - $ref: "#/components/responses/Generic404" -components: - securitySchemes: - openId: - type: openIdConnect - openIdConnectUrl: https://example.com/.well-known/openid-configuration - description: OpenID Connect authentication via discovery metadata. - notificationsBearerAuth: - type: http - scheme: bearer - bearerFormat: "{$request.body#/sinkCredential.credentialType}" - description: | - Bearer token for notification delivery. Token format is determined - by `sinkCredential.credentialType` in the subscription request. - parameters: - SubscriptionId: - name: subscriptionId - in: path - description: Subscription identifier that was obtained from the create event subscription operation - required: true - schema: - $ref: "#/components/schemas/SubscriptionId" - x-correlator: - name: x-correlator - in: header - description: Correlation id for the different services - schema: - $ref: "#/components/schemas/XCorrelator" - headers: - x-correlator: - description: Correlation id for the different services - schema: - $ref: "#/components/schemas/XCorrelator" - schemas: - ErrorInfo: - type: object - description: A structured error response providing details about a failed request, including the HTTP status code, an error code, and a human-readable message - required: - - status - - code - - message - properties: - status: - type: integer - format: int32 - minimum: 100 - maximum: 599 - description: HTTP response status code - code: - type: string - maxLength: 96 - description: A human-readable code to describe the error - message: - type: string - maxLength: 512 - description: A human-readable description of what the event represents - - XCorrelator: - type: string - description: Correlator string, UUID format recommended but any string matching the pattern can be used - pattern: ^[a-zA-Z0-9-_:;.\/<>{}]{0,256}$ - maxLength: 256 - example: "b4333c46-49c0-4f62-80d7-f0ef930f1c46" - - SubscriptionRequest: - description: The request for creating a event-type event subscription - type: object - required: - - sink - - protocol - - config - - types - properties: - protocol: - $ref: "#/components/schemas/Protocol" - sink: - type: string - format: uri - maxLength: 2048 - pattern: ^https:\/\/.+$ - description: The address to which events shall be delivered using the selected protocol. - example: "https://endpoint.example.com/sink" - sinkCredential: - $ref: "#/components/schemas/SinkCredential" - types: - description: | - Camara Event types eligible to be delivered by this subscription. - References ApiEventType (not the full NotificationEvent union) — - subscription requests target API-specific events only; lifecycle - events are server-initiated and cannot be subscribed to directly. - Note: the maximum number of event types per subscription will be decided at API project level. - type: array - minItems: 1 - maxItems: 1 - items: - $ref: "#/components/schemas/ApiEventType" - config: - $ref: "#/components/schemas/Config" - discriminator: - propertyName: protocol - mapping: - HTTP: "#/components/schemas/HTTPSubscriptionRequest" - MQTT3: "#/components/schemas/MQTTSubscriptionRequest" - MQTT5: "#/components/schemas/MQTTSubscriptionRequest" - AMQP: "#/components/schemas/AMQPSubscriptionRequest" - NATS: "#/components/schemas/NATSSubscriptionRequest" - KAFKA: "#/components/schemas/ApacheKafkaSubscriptionRequest" - - Protocol: - type: string - enum: ["HTTP", "MQTT3", "MQTT5", "AMQP", "NATS", "KAFKA"] - description: Identifier of a delivery protocol. Only HTTP is allowed for now - example: "HTTP" - - Config: - description: | - Implementation-specific configuration parameters needed by the subscription manager for acquiring events. - In CAMARA we have predefined attributes like `subscriptionExpireTime`, `subscriptionMaxEvents`, `initialEvent` - Specific event type attributes must be defined in `subscriptionDetail`. - Note: if a request is performed for several event types, all subscribed events will use same `config` parameters. - type: object - required: - - subscriptionDetail - properties: - subscriptionDetail: - $ref: "#/components/schemas/CreateSubscriptionDetail" - subscriptionExpireTime: - type: string - format: date-time - maxLength: 64 - example: 2023-01-17T13:18:23.682Z - description: The subscription expiration time (in date-time format) requested by the API consumer. It must follow [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) and must have time zone. Up to API project decision to keep it. - subscriptionMaxEvents: - type: integer - format: int32 - description: Identifies the maximum number of event reports to be generated (>=1) requested by the API consumer - Once this number is reached, the subscription ends. Up to API project decision to keep it. - minimum: 1 - maximum: 1000000 - example: 5 - initialEvent: - type: boolean - description: | - Set to `true` by API consumer if consumer wants to get an event as soon as the subscription is created and current situation reflects event request. - Example: Consumer request Roaming event. If consumer sets initialEvent to true and device is in roaming situation, an event is triggered - Up to API project decision to keep it. - - SinkCredential: - description: A sink credential provides authentication or authorization information necessary to enable delivery of events to a target. - type: object - properties: - credentialType: - type: string - enum: - - PLAIN - - ACCESSTOKEN - - PRIVATE_KEY_JWT - description: | - The type of the credential - MUST be set to ACCESSTOKEN or PRIVATE_KEY_JWT for now - discriminator: - propertyName: credentialType - mapping: - PLAIN: "#/components/schemas/PlainCredential" - ACCESSTOKEN: "#/components/schemas/AccessTokenCredential" - PRIVATE_KEY_JWT: "#/components/schemas/PrivateKeyJWTCredential" - required: - - credentialType - PlainCredential: - type: object - description: A plain credential as a combination of an identifier and a secret. - allOf: - - $ref: "#/components/schemas/SinkCredential" - - type: object - required: - - identifier - - secret - properties: - identifier: - description: The identifier might be an account or username. - type: string - maxLength: 256 - secret: - description: The secret might be a password or passphrase. - type: string - maxLength: 512 - AccessTokenCredential: - type: object - description: An access token credential. This type of credential is meant to be used by API Consumers that have limited capabilities to handle authorization requests. - allOf: - - $ref: "#/components/schemas/SinkCredential" - - type: object - properties: - accessToken: - description: REQUIRED. An access token is a token granting access to the target resource. - type: string - maxLength: 4096 - accessTokenExpiresUtc: - type: string - format: date-time - maxLength: 64 - description: | - REQUIRED. An absolute (UTC) timestamp at which the token shall be considered expired. - In the case of an ACCESS_TOKEN_EXPIRED termination reason, implementation should notify the client before the expiration date. - If the access token is a JWT and registered "exp" (Expiration Time) claim is present, the two expiry times should match. - It must follow [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) and must have time zone. - example: "2023-07-03T12:27:08.312Z" - accessTokenType: - description: REQUIRED. Type of the access token (See [OAuth 2.0](https://tools.ietf.org/html/rfc6749#section-7.1)). - type: string - enum: - - bearer - required: - - accessToken - - accessTokenExpiresUtc - - accessTokenType - PrivateKeyJWTCredential: - type: object - description: Use PRIVATE_KEY_JWT to get an access token. The authorization server information needed for this type of sink credential (token endpoint, client ID, JWKS URL) is shared upfront between the client and the CAMARA entity. This type of credential is to be used by clients that have an authorization server. - allOf: - - $ref: "#/components/schemas/SinkCredential" - CreateSubscriptionDetail: - description: The detail of the requested event subscription. - type: object - - ApiEventType: - type: string - description: | - Enum of API-specific event type strings for this API project. - The reverse-DNS prefix `org.camaraproject.` makes each value - globally unique, so two different API groups can independently define - identically-named event types without any collision risk. - enum: - - org.camaraproject.api-name.v0.event-type1 - - org.camaraproject.api-name.v0.event-type2 - - # ───────────────────────────────────────────────────────────────────────── - # Subscription lifecycle event group (Commonalities-owned) - # - # Common to every CAMARA API that supports subscriptions. - # Extends CloudEvent via allOf, constrains `type` to lifecycle values, - # and owns the lifecycle discriminator mapping. - # - # API projects reference this group via NotificationEvent but never modify it. - # ───────────────────────────────────────────────────────────────────────── - - SubscriptionLifecycleEvent: - description: | - Subscription lifecycle event group, common to all CAMARA APIs that - support explicit subscriptions. - Extends the CloudEvent envelope and constrains `type` to the set of - lifecycle event types managed by Commonalities. - allOf: - - $ref: "#/components/schemas/CloudEvent" - - type: object - properties: - type: - $ref: "#/components/schemas/SubscriptionLifecycleEventType" - discriminator: - propertyName: type - mapping: - org.camaraproject.api-name.v0.subscription-started: "#/components/schemas/EventSubscriptionStarted" - org.camaraproject.api-name.v0.subscription-updated: "#/components/schemas/EventSubscriptionUpdated" - org.camaraproject.api-name.v0.subscription-ended: "#/components/schemas/EventSubscriptionEnded" - - SubscriptionLifecycleEventType: - type: string - description: | - Enum of subscription lifecycle event type strings. - These are managed by Commonalities and are identical across all CAMARA - APIs that support explicit subscriptions. - Kept as a separate named schema so the set of valid lifecycle type - strings can be referenced independently from the discriminated schema. - enum: - - org.camaraproject.api-name.v0.subscription-started - - org.camaraproject.api-name.v0.subscription-updated - - org.camaraproject.api-name.v0.subscription-ended - - Subscription: - description: Represents a event-type subscription. - type: object - required: - - sink - - protocol - - config - - types - - id - properties: - protocol: - $ref: "#/components/schemas/Protocol" - sink: - type: string - format: uri - maxLength: 2048 - pattern: ^https:\/\/.+$ - description: The address to which events shall be delivered using the selected protocol. - example: "https://endpoint.example.com/sink" - types: - description: | - Camara Event types eligible to be delivered by this subscription. - Note: the maximum number of event types per subscription will be decided at API project level - type: array - minItems: 1 - maxItems: 1 - items: - $ref: "#/components/schemas/ApiEventType" - config: - $ref: '#/components/schemas/Config' - id: - $ref: '#/components/schemas/SubscriptionId' - startsAt: - type: string - format: date-time - maxLength: 64 - description: | - Date when the event subscription will begin/began - It must follow [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) and must have time zone. - example: "2023-07-03T12:27:08.312Z" - expiresAt: - type: string - format: date-time - maxLength: 64 - description: | - Date when the event subscription will expire. Only provided when `subscriptionExpireTime` is indicated by API client or Telco Operator has specific policy about that. - It must follow [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) and must have time zone. - example: "2023-07-03T12:27:08.312Z" - status: - type: string - description: |- - Current status of the subscription - Management of Subscription State engine is not mandatory for now. Note not all statuses may be considered to be implemented. Details: - - `ACTIVATION_REQUESTED`: Subscription creation (POST) is triggered but subscription creation process is not finished yet. - - `ACTIVE`: Subscription creation process is completed. Subscription is fully operative. - - `INACTIVE`: Subscription is temporarily inactive, but its workflow logic is not deleted. - - `EXPIRED`: Subscription is ended (no longer active). This status applies when subscription is ended due to `SUBSCRIPTION_EXPIRED` or `ACCESS_TOKEN_EXPIRED` event. - - `DELETED`: Subscription is ended as deleted (no longer active). This status applies when subscription information is kept (i.e. subscription workflow is no longer active but its meta-information is kept). - enum: - - ACTIVATION_REQUESTED - - ACTIVE - - EXPIRED - - INACTIVE - - DELETED - discriminator: - propertyName: protocol - mapping: - HTTP: '#/components/schemas/HTTPSubscriptionResponse' - MQTT3: '#/components/schemas/MQTTSubscriptionResponse' - MQTT5: '#/components/schemas/MQTTSubscriptionResponse' - AMQP: '#/components/schemas/AMQPSubscriptionResponse' - NATS: '#/components/schemas/NATSSubscriptionResponse' - KAFKA: '#/components/schemas/ApacheKafkaSubscriptionResponse' - - SubscriptionAsync: - description: Response for a event-type subscription request managed asynchronously (Creation or Deletion) - type: object - required: - - id - properties: - id: - $ref: "#/components/schemas/SubscriptionId" - - SubscriptionId: - type: string - maxLength: 256 - description: The unique identifier of the subscription in the scope of the subscription manager. When this information is contained within an event notification, it SHALL be referred to as `subscriptionId` as per the Commonalities Event Notification Model. - example: qs15-h556-rt89-1298 - - # ───────────────────────────────────────────────────────────────────────── - # CloudEvents 1.0 envelope (Commonalities-owned, never modified) - # - # Knows nothing about CAMARA event types, data payloads, or discriminator - # mappings. Any CAMARA API that needs to send a notification starts here. - # ───────────────────────────────────────────────────────────────────────── - CloudEvent: - type: object - description: | - CloudEvents 1.0 specification envelope. - This schema is the stable base for all CAMARA event notifications. - It imposes no constraints on `type` values or `data` structure — - those concerns belong to the API-specific and lifecycle group schemas. - required: - - id - - source - - specversion - - type - - time - properties: - id: - type: string - maxLength: 256 - description: Identifier of this event, unique within the source context. - source: - $ref: "#/components/schemas/Source" - type: - type: string - maxLength: 512 - description: | - Identifies the event type. CAMARA APIs use reverse-DNS notation: - `org.camaraproject...` - The api-name segment makes each type globally unique across API groups. - specversion: - type: string - description: Version of the specification to which this event conforms (must be 1.0 if it conforms to cloudevents 1.0.2 version) - enum: - - "1.0" - datacontenttype: - type: string - description: 'media-type that describes the event payload encoding, must be "application/json" for CAMARA APIs' - enum: - - application/json - data: - type: object - description: Event details payload. Structure is defined by each concrete event schema. - time: - $ref: "#/components/schemas/DateTime" - - # ───────────────────────────────────────────────────────────────────────── - # API-specific notification event group - # - # Extends CloudEvent via allOf and does exactly two things: - # 1. Constrains `type` to its own ApiEventType enum - # 2. Owns the discriminator mapping from each enum value to a concrete schema - # - # Adding a new event type requires only: adding a value to ApiEventType and - # adding a discriminator mapping entry here. CloudEvent is never touched. - # ───────────────────────────────────────────────────────────────────────── - - ApiNotificationEvent: - description: | - API-specific notification event group. - Extends the CloudEvent envelope and constrains `type` to the set of - event types defined by this API project. - Adding a new event type only requires updating ApiEventType and the - discriminator mapping below — the CloudEvent base never changes. - allOf: - - $ref: "#/components/schemas/CloudEvent" - - type: object - properties: - type: - $ref: "#/components/schemas/ApiEventType" - discriminator: - propertyName: "type" - mapping: - org.camaraproject.api-name.v0.event-type1: "#/components/schemas/EventApiSpecific1" - org.camaraproject.api-name.v0.event-type2: "#/components/schemas/EventApiSpecific2" - - Source: - type: string - format: uri-reference - minLength: 1 - maxLength: 2048 - description: | - Identifies the context in which an event happened - be a non-empty `URI-reference` like: - - URI with a DNS authority: - * https://github.com/cloudevents - * mailto:cncf-wg-serverless@lists.cncf.io - - Universally-unique URN with a UUID: - * urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66 - - Application-specific identifier: - * /cloudevents/spec/pull/123 - * 1-555-123-4567 - example: "https://notificationSendServer12.example.com" - - DateTime: - type: string - format: date-time - maxLength: 64 - description: Timestamp of when the occurrence happened. It must follow [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) and must have time zone. - example: "2018-04-05T17:31:00Z" - - # ───────────────────────────────────────────────────────────────────────── - # Callback union (API project-owned) - # - # oneOf over all valid event groups at the callback endpoint. - # Owns no discriminator and applies no constraints of its own. - # Its only job is to enumerate which groups are valid for this API. - # - # To add a new event group: add it to the oneOf list. That is the only - # change required at this layer. - # ───────────────────────────────────────────────────────────────────────── - - NotificationEvent: - description: | - Union of all valid notification event groups at the callback endpoint. - This schema owns no discriminator — routing within each group is - handled by ApiNotificationEvent and SubscriptionLifecycleEvent - respectively. Its only responsibility is to enumerate which groups - are valid payloads for this API's notification callback. - oneOf: - - $ref: "#/components/schemas/ApiNotificationEvent" - - $ref: "#/components/schemas/SubscriptionLifecycleEvent" - - # ───────────────────────────────────────────────────────────────────────── - # Concrete event schemas — API-specific (API project-owned) - # ───────────────────────────────────────────────────────────────────────── - - EventApiSpecific1: - description: event structure for event-type event 1 - allOf: - - $ref: "#/components/schemas/ApiNotificationEvent" - - type: object - properties: - data: - type: object - description: | - Event-specific payload for event-type1. - Replace with the actual data schema for this event type. - - EventApiSpecific2: - description: event structure for event-type event 2 - allOf: - - $ref: "#/components/schemas/ApiNotificationEvent" - - type: object - properties: - data: - type: object - description: | - Event-specific payload for event-type2. - Replace with the actual data schema for this event type. - - # ───────────────────────────────────────────────────────────────────────── - # Concrete event schemas — Subscription lifecycle (Commonalities-owned) - # ───────────────────────────────────────────────────────────────────────── - - EventSubscriptionStarted: - description: event structure for event subscription started - allOf: - - $ref: "#/components/schemas/SubscriptionLifecycleEvent" - - type: object - properties: - data: - $ref: "#/components/schemas/SubscriptionStarted" - - SubscriptionStarted: - description: Event detail structure for subscription started event - type: object - required: - - initiationReason - - subscriptionId - properties: - initiationReason: - $ref: "#/components/schemas/InitiationReason" - subscriptionId: - $ref: "#/components/schemas/SubscriptionId" - initiationDescription: - type: string - maxLength: 512 - description: Description of subscription initiation - - InitiationReason: - type: string - description: | - - SUBSCRIPTION_CREATED - Subscription created by API Server - enum: - - SUBSCRIPTION_CREATED - - EventSubscriptionUpdated: - description: event structure for event subscription updated - allOf: - - $ref: "#/components/schemas/SubscriptionLifecycleEvent" - - type: object - properties: - data: - $ref: "#/components/schemas/SubscriptionUpdated" - - SubscriptionUpdated: - description: Event detail structure for subscription updated event - type: object - required: - - updateReason - - subscriptionId - properties: - updateReason: - $ref: "#/components/schemas/UpdateReason" - subscriptionId: - $ref: "#/components/schemas/SubscriptionId" - updateDescription: - type: string - maxLength: 512 - description: Description of subscription update - - UpdateReason: - type: string - description: | - - SUBSCRIPTION_ACTIVE - API server transitioned subscription status to `ACTIVE` - - SUBSCRIPTION_INACTIVE - API server transitioned subscription status to `INACTIVE` - enum: - - SUBSCRIPTION_ACTIVE - - SUBSCRIPTION_INACTIVE - - EventSubscriptionEnded: - description: event structure for event subscription ended - allOf: - - $ref: "#/components/schemas/SubscriptionLifecycleEvent" - - type: object - properties: - data: - $ref: "#/components/schemas/SubscriptionEnded" - - SubscriptionEnded: - description: Event detail structure for subscription ended event - type: object - required: - - terminationReason - - subscriptionId - properties: - terminationReason: - $ref: "#/components/schemas/TerminationReason" - subscriptionId: - $ref: "#/components/schemas/SubscriptionId" - terminationDescription: - type: string - maxLength: 512 - description: Description of subscription termination - - TerminationReason: - type: string - description: | - - NETWORK_TERMINATED - API server stopped sending notification - - SUBSCRIPTION_EXPIRED - Subscription expire time (optionally set by the requester) has been reached - - MAX_EVENTS_REACHED - Maximum number of events (optionally set by the requester) has been reached - - ACCESS_TOKEN_EXPIRED - Access Token sinkCredential (optionally set by the requester with credential type `ACCESSTOKEN`) expiration time has been reached - - SUBSCRIPTION_DELETED - Subscription was deleted by the requester - enum: - - MAX_EVENTS_REACHED - - NETWORK_TERMINATED - - SUBSCRIPTION_EXPIRED - - ACCESS_TOKEN_EXPIRED - - SUBSCRIPTION_DELETED - # ───────────────────────────────────────────────────────────────────────── - # Protocol-specific subscription schemas - # ───────────────────────────────────────────────────────────────────────── - - HTTPSubscriptionRequest: - description: Subscription request for HTTP-based event delivery. - allOf: - - $ref: "#/components/schemas/SubscriptionRequest" - - type: object - properties: - protocolSettings: - $ref: "#/components/schemas/HTTPSettings" - - HTTPSubscriptionResponse: - description: Subscription resource returned for HTTP-based event delivery. - allOf: - - $ref: "#/components/schemas/Subscription" - - type: object - properties: - protocolSettings: - $ref: "#/components/schemas/HTTPSettings" - - HTTPSettings: - type: object - description: HTTP protocol settings for event delivery. - properties: - headers: - type: object - description: |- - A set of key/value pairs that is copied into the HTTP request as custom headers. - - NOTE: Use/Applicability of this concept has not been discussed in Commonalities. When required by an API project as an option to meet a UC/Requirement, please generate an issue for Commonalities discussion about it. - additionalProperties: - type: string - maxLength: 512 - method: - type: string - description: The HTTP method to use for sending the message. - enum: - - POST - - MQTTSubscriptionRequest: - allOf: - - $ref: "#/components/schemas/SubscriptionRequest" - - type: object - properties: - protocolSettings: - $ref: "#/components/schemas/MQTTSettings" - - MQTTSubscriptionResponse: - allOf: - - $ref: "#/components/schemas/Subscription" - - type: object - properties: - protocolSettings: - $ref: "#/components/schemas/MQTTSettings" - - MQTTSettings: - type: object - properties: - topicName: - type: string - maxLength: 256 - description: MQTT topic name - qos: - type: integer - format: int32 - minimum: 0 - maximum: 2 - description: Quality of Service level (0, 1, or 2) - retain: - type: boolean - expiry: - type: integer - format: int32 - minimum: 0 - maximum: 2147483647 - description: Message expiry interval in seconds - userProperties: - type: object - required: - - topicName - - AMQPSubscriptionRequest: - allOf: - - $ref: "#/components/schemas/SubscriptionRequest" - - type: object - properties: - protocolSettings: - $ref: "#/components/schemas/AMQPSettings" - - AMQPSubscriptionResponse: - allOf: - - $ref: "#/components/schemas/Subscription" - - type: object - properties: - protocolSettings: - $ref: "#/components/schemas/AMQPSettings" - - AMQPSettings: - type: object - properties: - address: - type: string - maxLength: 512 - linkName: - type: string - maxLength: 256 - senderSettlementMode: - type: string - enum: ["settled", "unsettled"] - linkProperties: - type: object - additionalProperties: - type: string - maxLength: 1024 - - ApacheKafkaSubscriptionRequest: - allOf: - - $ref: "#/components/schemas/SubscriptionRequest" - - type: object - properties: - protocolSettings: - $ref: "#/components/schemas/ApacheKafkaSettings" - - ApacheKafkaSubscriptionResponse: - allOf: - - $ref: "#/components/schemas/Subscription" - - type: object - properties: - protocolSettings: - $ref: "#/components/schemas/ApacheKafkaSettings" - - ApacheKafkaSettings: - type: object - properties: - topicName: - type: string - maxLength: 249 - partitionKeyExtractor: - type: string - maxLength: 512 - clientId: - type: string - maxLength: 256 - ackMode: - type: integer - format: int32 - minimum: 0 - maximum: 2 - description: Acknowledgment mode (0=no ack, 1=leader ack, 2=all replicas ack) - required: - - topicName - - NATSSubscriptionRequest: - allOf: - - $ref: "#/components/schemas/SubscriptionRequest" - - type: object - properties: - protocolSettings: - $ref: "#/components/schemas/NATSSettings" - - NATSSubscriptionResponse: - allOf: - - $ref: "#/components/schemas/Subscription" - - type: object - properties: - protocolSettings: - $ref: "#/components/schemas/NATSSettings" - - NATSSettings: - type: object - properties: - subject: - type: string - maxLength: 256 - description: NATS subject - required: - - subject - - responses: - CreateSubscriptionBadRequest400: - description: Problem with the client request - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 400 - code: - enum: - - INVALID_ARGUMENT - - OUT_OF_RANGE - - INVALID_PROTOCOL - - INVALID_CREDENTIAL - - INVALID_TOKEN - - INVALID_SINK - examples: - GENERIC_400_INVALID_ARGUMENT: - description: Invalid Argument. Generic Syntax Exception - value: - status: 400 - code: INVALID_ARGUMENT - message: Client specified an invalid argument, request body or query param. - GENERIC_400_OUT_OF_RANGE: - description: Out of Range. Specific Syntax Exception used when a given field has a pre-defined range or a invalid filter criteria combination is requested - value: - status: 400 - code: OUT_OF_RANGE - message: Client specified an invalid range. - GENERIC_400_INVALID_PROTOCOL: - description: Invalid protocol for events subscription management - value: - status: 400 - code: INVALID_PROTOCOL - message: Only HTTP is supported - GENERIC_400_INVALID_CREDENTIAL: - description: Invalid sink credential type - value: - status: 400 - code: INVALID_CREDENTIAL - message: Only Access token or Private key JWT are supported - GENERIC_400_INVALID_SINK: - description: Invalid sink value - value: - status: 400 - code: INVALID_SINK - message: sink not valid for the specified protocol - Generic400: - description: Problem with the client request - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 400 - code: - enum: - - INVALID_ARGUMENT - examples: - GENERIC_400_INVALID_ARGUMENT: - description: Invalid Argument. Generic Syntax Exception - value: - status: 400 - code: INVALID_ARGUMENT - message: Client specified an invalid argument, request body or query param. - SubscriptionIdRequired400: - description: Problem with the client request - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 400 - code: - enum: - - INVALID_ARGUMENT - examples: - GENERIC_400_INVALID_ARGUMENT: - description: Invalid Argument. Generic Syntax Exception - value: - status: 400 - code: INVALID_ARGUMENT - message: Client specified an invalid argument, request body or query param. - GENERIC_400_SUBSCRIPTION_ID_REQUIRED: - description: subscription id is required - value: - status: 400 - code: INVALID_ARGUMENT - message: "Expected property is missing: subscriptionId" - Generic401: - description: Authentication problem with the client request - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 401 - code: - enum: - - UNAUTHENTICATED - examples: - GENERIC_401_UNAUTHENTICATED: - description: Request cannot be authenticated and a new authentication is required - value: - status: 401 - code: UNAUTHENTICATED - message: Request not authenticated due to missing, invalid, or expired credentials. A new authentication is required. - Generic403: - description: Client does not have sufficient permission - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 403 - code: - enum: - - PERMISSION_DENIED - examples: - GENERIC_403_PERMISSION_DENIED: - description: Permission denied. OAuth2 token access does not have the required scope or when the user fails operational security - value: - status: 403 - code: PERMISSION_DENIED - message: Client does not have sufficient permissions to perform this action. - SubscriptionPermissionDenied403: - description: Client does not have sufficient permission - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 403 - code: - enum: - - PERMISSION_DENIED - - SUBSCRIPTION_MISMATCH - examples: - GENERIC_403_PERMISSION_DENIED: - description: Permission denied. OAuth2 token access does not have the required scope or when the user fails operational security - value: - status: 403 - code: PERMISSION_DENIED - message: Client does not have sufficient permissions to perform this action. - GENERIC_403_SUBSCRIPTION_MISMATCH: - description: Inconsistent access token for requested subscription - value: - status: 403 - code: "SUBSCRIPTION_MISMATCH" - message: "Inconsistent access token for requested events subscription" - Generic404: - description: Resource Not Found - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 404 - code: - enum: - - NOT_FOUND - examples: - GENERIC_404_NOT_FOUND: - description: Resource is not found - value: - status: 404 - code: NOT_FOUND - message: The specified resource is not found. - Generic409: - description: Conflict - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 409 - code: - enum: - - ABORTED - - ALREADY_EXISTS - examples: - GENERIC_409_ABORTED: - description: Concurrency of processes of the same nature/scope - value: - status: 409 - code: ABORTED - message: Concurrency conflict. - GENERIC_409_ALREADY_EXISTS: - description: Trying to create an existing resource - value: - status: 409 - code: ALREADY_EXISTS - message: The resource that a client tried to create already exists. - Generic410: - description: Gone - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 410 - code: - enum: - - GONE - examples: - GENERIC_410_GONE: - description: Use in notifications flow to allow API Consumer to indicate that its callback is no longer available - value: - status: 410 - code: GONE - message: Access to the target resource is no longer available. - CreateSubscriptionUnprocessableEntity422: - description: Unprocessable Entity - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 422 - code: - enum: - - SERVICE_NOT_APPLICABLE - - MISSING_IDENTIFIER - - UNSUPPORTED_IDENTIFIER - - UNNECESSARY_IDENTIFIER - - MULTIEVENT_SUBSCRIPTION_NOT_SUPPORTED - - MULTIEVENT_COMBINATION_TEMPORARILY_NOT_SUPPORTED - - PRIVATE_KEY_JWT_NOT_CONFIGURED - examples: - GENERIC_422_SERVICE_NOT_APPLICABLE: - description: Service not applicable for the provided identifier - value: - status: 422 - code: SERVICE_NOT_APPLICABLE - message: The service is not available for the provided identifier. - GENERIC_422_MISSING_IDENTIFIER: - description: An identifier is not included in the request and the device or phone number identification cannot be derived from the 3-legged access token - value: - status: 422 - code: MISSING_IDENTIFIER - message: The device cannot be identified. - GENERIC_422_UNSUPPORTED_IDENTIFIER: - description: None of the provided identifiers is supported by the implementation - value: - status: 422 - code: UNSUPPORTED_IDENTIFIER - message: The identifier provided is not supported. - GENERIC_422_UNNECESSARY_IDENTIFIER: - description: An explicit identifier is provided when a device or phone number has already been identified from the access token - value: - status: 422 - code: UNNECESSARY_IDENTIFIER - message: The device is already identified by the access token. - GENERIC_422_MULTIEVENT_SUBSCRIPTION_NOT_SUPPORTED: - description: Multi event types subscription is not supported - value: - status: 422 - code: MULTIEVENT_SUBSCRIPTION_NOT_SUPPORTED - message: Multi event types subscription not managed - GENERIC_422_MULTIEVENT_COMBINATION_TEMPORARILY_NOT_SUPPORTED: - description: Combination of multiple event types is temporarily not supported - value: - status: 422 - code: MULTIEVENT_COMBINATION_TEMPORARILY_NOT_SUPPORTED - message: The requested combination of event types is temporarily not supported. - GENERIC_422_PRIVATE_KEY_JWT_NOT_CONFIGURED: - description: Private key JWT sink credential type is used but no configuration was pre-shared - value: - status: 422 - code: PRIVATE_KEY_JWT_NOT_CONFIGURED - message: No JWK Set configured for PRIVATE_KEY_JWT authentication. - Generic429: - description: Too Many Requests - headers: - X-Correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 429 - code: - enum: - - QUOTA_EXCEEDED - - TOO_MANY_REQUESTS - examples: - GENERIC_429_QUOTA_EXCEEDED: - description: Request is rejected due to exceeding a business quota limit - value: - status: 429 - code: QUOTA_EXCEEDED - message: Out of resource quota. - GENERIC_429_TOO_MANY_REQUESTS: - description: Access to the API has been temporarily blocked due to rate or spike arrest limits being reached - value: - status: 429 - code: TOO_MANY_REQUESTS - message: Rate limit reached. diff --git a/artifacts/common/CAMARA_common.yaml b/artifacts/common/CAMARA_common.yaml index 2bf87fd1..e26e4f06 100644 --- a/artifacts/common/CAMARA_common.yaml +++ b/artifacts/common/CAMARA_common.yaml @@ -1,15 +1,19 @@ -openapi: 3.0.3 info: title: CAMARA common data types - description: Common data types for CAMARA APIs + description: | + Common data types for CAMARA APIs. + This file contains Commonalities-owned schemas that are identical across all + CAMARA APIs, including error responses, common parameters, headers, and + reusable data types. + + API repositories place this file in `code/common/` and reference schemas + via `$ref: "../common/CAMARA_common.yaml#/components/schemas/"`. license: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0.html - version: 0.8.0-rc.1 - + version: wip x-camara-commonalities: 0.7.0 -paths: {} components: securitySchemes: openId: @@ -34,6 +38,12 @@ components: pattern: ^[a-zA-Z0-9-_:;.\/<>{}]{0,256}$ maxLength: 256 example: "b4333c46-49c0-4f62-80d7-f0ef930f1c46" + DateTime: + type: string + format: date-time + maxLength: 64 + description: Timestamp. It must follow [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) and must have time zone. + example: "2018-04-05T17:31:00Z" TimePeriod: type: object description: A period of time defined by a start date and an optional end date diff --git a/artifacts/common/CAMARA_event_common.yaml b/artifacts/common/CAMARA_event_common.yaml new file mode 100644 index 00000000..2a8b47b3 --- /dev/null +++ b/artifacts/common/CAMARA_event_common.yaml @@ -0,0 +1,610 @@ +info: + title: CAMARA common event and subscription data types + description: | + Common data types for CAMARA event notification and subscription management. + This file contains Commonalities-owned schemas that are identical across all + CAMARA APIs supporting event notifications and/or explicit subscriptions. + + API repositories place this file in `code/common/` alongside `CAMARA_common.yaml` + and reference schemas via `$ref: "../common/CAMARA_event_common.yaml#/components/schemas/"`. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + version: wip + x-camara-commonalities: 0.7.0 + +components: + schemas: + + # ───────────────────────────────────────────────────────────────────────── + # Section 1: CloudEvents 1.0 envelope + # + # Pure CloudEvents 1.0 specification envelope. Knows nothing about CAMARA + # event types, data payloads, or discriminator mappings. Any CAMARA API + # that needs to send a notification starts here. + # ───────────────────────────────────────────────────────────────────────── + + CloudEvent: + type: object + description: | + CloudEvents 1.0 specification envelope. + This schema is the stable base for all CAMARA event notifications. + It imposes no constraints on `type` values or `data` structure — + those concerns belong to the API-specific and lifecycle group schemas. + required: + - id + - source + - specversion + - type + - time + properties: + id: + type: string + maxLength: 256 + description: Identifier of this event, unique within the source context. + source: + $ref: "#/components/schemas/Source" + type: + type: string + maxLength: 512 + description: | + Identifies the event type. CAMARA APIs use reverse-DNS notation: + `org.camaraproject...` + The api-name segment makes each type globally unique across API groups. + specversion: + type: string + description: Version of the specification to which this event conforms (must be 1.0 if it conforms to cloudevents 1.0.2 version) + enum: + - "1.0" + datacontenttype: + type: string + description: 'media-type that describes the event payload encoding, must be "application/json" for CAMARA APIs' + enum: + - application/json + data: + type: object + description: Event details payload. Structure is defined by each concrete event schema. + time: + $ref: "CAMARA_common.yaml#/components/schemas/DateTime" + + Source: + type: string + format: uri-reference + minLength: 1 + maxLength: 2048 + description: | + Identifies the context in which an event happened - be a non-empty `URI-reference` like: + - URI with a DNS authority: + * https://github.com/cloudevents + * mailto:cncf-wg-serverless@lists.cncf.io + - Universally-unique URN with a UUID: + * urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66 + - Application-specific identifier: + * /cloudevents/spec/pull/123 + * 1-555-123-4567 + example: "https://notificationSendServer12.example.com" + + # ───────────────────────────────────────────────────────────────────────── + # Section 2: Subscription management + # + # Configuration and identification schemas used by the subscription + # management endpoints. These are Commonalities-owned and identical + # across all CAMARA APIs that support explicit subscriptions. + # ───────────────────────────────────────────────────────────────────────── + + SubscriptionId: + type: string + maxLength: 256 + description: The unique identifier of the subscription in the scope of the subscription manager. When this information is contained within an event notification, it SHALL be referred to as `subscriptionId` as per the Commonalities Event Notification Model. + example: qs15-h556-rt89-1298 + + Config: + description: | + Implementation-specific configuration parameters needed by the subscription manager for acquiring events. + In CAMARA we have predefined attributes like `subscriptionExpireTime`, `subscriptionMaxEvents`, `initialEvent` + Specific event type attributes must be defined in `subscriptionDetail`. + Note: if a request is performed for several event types, all subscribed events will use same `config` parameters. + type: object + required: + - subscriptionDetail + properties: + subscriptionDetail: + $ref: "#/components/schemas/CreateSubscriptionDetail" + subscriptionExpireTime: + type: string + format: date-time + maxLength: 64 + example: 2023-01-17T13:18:23.682Z + description: The subscription expiration time (in date-time format) requested by the API consumer. It must follow [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) and must have time zone. Up to API project decision to keep it. + subscriptionMaxEvents: + type: integer + format: int32 + description: Identifies the maximum number of event reports to be generated (>=1) requested by the API consumer - Once this number is reached, the subscription ends. Up to API project decision to keep it. + minimum: 1 + maximum: 1000000 + example: 5 + initialEvent: + type: boolean + description: | + Set to `true` by API consumer if consumer wants to get an event as soon as the subscription is created and current situation reflects event request. + Example: Consumer request Roaming event. If consumer sets initialEvent to true and device is in roaming situation, an event is triggered + Up to API project decision to keep it. + + CreateSubscriptionDetail: + description: The detail of the requested event subscription. + type: object + + # ───────────────────────────────────────────────────────────────────────── + # Section 3: Protocol support + # + # Protocol selection and protocol-specific delivery settings. + # These are Commonalities-owned and identical across all CAMARA APIs. + # ───────────────────────────────────────────────────────────────────────── + + Protocol: + type: string + enum: ["HTTP", "MQTT3", "MQTT5", "AMQP", "NATS", "KAFKA"] + description: Identifier of a delivery protocol. Only HTTP is allowed for now + example: "HTTP" + + HTTPSettings: + type: object + description: HTTP protocol settings for event delivery. + properties: + headers: + type: object + description: |- + A set of key/value pairs that is copied into the HTTP request as custom headers. + + NOTE: Use/Applicability of this concept has not been discussed in Commonalities. When required by an API project as an option to meet a UC/Requirement, please generate an issue for Commonalities discussion about it. + additionalProperties: + type: string + maxLength: 512 + method: + type: string + description: The HTTP method to use for sending the message. + enum: + - POST + + MQTTSettings: + type: object + properties: + topicName: + type: string + maxLength: 256 + description: MQTT topic name + qos: + type: integer + format: int32 + minimum: 0 + maximum: 2 + description: Quality of Service level (0, 1, or 2) + retain: + type: boolean + expiry: + type: integer + format: int32 + minimum: 0 + maximum: 2147483647 + description: Message expiry interval in seconds + userProperties: + type: object + required: + - topicName + + AMQPSettings: + type: object + properties: + address: + type: string + maxLength: 512 + linkName: + type: string + maxLength: 256 + senderSettlementMode: + type: string + enum: ["settled", "unsettled"] + linkProperties: + type: object + additionalProperties: + type: string + maxLength: 1024 + + ApacheKafkaSettings: + type: object + properties: + topicName: + type: string + maxLength: 249 + partitionKeyExtractor: + type: string + maxLength: 512 + clientId: + type: string + maxLength: 256 + ackMode: + type: integer + format: int32 + minimum: 0 + maximum: 2 + description: Acknowledgment mode (0=no ack, 1=leader ack, 2=all replicas ack) + required: + - topicName + + NATSSettings: + type: object + properties: + subject: + type: string + maxLength: 256 + description: NATS subject + required: + - subject + + # ───────────────────────────────────────────────────────────────────────── + # Section 4: Sink credentials + # + # Authentication and authorization information for event delivery. + # These are Commonalities-owned and identical across all CAMARA APIs. + # ───────────────────────────────────────────────────────────────────────── + + SinkCredential: + description: A sink credential provides authentication or authorization information necessary to enable delivery of events to a target. + type: object + properties: + credentialType: + type: string + enum: + - PLAIN + - ACCESSTOKEN + - PRIVATE_KEY_JWT + description: | + The type of the credential - MUST be set to ACCESSTOKEN or PRIVATE_KEY_JWT for now + discriminator: + propertyName: credentialType + mapping: + PLAIN: "#/components/schemas/PlainCredential" + ACCESSTOKEN: "#/components/schemas/AccessTokenCredential" + PRIVATE_KEY_JWT: "#/components/schemas/PrivateKeyJWTCredential" + required: + - credentialType + + PlainCredential: + type: object + description: A plain credential as a combination of an identifier and a secret. + allOf: + - $ref: "#/components/schemas/SinkCredential" + - type: object + required: + - identifier + - secret + properties: + identifier: + description: The identifier might be an account or username. + type: string + maxLength: 256 + secret: + description: The secret might be a password or passphrase. + type: string + maxLength: 512 + + AccessTokenCredential: + type: object + description: An access token credential. This type of credential is meant to be used by API Consumers that have limited capabilities to handle authorization requests. + allOf: + - $ref: "#/components/schemas/SinkCredential" + - type: object + properties: + accessToken: + description: REQUIRED. An access token is a token granting access to the target resource. + type: string + maxLength: 4096 + accessTokenExpiresUtc: + type: string + format: date-time + maxLength: 64 + description: | + REQUIRED. An absolute (UTC) timestamp at which the token shall be considered expired. + In the case of an ACCESS_TOKEN_EXPIRED termination reason, implementation should notify the client before the expiration date. + If the access token is a JWT and registered "exp" (Expiration Time) claim is present, the two expiry times should match. + It must follow [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) and must have time zone. + example: "2023-07-03T12:27:08.312Z" + accessTokenType: + description: REQUIRED. Type of the access token (See [OAuth 2.0](https://tools.ietf.org/html/rfc6749#section-7.1)). + type: string + enum: + - bearer + required: + - accessToken + - accessTokenExpiresUtc + - accessTokenType + + PrivateKeyJWTCredential: + type: object + description: Use PRIVATE_KEY_JWT to get an access token. The authorization server information needed for this type of sink credential (token endpoint, client ID, JWKS URL) is shared upfront between the client and the CAMARA entity. This type of credential is to be used by clients that have an authorization server. + allOf: + - $ref: "#/components/schemas/SinkCredential" + + # ───────────────────────────────────────────────────────────────────────── + # Section 5: Subscription lifecycle data + # + # Data payload schemas for subscription lifecycle events. These define the + # `data` content of subscription-started, subscription-updated, and + # subscription-ended events. The lifecycle event wrappers (which contain + # api-name placeholders in their event type strings) stay in API templates. + # ───────────────────────────────────────────────────────────────────────── + + SubscriptionStarted: + description: Event detail structure for subscription started event + type: object + required: + - initiationReason + - subscriptionId + properties: + initiationReason: + $ref: "#/components/schemas/InitiationReason" + subscriptionId: + $ref: "#/components/schemas/SubscriptionId" + initiationDescription: + type: string + maxLength: 512 + description: Description of subscription initiation + + InitiationReason: + type: string + description: | + - SUBSCRIPTION_CREATED - Subscription created by API Server + enum: + - SUBSCRIPTION_CREATED + + SubscriptionUpdated: + description: Event detail structure for subscription updated event + type: object + required: + - updateReason + - subscriptionId + properties: + updateReason: + $ref: "#/components/schemas/UpdateReason" + subscriptionId: + $ref: "#/components/schemas/SubscriptionId" + updateDescription: + type: string + maxLength: 512 + description: Description of subscription update + + UpdateReason: + type: string + description: | + - SUBSCRIPTION_ACTIVE - API server transitioned subscription status to `ACTIVE` + - SUBSCRIPTION_INACTIVE - API server transitioned subscription status to `INACTIVE` + enum: + - SUBSCRIPTION_ACTIVE + - SUBSCRIPTION_INACTIVE + + SubscriptionEnded: + description: Event detail structure for subscription ended event + type: object + required: + - terminationReason + - subscriptionId + properties: + terminationReason: + $ref: "#/components/schemas/TerminationReason" + subscriptionId: + $ref: "#/components/schemas/SubscriptionId" + terminationDescription: + type: string + maxLength: 512 + description: Description of subscription termination + + TerminationReason: + type: string + description: | + - NETWORK_TERMINATED - API server stopped sending notification + - SUBSCRIPTION_EXPIRED - Subscription expire time (optionally set by the requester) has been reached + - MAX_EVENTS_REACHED - Maximum number of events (optionally set by the requester) has been reached + - ACCESS_TOKEN_EXPIRED - Access Token sinkCredential (optionally set by the requester with credential type `ACCESSTOKEN`) expiration time has been reached + - SUBSCRIPTION_DELETED - Subscription was deleted by the requester + enum: + - MAX_EVENTS_REACHED + - NETWORK_TERMINATED + - SUBSCRIPTION_EXPIRED + - ACCESS_TOKEN_EXPIRED + - SUBSCRIPTION_DELETED + + # ───────────────────────────────────────────────────────────────────────── + # Subscription-specific error responses + # + # These extend generic CAMARA error codes with subscription-specific codes. + # Commonalities-owned and identical across all APIs using explicit subscriptions. + # ───────────────────────────────────────────────────────────────────────── + + responses: + CreateSubscriptionBadRequest400: + description: Problem with the client request + headers: + x-correlator: + $ref: "CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + - OUT_OF_RANGE + - INVALID_PROTOCOL + - INVALID_CREDENTIAL + - INVALID_TOKEN + - INVALID_SINK + examples: + GENERIC_400_INVALID_ARGUMENT: + description: Invalid Argument. Generic Syntax Exception + value: + status: 400 + code: INVALID_ARGUMENT + message: Client specified an invalid argument, request body or query param. + GENERIC_400_OUT_OF_RANGE: + description: Out of Range. Specific Syntax Exception used when a given field has a pre-defined range or a invalid filter criteria combination is requested + value: + status: 400 + code: OUT_OF_RANGE + message: Client specified an invalid range. + GENERIC_400_INVALID_PROTOCOL: + description: Invalid protocol for events subscription management + value: + status: 400 + code: INVALID_PROTOCOL + message: Only HTTP is supported + GENERIC_400_INVALID_CREDENTIAL: + description: Invalid sink credential type + value: + status: 400 + code: INVALID_CREDENTIAL + message: Only Access token or Private key JWT are supported + GENERIC_400_INVALID_SINK: + description: Invalid sink value + value: + status: 400 + code: INVALID_SINK + message: sink not valid for the specified protocol + + SubscriptionIdRequired400: + description: Problem with the client request + headers: + x-correlator: + $ref: "CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + examples: + GENERIC_400_INVALID_ARGUMENT: + description: Invalid Argument. Generic Syntax Exception + value: + status: 400 + code: INVALID_ARGUMENT + message: Client specified an invalid argument, request body or query param. + GENERIC_400_SUBSCRIPTION_ID_REQUIRED: + description: subscription id is required + value: + status: 400 + code: INVALID_ARGUMENT + message: "Expected property is missing: subscriptionId" + + SubscriptionPermissionDenied403: + description: Client does not have sufficient permission + headers: + x-correlator: + $ref: "CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 403 + code: + enum: + - PERMISSION_DENIED + - SUBSCRIPTION_MISMATCH + examples: + GENERIC_403_PERMISSION_DENIED: + description: Permission denied. OAuth2 token access does not have the required scope or when the user fails operational security + value: + status: 403 + code: PERMISSION_DENIED + message: Client does not have sufficient permissions to perform this action. + GENERIC_403_SUBSCRIPTION_MISMATCH: + description: Inconsistent access token for requested subscription + value: + status: 403 + code: "SUBSCRIPTION_MISMATCH" + message: "Inconsistent access token for requested events subscription" + + CreateSubscriptionUnprocessableEntity422: + description: Unprocessable Entity + headers: + x-correlator: + $ref: "CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 422 + code: + enum: + - SERVICE_NOT_APPLICABLE + - MISSING_IDENTIFIER + - UNSUPPORTED_IDENTIFIER + - UNNECESSARY_IDENTIFIER + - MULTIEVENT_SUBSCRIPTION_NOT_SUPPORTED + - MULTIEVENT_COMBINATION_TEMPORARILY_NOT_SUPPORTED + - PRIVATE_KEY_JWT_NOT_CONFIGURED + examples: + GENERIC_422_SERVICE_NOT_APPLICABLE: + description: Service not applicable for the provided identifier + value: + status: 422 + code: SERVICE_NOT_APPLICABLE + message: The service is not available for the provided identifier. + GENERIC_422_MISSING_IDENTIFIER: + description: An identifier is not included in the request and the device or phone number identification cannot be derived from the 3-legged access token + value: + status: 422 + code: MISSING_IDENTIFIER + message: The device cannot be identified. + GENERIC_422_UNSUPPORTED_IDENTIFIER: + description: None of the provided identifiers is supported by the implementation + value: + status: 422 + code: UNSUPPORTED_IDENTIFIER + message: The identifier provided is not supported. + GENERIC_422_UNNECESSARY_IDENTIFIER: + description: An explicit identifier is provided when a device or phone number has already been identified from the access token + value: + status: 422 + code: UNNECESSARY_IDENTIFIER + message: The device is already identified by the access token. + GENERIC_422_MULTIEVENT_SUBSCRIPTION_NOT_SUPPORTED: + description: Multi event types subscription is not supported + value: + status: 422 + code: MULTIEVENT_SUBSCRIPTION_NOT_SUPPORTED + message: Multi event types subscription not managed + GENERIC_422_MULTIEVENT_COMBINATION_TEMPORARILY_NOT_SUPPORTED: + description: Combination of multiple event types is temporarily not supported + value: + status: 422 + code: MULTIEVENT_COMBINATION_TEMPORARILY_NOT_SUPPORTED + message: The requested combination of event types is temporarily not supported. + GENERIC_422_PRIVATE_KEY_JWT_NOT_CONFIGURED: + description: Private key JWT sink credential type is used but no configuration was pre-shared + value: + status: 422 + code: PRIVATE_KEY_JWT_NOT_CONFIGURED + message: No JWK Set configured for PRIVATE_KEY_JWT authentication. diff --git a/artifacts/notification-as-cloud-event.yaml b/artifacts/notification-as-cloud-event.yaml deleted file mode 100644 index d867e996..00000000 --- a/artifacts/notification-as-cloud-event.yaml +++ /dev/null @@ -1,344 +0,0 @@ -openapi: 3.0.3 -info: - title: Event Notification using CloudEvents specifications - description: | - The event notification endpoint is used by the API server to notify the API consumer that an event occurred. The notification is the message posted on listener side. - - # Introduction - - A lot of CAMARA APIs offer the capability to API consumer to receive events. - Event data are defined in each API definition but in order to provide consistency across CAMARA APIs and to increase - interoperability we will use [cloudevents](https://cloudevents.io/) specifications. In particular, every CAMARA Event will - be defined using [cloudevents-json-format](https://github.com/cloudevents/spec/blob/main/cloudevents/formats/json-format.md) - - # Relevant terms and definitions - - * **Occurrence** : An "occurrence" is the capture of a statement of fact during the operation of a software system. - - * **Event**: An "event" is a data record expressing an occurrence and its context. Events are routed from an - event producer (the source) to interested event consumers. - - * **Producer**: The "producer" is a specific instance, process or device that creates the data structure - describing the CloudEvent. - - * **Source**: The "source" is the context in which the occurrence happened. In a distributed system it might - consist of multiple producers. If a source is not aware of CloudEvents, an external producer creates - the CloudEvent on behalf of the source. - - * **Consumer**: A "consumer" receives the event and acts upon it. It uses the context and data to execute some - logic, which might lead to the occurrence of new events. - - * **Data**: Domain-specific information about the occurrence (i.e. the payload). This might - include information about the occurrence, details about the data that was changed, or more. - - # API Functionality - - Only one endpoint/operation is provided: `POST /your_webhook_notification_url` - This endpoint describes the event notification received on subscription listener side when the event occurred. - A detailed description of the event notification is provided in the [CAMARA API Event Subscription and Notification Guide](https://github.com/camaraproject/Commonalities/blob/main/documentation/CAMARA-API-Event-Subscription-and-Notification-Guide.md#3-event-notification) - - termsOfService: http://swagger.io/terms/ - contact: - email: project-email@sample.com - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html - version: 0.4.0-rc.1 -externalDocs: - description: Product documentation at CAMARA - url: https://github.com/camaraproject/Commonalities -security: - - notificationsBearerAuth: [] - - {} - -servers: - - url: '{apiRoot}' - variables: - apiRoot: - default: https://localhost:8080 - description: Can be any notification server address sent by the client application -tags: - - name: CAMARA Cloud Event - description: | - Events received on subscription listener side. -paths: - /your_webhook_notification_url: - post: - tags: - - CAMARA Cloud Event - summary: "Cloud Event notification endpoint to notify consumer that statement of fact had occurred" - description: | - INFORMATIVE ENDPOINT: The value of this endpoint is freely declared by each client app by means of resource-based - subscription or instance-based subscription. /your_webhook_notification_url is - just a convention naming referring to an absolute URL, indeed the one indicated by API client - in the triggering of the procedure (resource-based or instance-based). In this way, it represents an absolute - URL, i.e.: notifications won't be sent to /event-notification/vX/your_webhook_notification_url. - operationId: sendEvent - parameters: - - $ref: "#/components/parameters/x-correlator" - requestBody: - required: true - content: - application/cloudevents+json: - schema: - $ref: "#/components/schemas/CloudEvent" - examples: - QOS_STATUS_CHANGED_EXAMPLE: - $ref: '#/components/examples/QOS_STATUS_CHANGED_EXAMPLE' - - responses: - 204: - description: No Content - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - 400: - $ref: "#/components/responses/Generic400" - 401: - $ref: "#/components/responses/Generic401" - 403: - $ref: "#/components/responses/Generic403" - 410: - $ref: "#/components/responses/Generic410" - 429: - $ref: "#/components/responses/Generic429" -components: - securitySchemes: - notificationsBearerAuth: - type: http - scheme: bearer - bearerFormat: "{$request.body#/sinkCredential.credentialType}" - schemas: - ErrorInfo: - type: object - required: - - status - - code - - message - properties: - status: - type: integer - description: HTTP response status code - code: - type: string - description: A human-readable code to describe the error - message: - type: string - description: A human-readable description of what the event represents - - XCorrelator: - type: string - pattern: ^[a-zA-Z0-9-_:;.\/<>{}]{0,256}$ - example: "b4333c46-49c0-4f62-80d7-f0ef930f1c46" - - DateTime: - type: string - format: date-time - description: | - Timestamp of when the occurrence happened. It must follow [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) and must have time zone. - WARN: This optional field in CloudEvents specification is required in CAMARA APIs implementation. - example: '2018-04-05T17:31:00Z' - - Source: - type: string - format: uri-reference - minLength: 1 - description: | - Identifies the context in which an event happened - be a non-empty `URI-reference` like: - - URI with a DNS authority: - * https://github.com/cloudevents - * mailto:cncf-wg-serverless@lists.cncf.io - - Universally-unique URN with a UUID: - * urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66 - - Application-specific identifier: - * /cloudevents/spec/pull/123 - * 1-555-123-4567 - example: "https://notificationSendServer12.example.com" - - CloudEvent: - description: The notification callback - required: - - id - - source - - specversion - - type - - time - properties: - id: - type: string - description: identifier of this event, that must be unique in the source context. - minLength: 1 - source: - $ref: '#/components/schemas/Source' - type: - type: string - description: 'type of event as defined in each CAMARA API (e.g.: org.camaraproject.qod.qos-status-changed-event)' - example: 'org.camaraproject.qod.qos-status-changed-event' - minLength: 25 - specversion: - type: string - description: Version of the specification to which this event conforms (must be 1.0 if it conforms to cloudevents 1.0.2 version) - enum: - - "1.0" - datacontenttype: - type: string - description: 'media-type that describes the event payload encoding, must be "application/json" for CAMARA APIs' - enum: - - application/json - data: - type: object - description: Event details payload described in each CAMARA API and referenced by its type - time: - $ref: "#/components/schemas/DateTime" - headers: - x-correlator: - description: Correlation id for the different services - schema: - $ref: "#/components/schemas/XCorrelator" - parameters: - x-correlator: - name: x-correlator - in: header - description: Correlation id for the different services - schema: - $ref: "#/components/schemas/XCorrelator" - - responses: - Generic400: - description: Problem with the client request - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 400 - code: - enum: - - INVALID_ARGUMENT - examples: - GENERIC_400_INVALID_ARGUMENT: - description: Invalid Argument. Generic Syntax Exception - value: - status: 400 - code: INVALID_ARGUMENT - message: Client specified an invalid argument, request body or query param. - Generic401: - description: Authentication problem with the client request - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 401 - code: - enum: - - UNAUTHENTICATED - examples: - GENERIC_401_UNAUTHENTICATED: - description: Request cannot be authenticated and a new authentication is required - value: - status: 401 - code: UNAUTHENTICATED - message: Request not authenticated due to missing, invalid, or expired credentials. A new authentication is required. - Generic403: - description: Client does not have sufficient permission - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 403 - code: - enum: - - PERMISSION_DENIED - examples: - GENERIC_403_PERMISSION_DENIED: - description: Permission denied. OAuth2 token access does not have the required scope or when the user fails operational security - value: - status: 403 - code: PERMISSION_DENIED - message: Client does not have sufficient permissions to perform this action. - Generic410: - description: Gone - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 410 - code: - enum: - - GONE - examples: - GENERIC_410_GONE: - description: Use in notifications flow to allow API Consumer to indicate that its callback is no longer available - value: - status: 410 - code: GONE - message: Access to the target resource is no longer available. - Generic429: - description: Too Many Requests - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 429 - code: - enum: - - TOO_MANY_REQUESTS - examples: - GENERIC_429_TOO_MANY_REQUESTS: - description: Access to the API has been temporarily blocked due to rate or spike arrest limits being reached - value: - status: 429 - code: TOO_MANY_REQUESTS - message: Rate limit reached. - examples: - QOS_STATUS_CHANGED_EXAMPLE: - value: - id: "123e4567-e89b-12d3-a456-426655440000" - source: "https://notificationSendServer12.example.com" - type: "org.camaraproject.quality-on-demand.v0.qos-status-changed" - specversion: "1.0" - time: "2023-01-17T13:18:23.682Z" - datacontenttype: "application/json" - data: - sessionId: "6e8bc430-9c3a-11d9-9669-0800200c9a66" - qosStatus: UNAVAILABLE - statusInfo: DURATION_EXPIRED diff --git a/artifacts/notification-templates/sample-notification.yaml b/artifacts/notification-templates/sample-notification.yaml new file mode 100644 index 00000000..c0d5b727 --- /dev/null +++ b/artifacts/notification-templates/sample-notification.yaml @@ -0,0 +1,77 @@ +openapi: 3.0.3 +info: + title: Sample Notification Template + description: | + Template for the CAMARA event notification callback endpoint. + This is the receiver-side endpoint that API consumers implement to receive event notifications. + + Additional information is provided in the + [CAMARA API Event Subscription and Notification Guide](https://github.com/camaraproject/Commonalities/blob/main/documentation/CAMARA-API-Event-Subscription-and-Notification-Guide.md#3-event-notification). + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + version: wip + + x-camara-commonalities: 0.8.0 + +externalDocs: + description: Product documentation at CAMARA + url: https://github.com/camaraproject/Commonalities + +servers: + - url: "{apiRoot}" + variables: + apiRoot: + default: https://localhost:8080 + description: Can be any notification server address sent by the client application + +tags: + - name: CAMARA Cloud Event + description: Events received on subscription listener side. + +security: + - notificationsBearerAuth: [] + - {} + +paths: + /your_webhook_notification_url: + post: + tags: + - CAMARA Cloud Event + summary: Cloud Event notification endpoint to notify consumer that statement of fact had occurred + description: | + INFORMATIVE ENDPOINT: The value of this endpoint is freely declared by each client app by means of resource-based + subscription or instance-based subscription. `/your_webhook_notification_url` is + just a convention naming referring to an absolute URL, indeed the one indicated by API client + in the triggering of the procedure (resource-based or instance-based). In this way, it represents an absolute + URL, i.e.: notifications won't be sent to `/event-notification/vX/your_webhook_notification_url`. + operationId: sendEvent + parameters: + - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" + requestBody: + required: true + content: + application/cloudevents+json: + schema: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/CloudEvent" + responses: + "204": + description: No Content + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + "400": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic400" + "401": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic401" + "403": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic403" + "429": + $ref: "../common/CAMARA_common.yaml#/components/responses/Generic429" + +components: + securitySchemes: + notificationsBearerAuth: + type: http + scheme: bearer + bearerFormat: "{$request.body#/sinkCredential.credentialType}" diff --git a/artifacts/camara-cloudevents/event-subscription-template.feature b/artifacts/testing/event-subscription-template.feature similarity index 100% rename from artifacts/camara-cloudevents/event-subscription-template.feature rename to artifacts/testing/event-subscription-template.feature From 7494d0c928ee691c6dc8e834d354e7984459f756 Mon Sep 17 00:00:00 2001 From: Herbert Damker <52109189+hdamker@users.noreply.github.com> Date: Tue, 31 Mar 2026 15:04:29 +0200 Subject: [PATCH 3/3] fix: update stale template reference in feature file comment --- artifacts/testing/event-subscription-template.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artifacts/testing/event-subscription-template.feature b/artifacts/testing/event-subscription-template.feature index 0c862eba..f3ece0a1 100644 --- a/artifacts/testing/event-subscription-template.feature +++ b/artifacts/testing/event-subscription-template.feature @@ -14,7 +14,7 @@ Feature: Camara Template Subscriptions API, v{version here} - Operations on subs # + Add here the specific testing asset(s) required to test the API # # References to OAS spec schemas refer to schemas specified in -subscriptions.yaml - # References to schemas starting with the # symbol are JSON Pointers from the root of the OAS document: -subscriptions.yaml, Schema names are aligned with the event-subscription-template.yaml artifact. + # References to schemas starting with the # symbol are JSON Pointers from the root of the OAS document: -subscriptions.yaml, Schema names are aligned with the sample-service-subscriptions.yaml template. # # IMPORTANT: # 1/ This file must be completed with the test cases specific to the subscription type managed by the API.