diff --git a/artifacts/camara-cloudevents/event-subscription-template.yaml b/artifacts/camara-cloudevents/event-subscription-template.yaml index e28f39e8..98769daf 100644 --- a/artifacts/camara-cloudevents/event-subscription-template.yaml +++ b/artifacts/camara-cloudevents/event-subscription-template.yaml @@ -4,7 +4,9 @@ info: description: | This file is a template for CAMARA API explicit subscription endpoint and for Notification model. Additional information are provided in API Design Guidelines document. - Note on ``security`` - ``openId`` scope: The value in this yaml `api-name:event-type:grant-level` must be replaced accordingly to the format defined in the guideline document. + 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 @@ -16,14 +18,12 @@ externalDocs: description: Product documentation at CAMARA url: https://github.com/camaraproject/ servers: - - url: "{apiRoot}/{apiName}/v0.1" + - url: "{apiRoot}/api-name/vx.y" + # api-name and version should valued accordingly to the API variables: apiRoot: default: http://localhost:9091 - description: API root - apiName: - default: camaraAPI - description: apiName will be replaced in WG by its value and not modelled as a variable + 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 @@ -40,7 +40,8 @@ paths: - $ref: "#/components/parameters/x-correlator" security: - openId: - - api-name:event-type:grant-level + - api-name:event-type1:grant-level + - api-name:event-type2:grant-level requestBody: content: application/json: @@ -81,10 +82,6 @@ paths: $ref: "#/components/responses/Generic410" "429": $ref: "#/components/responses/Generic429" - "500": - $ref: "#/components/responses/Generic500" - "503": - $ref: "#/components/responses/Generic503" security: - {} - notificationsBearerAuth: [] @@ -116,16 +113,10 @@ paths: $ref: "#/components/responses/SubscriptionPermissionDenied403" "409": $ref: "#/components/responses/Generic409" - "415": - $ref: "#/components/responses/Generic415" "422": $ref: "#/components/responses/CreateSubscriptionUnprocessableEntity422" "429": $ref: "#/components/responses/Generic429" - "500": - $ref: "#/components/responses/Generic500" - "503": - $ref: "#/components/responses/Generic503" get: tags: - Subscription @@ -156,10 +147,6 @@ paths: $ref: "#/components/responses/Generic401" "403": $ref: "#/components/responses/Generic403" - "500": - $ref: "#/components/responses/Generic500" - "503": - $ref: "#/components/responses/Generic503" /subscriptions/{subscriptionId}: get: tags: @@ -191,10 +178,6 @@ paths: $ref: "#/components/responses/Generic403" "404": $ref: "#/components/responses/Generic404" - "500": - $ref: "#/components/responses/Generic500" - "503": - $ref: "#/components/responses/Generic503" delete: tags: - Subscription @@ -230,10 +213,6 @@ paths: $ref: "#/components/responses/Generic403" "404": $ref: "#/components/responses/Generic404" - "500": - $ref: "#/components/responses/Generic500" - "503": - $ref: "#/components/responses/Generic503" components: securitySchemes: openId: @@ -301,13 +280,12 @@ components: types: description: | Camara Event types eligible to be delivered by this subscription. - Note: for the Commonalities meta-release v0.4 we enforce to have only event type per subscription then for following meta-release use of array MUST be decided - at API project level. + Note: for the current Commonalities version (v0.5) only one event type per subscription is allowed, yet in the following releases use of array of event types SHALL be specified without changing this definition. type: array minItems: 1 maxItems: 1 items: - type: string + $ref: "#/components/schemas/SubscriptionEventType" config: $ref: "#/components/schemas/Config" discriminator: @@ -453,13 +431,22 @@ components: EventTypeNotification: type: string description: | - event-type - Event triggered when an event-type event occurred + event-type - Event triggered when an event-type event occurred. Several event-type could be defined. subscription-ends: Event triggered when the subscription ends enum: - - org.camaraproject.api-name.v0.event-type + - org.camaraproject.api-name.v0.event-type1 + - org.camaraproject.api-name.v0.event-type2 - org.camaraproject.api-name.v0.subscription-ends + SubscriptionEventType: + type: string + description: | + event-type that could be subscribed through this subscription. Several event-type could be defined. + enum: + - org.camaraproject.api-name.v0.event-type1 + - org.camaraproject.api-name.v0.event-type2 + Subscription: description: Represents a event-type subscription. type: object @@ -572,7 +559,8 @@ components: discriminator: propertyName: "type" mapping: - org.camaraproject.api-name.v0.event-type: "#/components/schemas/Event-typeEvent" + org.camaraproject.api-name.v0.event-type1: "#/components/schemas/EventApiSpecific1" + org.camaraproject.api-name.v0.event-type2: "#/components/schemas/EventApiSpecific2" org.camaraproject.api-name.v0.subscription-ends: "#/components/schemas/EventSubscriptionEnds" Source: @@ -597,8 +585,14 @@ components: description: Timestamp of when the occurrence happened. Must adhere to RFC 3339. example: "2018-04-05T17:31:00Z" - Event-typeEvent: - description: event structure for event-type event + EventApiSpecific1: + description: event structure for event-type event 1 + allOf: + - $ref: "#/components/schemas/CloudEvent" + - type: object + + EventApiSpecific2: + description: event structure for event-type event 2 allOf: - $ref: "#/components/schemas/CloudEvent" - type: object @@ -965,22 +959,6 @@ components: status: 410 code: GONE message: Access to the target resource is no longer available. - Generic415: - description: Unsupported Media Type - headers: - X-Correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - $ref: "#/components/schemas/ErrorInfo" - examples: - GENERIC_415_UNSUPPORTED_MEDIA_TYPE: - description: Payload format of the request is in an unsupported format by the Server. Should not happen - value: - status: 415 - code: UNSUPPORTED_MEDIA_TYPE - message: The server refuses to accept the request because the payload format is in an unsupported format CreateSubscriptionUnprocessableEntity422: description: Unprocessable Entity headers: @@ -1030,38 +1008,6 @@ components: status: 429 code: TOO_MANY_REQUESTS message: Either out of resource quota or reaching rate limiting. - Generic500: - description: Server error - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - $ref: "#/components/schemas/ErrorInfo" - examples: - GENERIC_500_INTERNAL: - description: Problem in Server side. Regular Server Exception - value: - status: 500 - code: INTERNAL - message: Unknown server error. Typically a server bug. - Generic503: - description: Service unavailable. Typically the server is down. - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - $ref: "#/components/schemas/ErrorInfo" - examples: - GENERIC_503_UNAVAILABLE: - description: Service is not available. Temporary situation usually related to maintenance process in the server side - value: - status: 503 - code: UNAVAILABLE - message: Service Unavailable. SubscriptionIdRequired: description: Problem with the client request headers: diff --git a/documentation/API-design-guidelines.md b/documentation/API-design-guidelines.md index cac51128..5bb2fc1d 100644 --- a/documentation/API-design-guidelines.md +++ b/documentation/API-design-guidelines.md @@ -13,7 +13,7 @@ This document captures guidelines for the API design in CAMARA project. These gu - [2.2 API First](#22-api-first) - [2.3 Interface standardization. Standardization fora.](#23-interface-standardization-standardization-fora) - [2.4 Information Representation Standard](#24-information-representation-standard) - - [2.5 Reduce telco-specific terminology in API definitions](#25-reduce-telco-specific-terminology-in-api-definitions) + - [2.5 Reduce telco-specific terminology in API definitions](#25-reduce-telco-specific-terminology-in-api-definitions) - [3. API Definition](#3-api-definition) - [3.1 API REST](#31-api-rest) - [POST or GET for transferring sensitive or complex data](#post-or-get-for-transferring-sensitive-or-complex-data) @@ -66,16 +66,21 @@ This document captures guidelines for the API design in CAMARA project. These gu - [Examples](#examples) - [APIs which deal with explicit subscriptions](#apis-which-deal-with-explicit-subscriptions) - [API-level scopes (sometimes referred to as wildcard scopes in CAMARA)](#api-level-scopes-sometimes-referred-to-as-wildcard-scopes-in-camara) + - [11.7 Resource access restriction](#117-resource-access-restriction) - [12. Subscription, Notification \& Event](#12-subscription-notification--event) - [12.1 Subscription](#121-subscription) - [Instance-based (implicit) subscription](#instance-based-implicit-subscription) - [Instance-based (implicit) subscription example](#instance-based-implicit-subscription-example) - [Resource-based (explicit) subscription](#resource-based-explicit-subscription) + - [Operations](#operations) + - [Rules for subscriptions data minimization](#rules-for-subscriptions-data-minimization) + - [Subscriptions data model](#subscriptions-data-model) - [Error definition for resource-based (explicit) subscription](#error-definition-for-resource-based-explicit-subscription) - [Termination for resource-based (explicit) subscription](#termination-for-resource-based-explicit-subscription) - [Resource-based (explicit) example](#resource-based-explicit-example) - [12.2 Event notification](#122-event-notification) - [Event notification definition](#event-notification-definition) + - [subscription-ends event](#subscription-ends-event) - [Error definition for event notification](#error-definition-for-event-notification) - [Correlation Management](#correlation-management) - [Security Considerations](#security-considerations) @@ -551,23 +556,23 @@ API versions use a numbering scheme in the format: `x.y.z` ### 5.1 API version (OAS info object) -The API version is defined in the `version` field (in the `info` object) of the OAS definition file of an API.  +The API version is defined in the `version` field (in the `info` object) of the OAS definition file of an API. ```yaml info: title: Number Verification description: text describing the API - version: 2.2.0   + version: 2.2.0 #... ``` -In line with Semantic Versioning 2.0.0, the API with MAJOR.MINOR.PATCH version number, increments as follows: +In line with Semantic Versioning 2.0.0, the API with MAJOR.MINOR.PATCH version number, increments as follows: -1. The MAJOR version when an incompatible / breaking API change is introduced -2. The MINOR version when functionality is added that is backwards compatible -3. The PATCH version when backward compatible bugs are fixed +1. The MAJOR version when an incompatible / breaking API change is introduced +2. The MINOR version when functionality is added that is backwards compatible +3. The PATCH version when backward compatible bugs are fixed -For more details on MAJOR, MINOR and PATCH versions, and how to evolve API versions, please see [API versioning](https://wiki.camaraproject.org/x/a4BaAQ) in the CAMARA wiki.  +For more details on MAJOR, MINOR and PATCH versions, and how to evolve API versions, please see [API versioning](https://wiki.camaraproject.org/x/a4BaAQ) in the CAMARA wiki. It is recommended to avoid breaking backward compatibility unless strictly necessary: new versions should be backwards compatible with previous versions. More information on how to avoid breaking changes can be found below. @@ -579,7 +584,7 @@ The API version in the `url` field only includes the "x" (MAJOR version) number ```yaml servers: -    url: {apiRoot}/qod/v2 + url: {apiRoot}/qod/v2 ``` --- @@ -590,7 +595,7 @@ IMPORTANT: CAMARA public APIs with x=0 (`v0.x.y`) MUST use both the MAJOR and th ```yaml servers: -    url: {apiRoot}/number-verification/v0.3 + url: {apiRoot}/number-verification/v0.3 ``` This allows for both test and commercial usage of initial API versions as they are evolving rapidly, e.g. `/qod/v0.10alpha1`, `/qod/v0.10rc1`, or `/qod/v0.10`. However, it should be acknowledged that any initial API version may change. @@ -604,7 +609,7 @@ Overall, an API can have any of the following versions: * work-in-progress (`wip`) API versions used during the development of an API before the first pre-release or in between pre-releases. Such API versions cannot be released and are not usable by API consumers. * alpha (`x.y.z-alpha.m`) API versions (with extensions) for CAMARA internal API rapid development purposes * release-candidate (`x.y.z-rc.n`) API versions (with extensions) for CAMARA internal API release bug fixing purposes -* public (`x.y.z`) API versions for usage in commercial contexts. These API versions only have API version number x.y.z (semver 2.0), no extension. Public APIs can have one of two maturity states (used in release management):  +* public (`x.y.z`) API versions for usage in commercial contexts. These API versions only have API version number x.y.z (semver 2.0), no extension. Public APIs can have one of two maturity states (used in release management): * initial - indicating that the API is still not fully stable (x=0) * stable - indicate that the API has reached a certain level of maturity (x>0) @@ -614,7 +619,7 @@ The following table gives the values of the API version (Info object) and the AP |-------------------|:-------------:|:--------------------------------:|:-------------------------------:|:---------------------------:| | work-in-progress | wip | vwip | vwip | No | | alpha | x.y.z-alpha.m | v0.yalpham | vxalpham | Yes (internal pre-release) | -| release-candidate |  x.y.z-rc.n | v0.yrcn | vxrcn | Yes (internal pre-release) | +| release-candidate | x.y.z-rc.n | v0.yrcn | vxrcn | Yes (internal pre-release) | | public | x.y.z | v0.y | vx | Yes | Precedence examples: @@ -666,7 +671,7 @@ Compatibility management: To ensure this compatibility, the following guidelines must be applied. **As API provider**: -- Never change an endpoint name; instead, add a new one and mark the original one for deprecation in a MINOR change and remove it in a later MAJOR change (see semver FAQ entry: https://semver.org/#how-should-i-handle-deprecating-functionality) +- Never change an endpoint name; instead, add a new one and mark the original one for deprecation in a MINOR change and remove it in a later MAJOR change (see semver FAQ entry: https://semver.org/#how-should-i-handle-deprecating-functionality) - If possible, do the same for attributes - New fields should always be added as optional. - Postel's Law: “Be conservative in what you do, be liberal in what you accept from others”. When you have input fields that need to be removed, mark them as unused, so they can be ignored. @@ -1568,6 +1573,22 @@ The decision on the API-level scopes was made within the [Identity and Consent M The scopes will always be those defined in the API Specs YAML files. Thus, a scope would only provide access to all endpoints and resources of an API if it is explicitly defined in the API Spec YAML file and agreed in the corresponding API subproject. +### 11.7 Resource access restriction + +In some CAMARA APIs there are functions to create resource (via POST) and then later query them via id and/or list (with GET) or delete them (via DELETE). For example we have sessions, payments, subscriptions, etc.. + +For the GET and DELETE operations we must restrict the resource(s) targeted depending on the information provided in the request. Basically we consider 2 filters: +* API client (aka ClientId) +* access token + +| Operation | 3-legged access token is used | 2-legged access token is used | +|-----------|--------------------------------|-------------------------------| +| GET/{id} | - The resource queried must have been created for the end user associated with the access token.
- The resource queried must have been created by the same API client given in the access token. | - The resource queried must have been created by the same API client given in the access token. | +| GET/ | - Return all resource(s) created by the API consumer that are associated with both the end user identified by the access token and the same API client given in the access token. | - Return all resource(s) created by the same API client given in the access token. | +| DELETE/{id} | - The resource to be deleted must have been created for the end user associated with the access token.
- The resource to be deleted must have been created by the same API client given in the access token. | - The resource to be deleted must have been created by the same API client given in the access token. | + + + ## 12. Subscription, Notification & Event To provide event-based interaction, CAMARA API could provide capabilities for subscription & notification management. @@ -1645,6 +1666,7 @@ CAMARA subscription model leverages **[CloudEvents](https://cloudevents.io/)** a To ensure consistency across Camara subprojects, it is necessary that explicit subscriptions are handled within separate API/s. It is mandatory to append the keyword "subscriptions" at the end of the API name. For e.g. device-roaming-subscriptions.yaml +##### Operations Four operations must be defined: | operation | path | description | @@ -1672,18 +1694,27 @@ The rationale for using this alternate pattern should be explicitly provided (e.g. the notification source for each of the supported events may be completely different, in which case, separating the implementations is beneficial). +##### Rules for subscriptions data minimization + +These rules apply for subscription with device identifier +- If 3-legged access token is used, the POST and GET responses must not provide any device identifier. +- If 2-legged access token is used, the presence of a device identifier in the response is mandatory and should be the same identifier type than the one provided in the request. + +Application of data minimization design must be considered by the API Sub Project for event structure definition. + +##### Subscriptions data model The following table provides `/subscriptions` attributes | name | type | attribute description | cardinality | |----------------|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------| | protocol | string | Identifier of a delivery protocol. **Only** `HTTP` **is allowed for now**. | Mandatory | -| sink | string | https callback address where the notification must be POST-ed | mandatory | -| sinkCredential | object | Sink credential provides authorization information necessary to enable delivery of events to a target. In order to be updated in future this object is polymorphic. See detail below. To protect the notification endpoint providing sinkCredential is RECOMMENDED. | optional | +| sink | string | The address to which events shall be delivered, using the HTTP protocol. | mandatory | +| sinkCredential | object | Sink credential provides authorization information necessary to enable delivery of events to a target. In order to be updated in future this object is polymorphic. See detail below. To protect the notification endpoint providing sinkCredential is RECOMMENDED.
The sinkCredential must **not** be present in `POST` and `GET` responses. | optional | | types | string | Type of event subscribed. This attribute **must** be present in the `POST` request. It is required by API project to provide an enum for this attribute. `type` must follow the format: `org.camaraproject...` with the `api-version` with letter `v` and the major version like ``org.camaraproject.device-roaming-subscriptions.v1.roaming-status`` - Note: An array of types could be passed **but as of now only one value MUST passed**. Use of multiple value will be open later at API level. | mandatory | | config | object | Implementation-specific configuration parameters needed by the subscription manager for acquiring events. In CAMARA we have predefined attributes like ``subscriptionExpireTime``, ``subscriptionMaxEvents`` or ``initialEvent``. See detail below. | mandatory | | id | string | Identifier of the event subscription - This attribute must not be present in the POST request as it is provided by API server | mandatory in server response | | startsAt | string - date-time | Date when the event subscription will begin/began. This attribute must not be present in the `POST` request as it is provided by API server. It must be present in `GET` endpoints | optional | -| expiresAt | string - date-time | Date when the event subscription will expire. This attribute must not be present in the `POST` request as it is provided (optionally) by API server. | optional | +| expiresAt | string - date-time | Date when the event subscription will expire. This attribute must not be present in the `POST` request as it is provided (optionally) by API server. This attribute must be provided by the server if subscriptionExpireTime is provided in the request and server is not able to handle it. | optional | | status | string | 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. See below status table. | optional | @@ -1715,7 +1746,11 @@ Remark: This action will trigger a subscription-ends event with terminationReaso | initialEvent | boolean | 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. | optional | -Subscription status value table: +**Note** on combined usage of initialEvent and subscriptionMaxEvents: +Unless explicitly decided otherwise by the API Sub Project, if an event is triggered following initialEvent set to `true`, this event will be counted towards subscriptionMaxEvents (if provided). +It is recommended to provide this clarification in all subscription APIs featuring subscriptionMaxEvents and initialEvent. + +**Subscription status value table**: Managing subscription is a draft feature, and it is not mandatory for now. An API project could decide to use/not use it. A list of status is provided for global consistency. @@ -1754,6 +1789,7 @@ It could be useful to provide a mechanism to inform subscriber for all cases. In _Termination rules regarding subscriptionExpireTime & subscriptionMaxEvents usage_ * When client side providing a `subscriptionExpireTime` and/or `subscriptionMaxEvents` service side has to terminate the subscription without expecting a `DELETE` operation. +* CAMARA does not impose limitations for `subscriptionExpireTime` or `subscriptionMaxEvents` but API providers may enforce limitations and must document them accordingly. * If both `subscriptionExpireTime` and `subscriptionMaxEvents` are provided, the subscription will end when the first one is reached. * When none `subscriptionExpireTime` and `subscriptionMaxEvents` are not provided, client side has to trigger a `DELETE` operation to terminate it. * It is perfectly valid for client side to trigger a DELETE operation before `subscriptionExpireTime` and/or `subscriptionMaxEvents` reached. @@ -1874,7 +1910,11 @@ For consistency across CAMARA APIs, the uniform CloudEvents model must be used w Note: For operational and troubleshooting purposes it is relevant to accommodate use of `x-correlator` header attribute. API listener implementations have to be ready to support and receive this data. -Specific event notification type "subscription-ends" is defined to inform listener about subscription termination. It is used when the `subscriptionExpireTime` or `subscriptionMaxEvents` has been reached, or, if the API server has to stop sending notification prematurely. For this specific event, the `data` must feature `terminationReason` attribute. +#### subscription-ends event +Specific event notification type "subscription-ends" is defined to inform listener about subscription termination. + +It is used when the `subscriptionExpireTime` or `subscriptionMaxEvents` has been reached, or, if the API server has to stop sending notifications prematurely, or if the subscription request is managed asynchronously by the server and it is not able to provide the service. For this specific event, the `data` must feature `terminationReason` attribute. An enumeration of `terminationReason` is provided in event-subscription-template.yaml (see in [Commonalities/artifacts/camara-cloudevents](/artifacts/camara-cloudevents) directory ``event-subscription-template.yaml``). + Note: The "subscription-ends" notification is not counted in the `subscriptionMaxEvents`. (for example, if a client request a `subscriptionMaxEvents` to 2, later, received second notification, then a third notification will be sent for "subscription-ends") #### Error definition for event notification