High-Level Architecture¶
The architecture consists of three main components:
- the Experience API,
- the Process API,
- and the System API.
Each component has its own responsibilities and interacts with the other components to fulfill user/client requests, following the Integration Hub's XAPI → PAPI → SAPI pattern. Each layer is implemented as a separate AWS Lambda function, built on an internal framework called ipaas-framework.
A single request from Sapio passes synchronously down through all three layers and back, as illustrated in the diagram below.
- XAPI (
inthub-xapi-sapio-studies) – the entry point Sapio calls. - PAPI (
inthub-papi-mlwh-studies) – a routing/orchestration layer with no business logic of its own. - SAPI (
inthub-sapi-sequencescape) – a thin adapter that talks to the real Sequencescape application over HTTPS.
Supported Operations¶
The architecture below is shared by every operation * only the validation rules and downstream target change per operation.
| Method | Path | Status |
|---|---|---|
GET |
/sapio/studies/v1 |
Implemented, in UAT |
POST |
/sapio/studies/v1 |
Implemented, in UAT |
Architecture Diagram¶
flowchart TD
A[Client/ Sapio]
subgraph XAPI["Experience API"]
direction TD
X1[Validate<br/>Request]
X2[Authenticate<br/>& Authorise]
X3[Normalise<br/>Parameters]
X4[Route to<br/>Process API]
end
subgraph PAPI["Process API"]
direction TD
P1[Build<br/>SQL Query]
P2[Apply<br/>Pagination]
P3[Transform<br/>Request Model]
P4[Route to<br/>System API]
end
subgraph SAPI_SS["System API: SequenceScape"]
direction TD
SS1[Build HTTPS<br/>Request to<br/>SequenceScape API]
SS2[Execute<br/>Query]
SS3[Return<br/>JSON<br/>Response]
end
subgraph SAPI_MLWH["System API: MLWH"]
direction TD
SM1[Execute<br/>Query]
SM2[Map Database<br/>Rows]
SM3[Return<br/>JSON<br/>Response]
end
DB[(MLWH<br/>Database)]
A --> XAPI
XAPI --> PAPI
PAPI --> SAPI_MLWH
PAPI --> SAPI_SS
SAPI_MLWH --> DB
- Each layer is responsible for validating, transforming, and routing the request to the next layer, until it reaches the Sequencescape or MLWH application.
- Every hop is a direct, blocking Lambda invocation (
RequestResponse), so the response flows back up through the same three layers in reverse.
Components¶
XAPI — inthub-xapi-sapio-studies¶
- Purpose: exposes the public-facing surface Sapio calls:
GET /sapio/studies/v1(lookup by name) andPOST /sapio/studies/v1(create a study record). - Responsibilities: validates the inbound request shape, invokes PAPI, and reshapes PAPI's response (JMESPath transform) into the shape Sapio expects.
- Dependencies: the PAPI Lambda, which is the only downstream target for this route.
PAPI — inthub-papi-mlwh-studies¶
- Purpose: a routing layer — it contains no domain logic, only maps an inbound route to the correct downstream SAPI Lambda.
- Responsibilities: for the Sapio-facing route (
/sapio/studies/v1), forwards directly to the SAPI/Sequencescape adapter. - Dependencies: the SAPI/Sequencescape and SAPI/MLWH Lambdas, which are the downstream targets for this route.
SAPI — inthub-sapi-sequencescape¶
- Purpose: adapter between PAPI and the real Sequencescape Rails application — not Sequencescape itself.
- Responsibilities: builds an authenticated HTTPS request to Sequencescape's
/api/v2/sapio/studiesJSON:API endpoint, and normalises both success and error responses back into a consistent shape for PAPI. - Dependencies: the Sequencescape application, which is the downstream target for this route.
Data Flow¶
Every operation shares the same shape: a single blocking round trip down through XAPI → PAPI → SAPI and back, with no retry or fallback path today. * A failure or timeout at any layer surfaces as an error at every layer above it. What differs per operation is the validation applied and the downstream target. Each operation gets its own breakdown below.
GET — look up a study by name¶
- Sapio sends
GET /sapio/studies/v1?name=...to the shared API Gateway. - The custom Lambda authorizer validates the caller before the request reaches XAPI.
- XAPI validates the
namequery parameter, then synchronously invokes PAPI with the request. - PAPI routes the request to the SAPI (Sequencescape) Lambda.
- SAPI calls Sequencescape's
/api/v2/sapio/studiesover HTTPS, authenticating with a secret-stored client-ID header and CA certificate. - Sequencescape's response travels back up unchanged in shape until SAPI normalises it, then PAPI and XAPI each pass it back untouched to the caller.
POST — create a study record¶
- Sapio sends
POST /sapio/studies/v1with a JSON body to the shared API Gateway. - The custom Lambda authorizer validates the caller before the request reaches XAPI.
- Tracking ID is generated in XAPI and attached onto the body for downstream logging and tracing.
- The enriched body (all fields +
event_uuid) is published to SNS, and XAPI returns a202 Acceptedresponse to Sapio immediately. The request is now asynchronous, and the caller does not wait for the downstream processing to complete. - PAPI is then invoked asynchronously by the SNS subscription, and it routes the request to the Sequencescape SAPI.
- The Sequencescape SAPI calls Sequencescape's
/api/v2/sapio/studiesby extracting onlynameanduuidfrom the body. - On Sequencescape success, PAPI then invokes the MLWH SAPI to create a matching record in the sequencing data warehouse.
- On MLWH success, PAPI invokes the Sapio SAPI to confirm back to Sapio that the study now exists in Sequencescape and MLWH — Sapio is the originator of the request and the recipient of this confirmation, not a third place the study record is created.
- If Sequencescape, MLWH, or this confirmation back to Sapio fails, the failure is recorded, an email alert is sent to the configured user group, and the record is pushed to a dead-letter queue for reprocessing. The caller already received its
202before any of this happens, so failures are only visible through these channels, not in the original response.
Current status of the Sapio confirmation step
Step 8 above describes the target design. Today, this step is routed to a mock in every environment rather than calling Sapio's real API — it's intentionally still a stub while that leg of the integration is finished.
Because the POST flow branches on success/failure at each of the three downstream systems, and because Sapio's own response comes back long before that branching happens, it's worth seeing as a diagram rather than prose alone:
sequenceDiagram
participant Sapio
participant XAPI
participant PAPI
participant Sequencescape
participant MLWH
participant Notifications as Notification Service
Sapio->>XAPI: POST /sapio/studies/v1
XAPI->>XAPI: Validate, generate event_uuid
XAPI-->>Sapio: 202 Accepted (event_uuid)
XAPI->>PAPI: Publish via SNS (async)
PAPI->>Sequencescape: Create study
alt Sequencescape succeeds
PAPI->>MLWH: Insert study row
alt MLWH succeeds
PAPI->>Sapio: Confirm study created
alt Confirmation fails
PAPI->>Notifications: Send failure alert
PAPI->>PAPI: Push to dead-letter queue
end
else MLWH fails
PAPI->>Notifications: Send failure alert
PAPI->>PAPI: Push to dead-letter queue
end
else Sequencescape fails
PAPI->>Notifications: Send failure alert
PAPI->>PAPI: Push to dead-letter queue
end
External Dependencies¶
- Sequencescape – the system of record for study data, called by SAPI over HTTPS.
- Shared API Gateway + custom Lambda authorizer – owned by another Integration Hub component; provides the only application-level authentication in the whole chain.
ipaas-framework– the internal Integration Hub framework all three Lambdas are built on.- AWS Secrets Manager – holds the Sequencescape client-ID and CA certificate used by SAPI.
- AWS SSM Parameter Store – resolves shared infra values (VPC networking, authorizer ID, Lambda layer ARN) at deploy time.