FHIR connections
Give every service secure access to any FHIR server as self.fhir - credentials, pooling and guaranteed delivery included.
Python services reach FHIR servers through outgoing connections. You create a connection once in the Dashboard and every service can use it as self.fhir - the client it returns attaches the credentials, pools the network connections and turns search results into Python objects.
Create a connection
To create a connection, go to Connections > Outgoing > HL7 > FHIR in the Dashboard, click Create a new connection and fill in the form:
- Name: FHIR.Sample
- Address: your FHIR server's address, e.g.
https://fhir.example.com - Security: No security definition - servers that require credentials are covered in FHIR security
- Click OK
The connection is ready the moment you click OK - configuration changes propagate to all servers automatically, with no restarts.
You can also set Pool size in the same form - how many network connections Zato keeps open to the server, 10 by default. Requests above that number wait for a connection to free up rather than opening new ones.
Use the connection in a service
The self.fhir dictionary returns a client for the connection whose name you pass. The service below looks up active patients on the server, sorted by their birth date:
# -*- coding: utf-8 -*-
# Zato
from zato.server.service import Service
class GetActivePatients(Service):
""" Looks up active patients on a FHIR server, sorted by birth date.
"""
name = 'demo.fhir.get-active-patients'
def handle(self) -> 'None':
# A client connected to the server behind FHIR.Sample ..
client = self.fhir['FHIR.Sample']
# .. everything about patients starts here ..
patients = client.resources('Patient')
# .. all of the active ones, sorted by their birth date ..
result = patients.search(active=True).sort('-birthdate')
# .. and each match goes to the server log.
for patient in result:
self.logger.info('Received %s', patient['name'])
Invoking the service writes the received data to the server log:
To learn what else the client offers, see resources for creating, reading and updating data, and searches and bundles for queries and pagination.
Queue documents for guaranteed delivery
A call to .save sends the resource to the server immediately - if the server is down or slow, the call raises an error the service must handle. When the document only needs to reach the server eventually, and the service does not need the answer, publish it instead:
# -*- coding: utf-8 -*-
# Zato
from zato.server.service import Service
class PublishPatient(Service):
""" Queues a patient document for guaranteed delivery to a FHIR server.
"""
name = 'demo.fhir.publish-patient'
def handle(self) -> 'None':
# The document to store, its resourceType saying what it is ..
patient = {
'resourceType': 'Patient',
'name': [{'family': 'Chalmers', 'given': ['Peter', 'James']}],
}
# .. a client connected to the server behind FHIR.Sample ..
client = self.fhir['FHIR.Sample']
# .. and the publish call, returning as soon as the document is queued.
result = client.publish(patient)
self.logger.info('Queued as %s', result.msg_id)
The call returns in a few milliseconds and does not touch the network. Zato delivers the document in the background, retrying with a growing interval - from 3 seconds up to 10 seconds between attempts - for up to 30 days. The queue is stored in a database, so delivery resumes after a restart, and a document leaves the queue only once the server confirms that it stored it.
Each connection has a queue of its own and documents are delivered in the order they were published. Delivery uses the connection's own address, credentials and pool, the same ones a .save uses, and the document is created under the path its resourceType names - a Patient published to a connection addressed https://fhir.example.com/r4 is posted to https://fhir.example.com/r4/Patient.
A document without a resourceType is rejected at publish time, because no delivery path can be derived for it.
After you rename a connection, the documents queued under the old name are delivered under the new one, without duplicates. Deleting a connection deletes its queue - the remaining documents are dropped and their count is written to the server log.
Secure the connection
A server that requires credentials takes a Basic Auth or OAuth definition in the connection's Security field - Zato attaches the credentials to every request, and OAuth tokens are acquired and refreshed automatically. Servers behind TLS with non-public certificates take a CA bundle uploaded through the Dashboard. To set up each of these, see FHIR security.
Define connections in YAML
Instead of filling out the Dashboard form, you can declare connections in YAML and import them with enmasse, which is what automated deployments and version-controlled configuration use:
outgoing_fhir:
- name: FHIR.Sample
address: https://fhir.example.com/r4
- name: FHIR.Secured
address: https://fhir.partner.example.com/r4
security: my.basic_auth.1
pool_size: 20
Every field is listed in the enmasse reference.
See also
| Feature | What it does |
|---|---|
| Resources | Create, read, update and delete any FHIR resource |
| Searches and bundles | Search parameters, result bundles and pagination |
| Security | Basic Auth, OAuth and TLS for FHIR servers |
| AI agents | Expose FHIR-backed services to AI agents as MCP tools |
| FHIR tutorial | A connection, services and searches built end to end |
Learn more
Schedule a meaningful demo
Book a demo with an expert who will help you build meaningful systems that match your ambitions
"We evaluated 12 integration platforms and Zato was the only one to score 100%."
Philip Zuñiga, Assistant Professor, University of the Philippines