From ef4f1f2142a932094d2c0a5ff194eab96866fccd Mon Sep 17 00:00:00 2001 From: Alberto Ramos Monagas Date: Tue, 15 Sep 2026 15:26:11 +0200 Subject: [PATCH] chore/align yaml and spec to commonalities r4.4 --- .../population-density-data.yaml | 132 +++++++++--------- .../population-density-data.feature | 20 ++- 2 files changed, 85 insertions(+), 67 deletions(-) diff --git a/code/API_definitions/population-density-data.yaml b/code/API_definitions/population-density-data.yaml index 540fbf4..f50ba8c 100644 --- a/code/API_definitions/population-density-data.yaml +++ b/code/API_definitions/population-density-data.yaml @@ -112,21 +112,31 @@ info: The standard behaviour of the API is synchronous, although for large area requests the API may behave asynchronously. An API invoker can enforce asynchronous behaviour by providing a callback URL (`sink`) - in the request, in this case the API sends a callback + in the request; in this case the API sends a callback to the callback URL provided with the result of the request. If `sink` is included, it is RECOMMENDED for the client to provide as well the `sinkCredential` property to protect the notification endpoint. In the current version,`sinkCredential.credentialType` MUST be set to `ACCESSTOKEN` or `PRIVATE_KEY_JWT` if provided. - For requests with a combination of `area`, `precision`, `startTime` and `endTime` - properties involving an amount of processing that cannot be processed synchronously, - the API returns the error response `POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE`. + Three different `422` error responses distinguish why a request cannot be served. They are + mutually exclusive and are evaluated in this order: + - `POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE`: the API consumer requested the + asynchronous behaviour by providing `sink`, but the API provider does not support asynchronous + processing at all. This error depends only on the capabilities of the implementation, never on + the size of the request: it is returned even for a request small enough to be served + synchronously. The API consumer can retry the same request without `sink` to obtain a + synchronous response. - For requests with a combination of `area`, `precision`, `startTime` and `endTime` - properties too big for both synchronous and asynchronous processing, the API - returns the error response `POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST`. + - `POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE`: the combination of `area`, `precision`, + `startTime` and `endTime` involves an amount of processing that cannot be handled synchronously, + and asynchronous processing is not enabled. Unlike the previous error, this one depends on the + size of the request, so a smaller request would succeed. + + - `POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST`: the combination of `area`, `precision`, + `startTime` and `endTime` is too big to be processed **even asynchronously**. Retrying with + `sink` does not help; only a smaller request does. If an error happens during the asynchronous processing of the request. The API callback will have property `status` with value `OPERATION_NOT_COMPLETED` as an error cannot be returned in the callback. @@ -143,6 +153,7 @@ info: density information in the specified area. + # Authorization and authentication The "Camara Security and Interoperability Profile" provides details of how an API consumer requests an access token. Please refer to Identity and Consent Management (https://github.com/camaraproject/IdentityAndConsentManagement/) for the released version of the profile. @@ -156,16 +167,18 @@ info: Therefore, the access to Population Density Data API is defined as Client Credentials - 2-legged. Please refer to Identity and Consent Management (https://github.com/camaraproject/IdentityAndConsentManagement/) for the latest detailed specification of this authentication/authorization flow. + # Additional CAMARA error responses The list of error codes in this API specification is not exhaustive. Therefore the API specification MAY not document some non-mandatory error statuses as indicated in `CAMARA API Design Guide`. - Please refer to the `CAMARA_common.yaml` of the Commonalities Release associated to this API version for a complete list of error responses. The applicable Commonalities Release can be identified in the `API Readiness Checklist` document associated to this API version. + Please refer to the `CAMARA_common.yaml` of the Commonalities Release associated to this API version for a complete list of error responses. The applicable Commonalities Release can be identified from the `x-camara-commonalities` field, the changelog and the metadata of the released API version. As a specific rule, error `501 - NOT_IMPLEMENTED` can be only a possible error response if it is explicitly documented in the API. + # Request body strictness This API rejects requests with JSON request bodies that contain properties not declared in this specification, at any nesting level. Unknown properties result in a `400 INVALID_ARGUMENT` response. @@ -176,7 +189,7 @@ info: url: https://www.apache.org/licenses/LICENSE-2.0.html version: wip - x-camara-commonalities: wip + x-camara-commonalities: 0.9.0 externalDocs: description: Product documentation at CAMARA. url: https://github.com/camaraproject/PopulationDensityData @@ -263,15 +276,15 @@ paths: x-correlator: $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" '400': - $ref: '../common/CAMARA_common.yaml#/components/responses/Generic400' + $ref: '../common/CAMARA_common.yaml#/components/responses/BadRequest400' '401': - $ref: '../common/CAMARA_common.yaml#/components/responses/Generic401' + $ref: '../common/CAMARA_common.yaml#/components/responses/Unauthenticated401' '403': - $ref: '../common/CAMARA_common.yaml#/components/responses/Generic403' + $ref: '../common/CAMARA_common.yaml#/components/responses/PermissionDenied403' '410': - $ref: '../common/CAMARA_common.yaml#/components/responses/Generic410' + $ref: '../common/CAMARA_event_common.yaml#/components/responses/SinkGone410' '429': - $ref: '../common/CAMARA_common.yaml#/components/responses/Generic429' + $ref: '../common/CAMARA_common.yaml#/components/responses/TooManyRequests429' security: - {} - notificationsBearerAuth: [] @@ -305,15 +318,13 @@ paths: '400': $ref: '#/components/responses/RetrieveLocationBadRequest400' '401': - $ref: '../common/CAMARA_common.yaml#/components/responses/Generic401' + $ref: '../common/CAMARA_common.yaml#/components/responses/Unauthenticated401' '403': - $ref: '../common/CAMARA_common.yaml#/components/responses/Generic403' - '404': - $ref: '../common/CAMARA_common.yaml#/components/responses/Generic404' + $ref: '../common/CAMARA_common.yaml#/components/responses/PermissionDenied403' '422': $ref: '#/components/responses/RetrieveLocationUnprocessableContent422' '429': - $ref: '../common/CAMARA_common.yaml#/components/responses/Generic429' + $ref: '../common/CAMARA_common.yaml#/components/responses/TooManyRequests429' security: - openId: - population-density-data:read @@ -350,12 +361,14 @@ components: maximum: 12 default: 7 sink: - type: string - format: uri - maxLength: 2048 - description: The address where the API response will be asynchronously delivered, using the HTTP protocol. - pattern: ^https:\/\/.+$ - example: 'https://endpoint.example.com/sink' + description: | + The address where the API response will be asynchronously delivered, using the HTTP protocol. + Providing `sink` enforces the asynchronous behaviour of the API. If the API provider does not + support asynchronous processing, the request MUST be rejected with the error response + `422 POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE` and no callback is delivered. + The API consumer can then retry the request without `sink` to obtain a synchronous response. + allOf: + - $ref: "../common/CAMARA_event_common.yaml#/components/schemas/Sink" sinkCredential: $ref: "../common/CAMARA_event_common.yaml#/components/schemas/SinkCredential" required: @@ -489,21 +502,15 @@ components: type: object properties: startTime: - type: string - format: date-time - maxLength: 64 - description: >- - Interval start time. It must follow [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) - and must have time zone. - example: "2023-07-03T10:00:00Z" + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" + - description: Interval start time. + example: "2023-07-03T10:00:00Z" endTime: - type: string - format: date-time - maxLength: 64 - description: >- - Interval end time. It must follow [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) - and must have time zone. - example: "2023-07-03T11:00:00Z" + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" + - description: Interval end time. + example: "2023-07-03T11:00:00Z" cellPopulationDensityData: $ref: '#/components/schemas/CellPopulationDensityDataArray' required: @@ -588,7 +595,6 @@ components: - Indicated `endTime` is earlier than the `startTime` ("code": "POPULATION_DENSITY_DATA.INVALID_END_TIME", "message": "Indicated endTime is earlier than the startTime") - Indicated time period is partially in the past and partially in the future ("code": "POPULATION_DENSITY_DATA.INVALID_TIME_PERIOD", "message": "time period is partially in the past and partially in the future") - Indicated time period is greater than the maximum allowed (More than maximum hours between startTime and endTime) ("code": "POPULATION_DENSITY_DATA.MAX_TIME_PERIOD_EXCEEDED", "message": "Indicated time period is greater than the maximum allowed (More than maximum hours between startTime and endTime)") - - `sinkCredential.credentialType` is set to `PRIVATE_KEY_JWT` but no JWK Set is configured for the API consumer ("code": "PRIVATE_KEY_JWT_NOT_CONFIGURED", "message": "No JWK Set configured for PRIVATE_KEY_JWT authentication.") headers: x-correlator: $ref: '../common/CAMARA_common.yaml#/components/headers/x-correlator' @@ -614,30 +620,15 @@ components: - POPULATION_DENSITY_DATA.INVALID_END_TIME - POPULATION_DENSITY_DATA.MAX_TIME_PERIOD_EXCEEDED - POPULATION_DENSITY_DATA.INVALID_TIME_PERIOD - - PRIVATE_KEY_JWT_NOT_CONFIGURED examples: GENERIC_400_INVALID_ARGUMENT: - value: - status: 400 - code: INVALID_ARGUMENT - message: Invalid input + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_400_INVALID_ARGUMENT" 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 + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_CREDENTIAL" GENERIC_400_INVALID_TOKEN: - value: - status: 400 - code: INVALID_TOKEN - message: "Only bearer token is supported" + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_TOKEN" GENERIC_400_INVALID_SINK: - description: Invalid sink value - value: - status: 400 - code: INVALID_SINK - message: sink not valid for the specified protocol + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_SINK" POPULATION_DENSITY_DATA_400_INVALID_AREA: value: status: 400 @@ -677,10 +668,12 @@ components: RetrieveLocationUnprocessableContent422: description: >- Problem with the client request. The following scenarios may exist: - - Indicated combination of area, time interval and precision is too big ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST", "message": "Indicated combination of area, time interval and precision is too big") + - Indicated combination of area, time interval and precision is too big for both synchronous and asynchronous processing, so providing `sink` does not help ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST", "message": "Indicated combination of area, time interval and precision is too big") - Indicated cell precision (Geohash level) is not supported ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION", "message": "Indicated cell precision (Geohash level) is not supported") - - Indicated combination of area, time interval and precision is too big for a sync response ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE", "message": "Indicated combination of area, time interval and precision is too big for a sync response") + - Indicated combination of area, time interval and precision is too big for a sync response and asynchronous processing is not enabled ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE", "message": "Indicated combination of area, time interval and precision is too big for a sync response") + - `sink` is provided but the API provider does not support asynchronous processing at all, whatever the size of the request ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE", "message": "The API provider does not support the asynchronous processing") - The requested `areaType` is not supported by the MNO ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE", "message": "The requested areaType is not supported by the MNO") + - `sinkCredential.credentialType` is set to `PRIVATE_KEY_JWT` but no JWK Set is configured for the API consumer ("code": "PRIVATE_KEY_JWT_NOT_CONFIGURED", "message": "No JWK Set configured for PRIVATE_KEY_JWT authentication.") headers: x-correlator: $ref: '../common/CAMARA_common.yaml#/components/headers/x-correlator' @@ -700,9 +693,13 @@ components: - POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION - POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE - POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE + - POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE - PRIVATE_KEY_JWT_NOT_CONFIGURED examples: POPULATION_DENSITY_DATA_422_UNSUPPORTED_REQUEST: + description: >- + The request is too big to be processed even asynchronously, so retrying it with sink does not + help. Only a smaller request does value: status: 422 code: POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST @@ -725,12 +722,17 @@ components: status: 422 code: POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE message: The requested areaType is not supported by the MNO - GENERIC_422_PRIVATE_KEY_JWT_NOT_CONFIGURED: - description: Private key JWT sink credential type is used but no configuration was pre-shared + POPULATION_DENSITY_DATA_422_UNSUPPORTED_ASYNC_RESPONSE: + description: >- + The API consumer requested the asynchronous behaviour by providing sink, but the API provider + does not support asynchronous processing. Unlike UNSUPPORTED_REQUEST, this error does not depend + on the size of the request value: status: 422 - code: PRIVATE_KEY_JWT_NOT_CONFIGURED - message: No JWK Set configured for PRIVATE_KEY_JWT authentication. + code: POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE + message: The API provider does not support the asynchronous processing + GENERIC_422_PRIVATE_KEY_JWT_NOT_CONFIGURED: + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_422_PRIVATE_KEY_JWT_NOT_CONFIGURED" examples: PopulationDensitySupportedAreaResponseExample: description: Population density supported area response example diff --git a/code/Test_definitions/population-density-data.feature b/code/Test_definitions/population-density-data.feature index 5d4ceca..37d0e63 100644 --- a/code/Test_definitions/population-density-data.feature +++ b/code/Test_definitions/population-density-data.feature @@ -10,6 +10,7 @@ Feature: CAMARA Population Density Data API, vwip # * Limitations about max complexity of requested area allowed # * Whether the GEOHASHLIST area type is supported # * Whether `PRIVATE_KEY_JWT` is accepted as `sinkCredential.credentialType` + # * Whether asynchronous processing is supported (it determines whether scenarios 07, 08 and 11 or scenario 422.07 apply) # # Testing assets: # * An Area within the supported region @@ -538,7 +539,7 @@ Feature: CAMARA Population Density Data API, vwip And the response property "$.message" contains a user friendly text @population_density_data_422.03_too_big_request - #To test this scenario provided values for "$.area.boundary", "$.startTime", "$.endTime" and "$.precision" MUST generate a too big response in both sync and async scenarios + #To test this scenario provided values for "$.area.boundary", "$.startTime", "$.endTime" and "$.precision" MUST generate a too big response in both sync and async scenarios. Unlike 422.07, this error is caused by the size of the request and applies even when the implementation does support asynchronous processing Scenario: Error 422 when the response is too big for a sync and async response Given the request body properties "$.area.boundary", "$.startTime", "$.endTime" and "$.precision" are set to valid values When the request "retrievePopulationDensity" is sent @@ -574,7 +575,7 @@ Feature: CAMARA Population Density Data API, vwip And the response property "$.code" is "POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION" And the response property "$.message" contains a user friendly text - @population_density_data_422.06_private_key_jwt_not_configured + @population_density_data_422.06_private_key_jwt_not_configured #To test this scenario the API consumer must not have a JWK Set pre-configured for PRIVATE_KEY_JWT authentication Scenario: Error 422 when PRIVATE_KEY_JWT is requested and no JWK Set is configured for the API consumer Given the API provider has no JWK Set configured for the API consumer used in the test @@ -587,6 +588,21 @@ Feature: CAMARA Population Density Data API, vwip And the response property "$.code" is "PRIVATE_KEY_JWT_NOT_CONFIGURED" And the response property "$.message" contains a user friendly text + @population_density_data_422.07_unsupported_async_response + #To test this scenario the implementation must not support asynchronous processing. The request MUST be small enough to be served synchronously, so that the error is caused by the lack of asynchronous support and not by the size of the request + Scenario: Error 422 when sink is provided but the implementation does not support asynchronous processing + Given the request body property "$.area" is set to a valid testing area within supported regions + And the request body properties "$.startTime" and "$.endTime" are valid future date-times, with "$.endTime" later than "$.startTime" + And the request body properties "$.area", "$.precision", "$.startTime" and "$.endTime" are set to values small enough to be processed synchronously + And the request body property "$.sink" is set to a valid HTTPS URL + When the request "retrievePopulationDensity" is sent + Then the response status code is 422 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 422 + And the response property "$.code" is "POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE" + And the response property "$.message" contains a user friendly text + And no request is received at the address of the request property "$.sink" + # Error 429 scenarios @population_density_data_429.01_too_many_requests