Overview
The Document Download Frontend usesServiceApiClient to communicate with the GOV.UK Notify API for retrieving service information. This client extends the notifications-python-client library with custom request header forwarding.
File: app/notify_client/service_api_client.py
ServiceApiClient Class
Class Definition
NotificationsAPIClient for service-related API calls
Initialization
Constructor parameters:app: Flask application instance
API_HOST_NAME: Base URL for Notify API (e.g.,https://api.notifications.service.gov.uk)ADMIN_CLIENT_USER_NAME: Service ID for authenticationADMIN_CLIENT_SECRET: API key secret
NotificationsAPIClient expects destructured end-user API keys. Service ID and API key are set directly afterward.
OnwardsRequestNotificationsAPIClient
Custom Client Class
NotificationsAPIClient to forward request headers
Inherits: notifications_python_client.notifications.NotificationsAPIClient
Header Forwarding
Method:generate_headers(api_token)
Behavior:
- Call parent class
generate_headers()to get standard auth headers - Check if in Flask request context
- If
request.get_onwards_request_headersexists, merge those headers - Return combined headers
X-B3-TraceId) when making API calls, enabling distributed tracing across services.
Onwards Request Headers
Source: Added by Flask middleware (not shown in these files) Typical headers forwarded:X-B3-TraceId- Distributed tracing IDX-B3-SpanId- Span ID for tracingX-Request-ID- Request correlation ID
has_request_context(): Ensures we’re in a Flask request (not CLI/background task)hasattr(request, "get_onwards_request_headers"): Checks middleware added the method
API Methods
get_service()
Method signature:service_id(str|UUID): Service UUID
landing()(index.py:52)confirm_email_address()(index.py:102)download_document()(index.py:185)
Error Handling
HTTPError Exceptions
Source:notifications_python_client.errors.HTTPError
Raised when: API returns non-2xx status code
Attributes:
status_code: HTTP status code from APImessage: Error message
404: Service not found403: Forbidden (invalid credentials)500: API server error
Authentication
API Key Authentication
Method: JWT token inAuthorization header
Generated by: generate_headers() in parent class
Header format:
iss: Service ID (fromADMIN_CLIENT_USER_NAME)iat: Issued at timestamp
ADMIN_CLIENT_SECRET)
Configuration
Environment variables:Integration with Views
Global Instance
File:app/__init__.py
Usage in Routes
Helper function pattern:Alternative: Direct API Calls
Some endpoints bypassServiceApiClient and use requests directly:
Document Metadata
Why not use ServiceApiClient? Document Download API is separate from Notify API Implementation:OnwardsRequestNotificationsAPIClient
Dependencies
Required packages:notifications-python-client- Official Notify Python clientFlask- Request context handling
Testing Considerations
Mocking Service API
Request Context for Headers
Related Configuration
Config keys used:API_HOST_NAME- Notify API base URLADMIN_CLIENT_USER_NAME- Service ID for authADMIN_CLIENT_SECRET- API key secretDOCUMENT_DOWNLOAD_API_HOST_NAME_INTERNAL- Document API URL (separate service)