diff --git a/.changeset/deprecate-504-events-search.md b/.changeset/deprecate-504-events-search.md new file mode 100644 index 00000000..1ec11149 --- /dev/null +++ b/.changeset/deprecate-504-events-search.md @@ -0,0 +1,5 @@ +--- +'@fingerprint/python-sdk': minor +--- + +**events-search**: The `504` response for the Events Search endpoint is deprecated and will no longer be generated by the Server API. diff --git a/.changeset/deprecate-504-events.md b/.changeset/deprecate-504-events.md new file mode 100644 index 00000000..07cfcb16 --- /dev/null +++ b/.changeset/deprecate-504-events.md @@ -0,0 +1,5 @@ +--- +'@fingerprint/python-sdk': minor +--- + +**events**: The `504` response for the Get Event endpoint is deprecated and will no longer be generated by the Server API. diff --git a/.changeset/error-response-503-events-search.md b/.changeset/error-response-503-events-search.md new file mode 100644 index 00000000..f70fce61 --- /dev/null +++ b/.changeset/error-response-503-events-search.md @@ -0,0 +1,5 @@ +--- +'@fingerprint/python-sdk': minor +--- + +**events-search**: Add `503` Service Temporarily Unavailable response to the Events Search endpoint diff --git a/.changeset/error-response-503-events.md b/.changeset/error-response-503-events.md new file mode 100644 index 00000000..ac413c14 --- /dev/null +++ b/.changeset/error-response-503-events.md @@ -0,0 +1,5 @@ +--- +'@fingerprint/python-sdk': minor +--- + +**events**: Add `503` Service Temporarily Unavailable response to the Get Event endpoint diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 00000000..8186e344 --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,8 @@ +{ + "mode": "pre", + "tag": "rc", + "initialVersions": { + "@fingerprint/python-sdk": "9.8.0" + }, + "changesets": [] +} diff --git a/.schema-version b/.schema-version index ea535dc5..65aee83a 100644 --- a/.schema-version +++ b/.schema-version @@ -1 +1 @@ -v3.8.0 \ No newline at end of file +v3.9.0 \ No newline at end of file diff --git a/docs/DeviceDetails.md b/docs/DeviceDetails.md index b79e8631..f9f34dc1 100644 --- a/docs/DeviceDetails.md +++ b/docs/DeviceDetails.md @@ -5,7 +5,7 @@ Native, SDK-collected mobile device identification signals (manufacturer, model, Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **device_manufacturer** | **str** | Raw device manufacturer string as reported by the device OS. Not normalized: casing is vendor-defined (samsung, Xiaomi, OPPO, HUAWEI). Always `Apple` on iOS. | [optional] -**device_model** | **str** | Raw device model identifier, as reported by the mobile OS. | [optional] +**device_model** | **str** | Raw device model identifier, as reported by the mobile OS. On Android, this is the vendor-defined model string (e.g., `SM-G991U`). On iOS, this is an Apple board code (e.g., `D84AP`). | [optional] **os_version** | **str** | Mobile operating system version. Component count is not fixed and must not be assumed by consumers: iOS always reports `major.minor.patch` (e.g. `17.4.1`), while Android's precision varies by OS era and which raw signal resolved it — `major` only (`9`, `13`) since Android 10 dropped point releases, `major.minor` (`16.1`) from Android 16 (API 36+) reintroducing a minor component, or a genuine `major.minor.patch` (`8.1.0`) on pre-Android 10 devices that shipped real point releases. Never a fabricated/zero-padded component. | [optional] [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/docs/FingerprintApi.md b/docs/FingerprintApi.md index 795ae2d8..c1418a8c 100644 --- a/docs/FingerprintApi.md +++ b/docs/FingerprintApi.md @@ -191,9 +191,10 @@ Name | Type | Description | Notes **400** | Bad request. The event ID provided is not valid. | - | **403** | Forbidden. Access to this API is denied. | - | **404** | Not found. The event ID cannot be found in this workspace's data. | - | -**429** | Too Many Requests. The request is throttled. To protect service stability during rare periods of extreme load, we may return HTTP 429 responses with message `too many search requests` even if you are within your assigned rate limits. | - | +**429** | Too Many Requests. The request is throttled. | - | **500** | Workspace error. | - | -**504** | Gateway Timeout. Search execution exceeded the allowed timeout window. | - | +**503** | Service Temporarily Unavailable. | - | +**504** | Gateway Timeout. | - | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) @@ -404,9 +405,10 @@ Name | Type | Description | Notes **400** | Bad request. One or more supplied search parameters are invalid, or a required parameter is missing. | - | **403** | Forbidden. Access to this API is denied. | - | **404** | Not found. The requested visitor does not exist in this workspace's data. | - | -**429** | Too Many Requests. The request is throttled. To protect service stability during rare periods of extreme load, we may return HTTP 429 responses with message `too many search requests` even if you are within your assigned rate limits. | - | +**429** | Too Many Requests. The request is throttled. | - | **500** | Workspace error. | - | -**504** | Gateway Timeout. Search execution exceeded the allowed timeout window. | - | +**503** | Service Temporarily Unavailable. | - | +**504** | Gateway Timeout. | - | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) diff --git a/fingerprint_server_sdk/api/fingerprint_api.py b/fingerprint_server_sdk/api/fingerprint_api.py index aca258fb..145c04e1 100644 --- a/fingerprint_server_sdk/api/fingerprint_api.py +++ b/fingerprint_server_sdk/api/fingerprint_api.py @@ -363,6 +363,7 @@ def get_event( '404': 'ErrorResponse', '429': 'ErrorResponse', '500': 'ErrorResponse', + '503': 'ErrorResponse', '504': 'ErrorResponse', } @@ -438,6 +439,7 @@ def get_event_with_http_info( '404': 'ErrorResponse', '429': 'ErrorResponse', '500': 'ErrorResponse', + '503': 'ErrorResponse', '504': 'ErrorResponse', } @@ -513,6 +515,7 @@ def get_event_without_preload_content( '404': 'ErrorResponse', '429': 'ErrorResponse', '500': 'ErrorResponse', + '503': 'ErrorResponse', '504': 'ErrorResponse', } @@ -1082,6 +1085,7 @@ def search_events( '404': 'ErrorResponse', '429': 'ErrorResponse', '500': 'ErrorResponse', + '503': 'ErrorResponse', '504': 'ErrorResponse', } @@ -1605,6 +1609,7 @@ def search_events_with_http_info( '404': 'ErrorResponse', '429': 'ErrorResponse', '500': 'ErrorResponse', + '503': 'ErrorResponse', '504': 'ErrorResponse', } @@ -2128,6 +2133,7 @@ def search_events_without_preload_content( '404': 'ErrorResponse', '429': 'ErrorResponse', '500': 'ErrorResponse', + '503': 'ErrorResponse', '504': 'ErrorResponse', } diff --git a/fingerprint_server_sdk/models/device_details.py b/fingerprint_server_sdk/models/device_details.py index 34a71b99..3d4338c6 100644 --- a/fingerprint_server_sdk/models/device_details.py +++ b/fingerprint_server_sdk/models/device_details.py @@ -32,7 +32,8 @@ class DeviceDetails(BaseModel): description='Raw device manufacturer string as reported by the device OS. Not normalized: casing is vendor-defined (samsung, Xiaomi, OPPO, HUAWEI). Always `Apple` on iOS.', ) device_model: Optional[StrictStr] = Field( - default=None, description='Raw device model identifier, as reported by the mobile OS.' + default=None, + description='Raw device model identifier, as reported by the mobile OS. On Android, this is the vendor-defined model string (e.g., `SM-G991U`). On iOS, this is an Apple board code (e.g., `D84AP`).', ) os_version: Optional[StrictStr] = Field( default=None, diff --git a/res/fingerprint-server-api.yaml b/res/fingerprint-server-api.yaml index c71de893..bc18d5b1 100644 --- a/res/fingerprint-server-api.yaml +++ b/res/fingerprint-server-api.yaml @@ -17,8 +17,7 @@ info: email: support@fingerprint.com license: name: MIT - url: >- - https://github.com/fingerprintjs/fingerprint-pro-server-api-openapi/blob/main/LICENSE + url: https://github.com/fingerprintjs/openapi/blob/main/LICENSE tags: - name: Fingerprint description: >- @@ -104,12 +103,8 @@ paths: schema: $ref: '#/components/schemas/ErrorResponse' '429': - description: > + description: | Too Many Requests. The request is throttled. - - To protect service stability during rare periods of extreme load, we - may return HTTP 429 responses with message `too many search - requests` even if you are within your assigned rate limits. content: application/json: schema: @@ -120,10 +115,15 @@ paths: application/json: schema: $ref: '#/components/schemas/ErrorResponse' + '503': + description: Service Temporarily Unavailable. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' '504': - description: >- - Gateway Timeout. Search execution exceeded the allowed timeout - window. + description: Gateway Timeout. + x-deprecated-response: true content: application/json: schema: @@ -1005,12 +1005,8 @@ paths: schema: $ref: '#/components/schemas/ErrorResponse' '429': - description: > + description: | Too Many Requests. The request is throttled. - - To protect service stability during rare periods of extreme load, we - may return HTTP 429 responses with message `too many search - requests` even if you are within your assigned rate limits. content: application/json: schema: @@ -1021,10 +1017,15 @@ paths: application/json: schema: $ref: '#/components/schemas/ErrorResponse' + '503': + description: Service Temporarily Unavailable. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' '504': - description: >- - Gateway Timeout. Search execution exceeded the allowed timeout - window. + description: Gateway Timeout. + x-deprecated-response: true content: application/json: schema: @@ -2088,8 +2089,11 @@ components: type: string examples: - SM-G991U - - iPhone14,5 - description: Raw device model identifier, as reported by the mobile OS. + - D84AP + description: >- + Raw device model identifier, as reported by the mobile OS. On + Android, this is the vendor-defined model string (e.g., `SM-G991U`). + On iOS, this is an Apple board code (e.g., `D84AP`). os_version: type: string examples: diff --git a/sync.sh b/sync.sh index f4c2efe5..eb4c3e3a 100755 --- a/sync.sh +++ b/sync.sh @@ -38,6 +38,7 @@ examples=( 'errors/404_visitor_not_found.json' 'errors/409_state_not_ready.json' 'errors/429_too_many_requests.json' + 'errors/503_service_unavailable.json' ) for example in "${examples[@]}"; do diff --git a/test/mocks/errors/503_service_unavailable.json b/test/mocks/errors/503_service_unavailable.json new file mode 100644 index 00000000..aebf5cdd --- /dev/null +++ b/test/mocks/errors/503_service_unavailable.json @@ -0,0 +1,6 @@ +{ + "error": { + "code": "service_unavailable", + "message": "service temporarily unavailable" + } +} diff --git a/test/test_fingerprint_api.py b/test/test_fingerprint_api.py index 6ee8c73d..d79951b9 100644 --- a/test/test_fingerprint_api.py +++ b/test/test_fingerprint_api.py @@ -24,6 +24,7 @@ SearchEventsSdkPlatform, SearchEventsSource, SearchEventsVpnConfidence, + ServiceException, TooManyRequestsException, __version__, ) @@ -332,6 +333,30 @@ def test_get_event_too_many_requests(self) -> None: self.assertIsInstance(context.exception.data, ErrorResponse) self.assertEqual(context.exception.data.error.code, ErrorCode.TOO_MANY_REQUESTS) + def test_get_event_service_unavailable(self) -> None: + """Test case for get_event with 503 Service Unavailable response""" + mock_pool = MockPoolManager(self) + self.api.api_client.rest_client.pool_manager = mock_pool + event_id = '0000000000000.XXXXX' + mock_pool.expect_request( + 'GET', + TestFingerprintApi.get_event_path(event_id), + fields=[], + headers=self.request_headers, + preload_content=True, + timeout=None, + response_status_code=503, + response_data_file='errors/503_service_unavailable.json', + ) + + with self.assertRaises(ServiceException) as context: + self.api.get_event(event_id) + + self.assertNotIsInstance(context.exception, GatewayTimeoutException) + self.assertEqual(context.exception.status, 503) + self.assertIsInstance(context.exception.data, ErrorResponse) + self.assertEqual(context.exception.data.error.code, ErrorCode.SERVICE_UNAVAILABLE) + def test_get_event_gateway_timeout(self) -> None: """Test case for get_event with 504 Gateway Timeout response""" mock_pool = MockPoolManager(self) @@ -580,6 +605,31 @@ def test_search_events_too_many_requests(self) -> None: self.assertIsInstance(context.exception.data, ErrorResponse) self.assertEqual(context.exception.data.error.code, ErrorCode.TOO_MANY_REQUESTS) + def test_search_events_service_unavailable(self) -> None: + """Test case for search_events with 503 Service Unavailable response""" + params = {'limit': 2} + + mock_pool = MockPoolManager(self) + self.api.api_client.rest_client.pool_manager = mock_pool + mock_pool.expect_request( + 'GET', + TestFingerprintApi.get_search_events_path(params), + fields=[], + headers=self.request_headers, + preload_content=True, + timeout=None, + response_status_code=503, + response_data_file='errors/503_service_unavailable.json', + ) + + with self.assertRaises(ServiceException) as context: + self.api.search_events(**params) + + self.assertNotIsInstance(context.exception, GatewayTimeoutException) + self.assertEqual(context.exception.status, 503) + self.assertIsInstance(context.exception.data, ErrorResponse) + self.assertEqual(context.exception.data.error.code, ErrorCode.SERVICE_UNAVAILABLE) + def test_search_events_gateway_timeout(self) -> None: """Test case for search_events with 504 Gateway Timeout response""" params = {'limit': 2}