Released docs. You are viewing the documentation published with v0.46.0. Development docs are available at Latest.
If you integrate an institution’s existing HTTP API with Registry Evidence, you connect one of its
operations here and return a verified answer from it. You start a new project, so you are no
longer in the standalone project from your first assertion; if that one is still
running, run rstack evidence dev stop . in its directory first, because both use the same ports.
What Evidence needs from your API
Section titled “What Evidence needs from your API”Settle three things about the operation you connect:
- A fixed request shape. One method and one path template. Selector values fill the path parameters; the caller never chooses the operation, query, or headers.
- Authentication configuration and, when needed, a secret reference. The reviewed pack endpoint
declares the authentication type and the target names the same type plus any reference;
check --targetrefuses the two when they differ. A configured secret provider supplies the credential bytes, and the caller’s own token never reaches your API. - The fields the integration may retain. Review exactly which response fields can be retained; nothing else in the response may reach the assertion logic.
Without a real API at hand, you connect a FHIR R4 Coverage read on a synthetic public server.
Each step applies to your own API.
For an existing DHIS2 Tracker or OpenCRVS integration, download the source recipe catalog. It includes reviewed exports and synthetic fixture projects. Follow its README to validate the recipe with matching binaries, then import it through the existing source lifecycle. Its contract notes identify the provider shapes you need to check against your deployment.
Get the project and prove it offline
Section titled “Get the project and prove it offline”Download the Evidence example projects into a fresh
working directory as evidence-examples.tar.gz, then unpack the FHIR project into a directory of
its own, because the next commands write keys and responses into it:
The download uses the Adapter-pack authoring format, which v0.45.0 is the first release to read. Do not pair it with binaries from an older release.
mkdir connect-an-institution-apitar -xzf evidence-examples.tar.gz -C connect-an-institution-api fhirmv connect-an-institution-api/fhir connect-an-institution-api/fhir-record-evidencecd connect-an-institution-api/fhir-record-evidenceCheck it and run its fixtures, which need no network:
rstack evidence check . --target local-target.yamlrstack evidence test . --target local-target.yaml --deny-warningsEvidence project check: completeProject: .Target: local-target.yamlDeployment inputs missing: signer.publicJwkFile; the compiled-target bundle check was skipped. Supply them and rerun check to prove the target.0 errors, 0 warnings in 1 filePASS: checkPASS: fixtures/coverage-status.yaml (8 cases)PASS: fixtures/healthcare-establishment.yaml (11 cases)3 passed, 0 failed (19 cases evaluated)Proof: offline synthetic fixture evaluation; no live dependency readiness was checkedYou request fhir-coverage-status, one of its two assertion definitions. check runs before any
signing key exists, so it reports the missing public key and skips the compiled-target check. test
then wrote disposable, owner-only keys under .generated/secrets; keep that directory out of
version control.
Inspect the acquisition and derivation that the checked project will use:
rstack evidence explain . --target local-target.yamlDefinition fhir-coverage-status: urn:example:requirement:coverage-record:v1 Acquisition: Source coverage-record Source coverage-record: pack fhir-read-through@1; route coverage-record; connection fhir-read-through Posture: record-transformed Inputs: coverageId <- selector coverage-record@coverage-by-id.coverage_id Facts: beneficiary-reference (string), status (string) Derive: Function derive-coverage-status Outputs: coverage-record-reports-activeThe Source is the project’s thin acquisition binding. It selects one route from the reviewed
fhir-read-through@1 pack, supplies coverageId from the fixed selector profile, and names the
target-owned connection. The route returns only the two private Facts shown before the derivation
Function produces the Boolean Output.
Read the operation from its OpenAPI description
Section titled “Read the operation from its OpenAPI description”source.openapi.yaml describes the API. Print a source draft for one operation, selecting the
two fields the answer needs (--list-pointers instead lists every field it returns):
rstack evidence source suggest --openapi source.openapi.yaml \ --operation 'GET /Coverage/{coverage_id}' --source-id coverage-record \ --select /status --select /beneficiary/referenceevidencectl source suggest: draft for source `coverage-record` (GET /Coverage/{coverage_id})
Derived automatically: none.
Still needs your input (the source block below): - Set the source origin. - Review the generated Source posture and default source limits. - Configure target-owned authentication. - Complete selector bindings and the pack request mapping.This print-only draft includes a candidate pack and Source block. It is incomplete until you review the pack, bind every request input, and resolve its draft markers. For another operation, explicit selector mappings generate fixed pack request bindings from profiles already in your project.
The downloaded project uses the reviewed fhir-read-through@1 pack instead of the generated
candidate. Its Source remains a small binding in evidence.yaml:
coverage-record: pack: id: fhir-read-through version: '1' route: coverage-record connection: fhir-read-through acquisitionPosture: record-transformed inputs: coverageId: selector: role: coverage-record profile: coverage-by-id field: coverage_idThe selected pack route owns the inputs and Facts schemas for acquisition:
{ "id": "coverage-record", "evidence": { "inputsSchema": { "path": "schemas/inputs-coverage.json", "digest": "sha256:a70e6414a6baedd4404c53015ce035caa3e3a2528700a259727be4632296f03d" }, "factsSchema": { "path": "schemas/facts-coverage.json", "digest": "sha256:7c93c17ec873a96e80a31fb096260add3abbb64e0b2a3ad9352cde10b4c9775a" }, "acquisitionPosture": "record-transformed" }}The route fixes the request method, path, and path-parameter source:
{ "to": { "uri": "http:fhir", "parameters": { "httpMethod": "GET", "path": "/Coverage/{{coverage-id}}", "pathParameters": { "coverage-id": { "exchangeProperty": "coverage-id" } }, "operation": "coverage-read" } }}Its reviewed script projects resourceType, id, status, and beneficiary.reference. A separate
validateSchema step enforces provider-coverage.json against that projection. The following
lookup step checks the returned record’s identity and returns only status and
beneficiary-reference as private Facts. The posture
record-transformed records that the API returns a broader record than the answer needs, so the
integration claims disclosure minimization only.
The endpoint details live in local-target.yaml, under the connection the Source names:
connections: fhir-read-through: endpoints: fhir: origin: http://127.0.0.1:8000 authentication: type: none attemptTimeoutMilliseconds: 30000 maximumResponseBytes: 65536The local read-through helper needs no credential, and the pack endpoint declares the same
authentication type, none. For an API that expects a fixed Authorization value, change both files
to the same type:
- In
adapter-packs/fhir-read-through/pack.yaml, set the endpoint’sauthenticationto{"type": "static-authorization"}. - In
local-target.yaml, settype: static-authorizationand add atokenRefto a secret reference, as your first assertion’s target does.
If you change only one of them, rstack evidence check . --target local-target.yaml refuses the
pair with evidence.source.authentication-mismatch, which names both types. The configured secret
provider supplies the credential bytes. For your own description,
rstack evidence init <dir> --openapi <doc> --profile local writes a project and
rstack evidence source suggest <dir> writes a pack draft into it.
Serve the API locally
Section titled “Serve the API locally”FHIR servers answer with application/fhir+json; the pack route accepts application/json from
the local read-through helper. That helper is project code and not part of Evidence. It re-serves
each allowed resource from the synthetic server. In a second terminal, start it and leave it
running:
python3 serve-source.pySend it no real identifiers. Back in the first terminal, pick one synthetic coverage record and its patient; the script writes owner-only subject files in the parent directory:
cd ..python3 fhir-record-evidence/discover-records.pycd fhir-record-evidenceCoverage selector file: readyOrganization selector file: readyStart Registry Evidence and request one assertion
Section titled “Start Registry Evidence and request one assertion”Register the client you will request as:
rstack evidence access client add fhir-client --access-profile fhir-service --generate-local-keyAdded client fhir-client with access profile fhir-service.Start the gateway and its local token issuer; they run until you stop them:
rstack evidence dev start . --target local-target.yaml --evidence-port 18080 --issuer-port 8082Evidence ready at http://127.0.0.1:18080Issuer ready at http://127.0.0.1:8082Prepare the request from the subject file:
rstack evidence request prepare fhir-coverage-status \ --client fhir-client \ --purpose coverage-record-verification \ --subjects-file ../fhir-coverage-subjects.json \ --name fhir-coveragePrepared request: .evidence/requests/fhir-coverage/request.jsonPrepared verification context: .evidence/requests/fhir-coverage/verification.jsonPrepared authorization: .evidence/requests/fhir-coverage/authorization.curlSend it and verify the signed response offline:
rstack evidence api /v1/evidence \ --client fhir-client \ --input .evidence/requests/fhir-coverage/request.json \ --accept application/jose+json \ --output fhir-coverage.jws.jsonrstack evidence verify fhir-coverage.jws.json \ --context .evidence/requests/fhir-coverage/verification.json \ --output fhir-coverage.verified.jsonVERIFIEDjq '.supportedValues' fhir-coverage.verified.json[ { "providesValueFor": "urn:example:concept:coverage-record-reports-active:v1", "value": true }]The assertion carries one Boolean, whether the coverage is active, and none of the coverage record.
Stop, read the audit, and clean up
Section titled “Stop, read the audit, and clean up”The audit view reads only a stopped session, so stop the gateway first:
rstack evidence dev stop .rstack evidence audit show --last-operationACCESS AUTHORIZED fhir-coverage-status coverage-record-verification requester=<pseudonym>DISCLOSURE RELEASED coverage-record-reports-activeCleaning removes the stopped session’s directory, .evidence/dev, and the audit with it, so read
the audit first. The project, its registered client, and the prepared request stay:
rstack evidence dev clean .Removed stopped local Evidence statePress Ctrl+C in the read-through helper’s terminal, then remove the subject files:
cd ..rm -f fhir-coverage-subjects.json fhir-organization-subjects.jsonCookies on Registry Stack
We use optional cookies to understand how you use the main Registry Stack website and this documentation. If you contact us, we may link this activity to your enquiry. You can change your choice at any time. Read the privacy policy.
Your browser asks sites not to track you, so optional tracking stays off.
We could not use or save that choice. Optional tracking remains off.