Async Python client for the Austrian eHealth Codierservice API (FHIR R5 ConceptMap).
Project description
ehcsapi
Async Python client for the eHealth Codierservice API (Austrian eHealth, FHIR R5 ConceptMap).
The service maps free-text diagnoses to coded concepts (SNOMED CT, ICD-10, Orphanet). The typical flow is:
- create a search episode once,
- call
find_diagnoses(...)repeatedly while the user types (type-ahead), - call
get_codes(...)for the selected diagnosis to obtain the SNOMED/ICD-10 codes, - drop the episode.
The client is async-only (built on httpx.AsyncClient) so it fits naturally into a Django ASGI
type-ahead view, where in-flight requests can be cancelled as the user keeps typing.
Installation
uv add ehcsapi # or: pip install ehcsapi
Requires Python ≥ 3.11. Depends on httpx and cryptography.
Authentication (mutual TLS)
The service requires a client certificate. The operator recommends loading the certificate once at
startup and keeping it in memory for the lifetime of the process. This client supports exactly that —
pass a pre-built ssl.SSLContext, or in-memory certificate bytes, or a file path:
import ehcsapi
# Recommended: build the context once at startup (e.g. from your central cert service) and reuse it.
ctx = ehcsapi.build_ssl_context(cert_bytes, password="…") # bytes (PEM or PKCS#12) or a path
client = ehcsapi.AsyncClient("com.example.myapp", ssl_context=ctx)
# Or let the client build it from a path / bytes:
client = ehcsapi.AsyncClient("com.example.myapp", cert="/path/to/client.p12", cert_password="…")
The base URL defaults to production (ehcsapi.PRODUCTION_BASE_URL). For the test system use
ehcsapi.TEST_BASE_URL (https://csapi-t.ehealth.gv.at):
client = ehcsapi.AsyncClient("com.example.myapp", base_url=ehcsapi.TEST_BASE_URL, cert=cert)
Usage
Type-ahead (one episode, many keystrokes)
async with ehcsapi.AsyncClient("com.example.myapp", ssl_context=ctx) as cs:
async with cs.search_episode() as episode: # POST on enter, DELETE on exit
hits = await episode.find_diagnoses("influ") # -> list[Diagnosis]
codes = await episode.get_codes(hits[0]) # search terms reused from the Diagnosis
print(codes.icd10) # [Coding(code='J11.1', display='Grippe …')]
In a stateless Django view you usually create the episode once, keep its id in the session, and reconstruct a handle per request without a new POST:
episode = cs.episode(request.session["episode_id"]) # existing episode, no round-trip
hits = await episode.find_diagnoses(query)
One-shot lookup
async with ehcsapi.AsyncClient("com.example.myapp", ssl_context=ctx) as cs:
hits = await cs.find_diagnoses("influenza") # opens + drops an ad-hoc episode
API surface
| Method | Endpoint |
|---|---|
startup_probe() |
HEAD /startupprobe |
version() / dataset_version() / application_version() |
GET /version[...] |
create_episode() / create_episode_v2() / search_episode() |
POST .../searchepisode |
episode(id) |
resume an existing episode (no request) |
delete_episode(id) / delete_episode_v2(id) |
DELETE .../searchepisode/{id} |
SearchEpisode.find_diagnoses(...) |
GET .../conceptmap?_query=findDiagnoses |
SearchEpisode.get_codes(...) |
GET .../conceptmap?_query=getCodeByElementId |
emit_x(n) / emit_random(n) |
diagnostic GET /emit/... |
Errors raise a CodierserviceError subclass: BadRequestError (400), ForbiddenError (403),
SearchEpisodeExpiredError (410 — create a fresh episode), or TransportError for network failures.
Test run against the test system
A runnable smoke script and an opt-in live test hit csapi-t:
# one-off manual run
CSAPI_CLIENT_TLS_CERT_PATH=/path/to/client.p12 CSAPI_CLIENT_TLS_CERT_PASSWORD=… \
python examples/smoke.py influenza
# opt-in pytest
EHCSAPI_LIVE=1 CSAPI_CLIENT_TLS_CERT_PATH=/path/to/client.p12 CSAPI_CLIENT_TLS_CERT_PASSWORD=… \
uv run pytest -m live
The reference OpenAPI document is in docs/openapi.json.
Development
uv sync
uv run pytest # unit tests, no network
uv run ruff check
uv run mypy src
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ehcsapi-0.2.0.tar.gz.
File metadata
- Download URL: ehcsapi-0.2.0.tar.gz
- Upload date:
- Size: 53.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
09a0a01b201cdd62273ff66a02bd0ad9b5f935261db2edbbc83634eba1c4ed45
|
|
| MD5 |
51e9dbf35e6fdb51f730e60ed26a9a6f
|
|
| BLAKE2b-256 |
214b3efd28a2b26bf832ac33acd92c49bb86cc2dfc499d5337706174f93ea37f
|
File details
Details for the file ehcsapi-0.2.0-py3-none-any.whl.
File metadata
- Download URL: ehcsapi-0.2.0-py3-none-any.whl
- Upload date:
- Size: 13.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b4ba01c9aaa1ab54d49f7eee665959660a772088bae5727c2bb94d2281ba9901
|
|
| MD5 |
091cd9f756f28a020a60843d55a7d48f
|
|
| BLAKE2b-256 |
219778c11b649186a8dc34467ef5e6cce6fc1e10f93d7571b1ed93f046110f63
|