-
Notifications
You must be signed in to change notification settings - Fork 2
fhirpy client example #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
6d2627e
9c346f4
f0d1e7f
83d499b
4fa5e67
033a514
481ec9c
a9fd2f6
77fa166
8c3bf7e
087115b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
AIDBOX_LICENSE= | ||
|
||
AIDBOX_DEV_MODE=true | ||
AIDBOX_FHIR_VERSION=4.0.1 | ||
AIDBOX_FHIR_SCHEMA_VALIDATION=true | ||
AIDBOX_FHIR_PACKAGES=hl7.fhir.r4.core#4.0.1 | ||
|
||
AIDBOX_CLIENT_SECRET=secret | ||
AIDBOX_CLIENT_ID=root | ||
AIDBOX_ADMIN_PASSWORD=password | ||
|
||
BOX_AUTH_KEYS_SECRET=auth-key-secret | ||
BOX_AUTH_KEYS_PRIVATE="-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEApbUYGNmCz1P8G0j/FFOjx1d5GNssJ/jj6xasSwTIbjjt6FtY\nCDw8o7hayOc/u8aUqXCGhK3JD2T9gtKv9/rV30w4YzmHhA8OOuLJE7tfh/PJA4Hn\n4i2JJ30BuoZ7rPTlTRGdc1FS3XFdmBQtnplEkJ7y8qbdrVme3Kbtn+BR1BdtgwSy\nbpNH2yqh3bb6PwpgNSMH7BIkBWL4A6QDpaFf1/9jSNE1vO25ssLC+bhFQNWLYriu\n+HogzEf9NWIrR2W29mI1QiA7wqvEuhg1yx38ylWD8GhCGL6+2QLKBYgp7DIGv6Uo\nTnqcVISatdQ51lVcCPmU6L1BhmcXVti6dWBI+wIDAQABAoIBAFKMOcJbTKpKvLq8\n7PErz1lFDpreyArrlmKsy0ydx9j8vCt1oY+MrmqisnsFk/7PaIxV9XUP+6qTFSUA\nHtAKYVOZLTfk10jmlSCpjCCrxWW9AISiSKkoJPyKbfuE9gRNhRMU9NoXB5Av4r+Z\nQbaRxJHE1OMjVCgAjr592786qJjd+shhY8ZLchrxctpBj6/4T2Rd4Q8ltyEV3hiy\noYaFVp9g332bFw7jZSuxgedZojNO6xPvbparTAgVDDwKB+CVUhuZ5EXWwemRvwoc\nYZM1UKPgtCqBZwm2GRv7s6XzJKBAZEMxcL7hS0RfijCe4MJcZlUCoM43Tf5XqDlT\nMmoXnPECgYEA4dkY/uqDLjJep5+4imRbceotxV2CZoJRQ0D85Ewu3tm9zdXhqL4p\n3XAOcNnqj7xBP3qkb/cXZumwdAIZns4kO1kw5hVQLX+xwMAJuravxp8sYJkx3CLO\noaOPNnlhGRv35fg4ZnoHHMO2C0wUmtSqsi6vE1EObYsIIFil58pI0NECgYEAu9SL\ne6AUCI/sdDlrTXQ8fdW8XSSJYPhZHqAvOAZfkeG4uuA2Qzxe8yUSES7z5V29futl\nWU7x+FWfqzkjh8qerviydAEFxVOpZ99ih9VB9dAwz3nX3OCoz3EUFmQGtTMxQmbo\nfW9sT4E6R7Hpa5jKnYvixk6u4p3aoEaZI4KeUAsCgYEA2OC3hiQBcN1h1Com9o7E\n2bF93qebT4EZNDI2J62Y3NvPztfy6S4j2cd/tpMtEnY/WgwV2Ic5a9RBZEWYAM4I\nMQ3HTUtuQSL8uRIwxaIlTeEQpnq2TKUINGRyZGdO/OPEvIwO7SmFpvOx30tiBgTv\nHkiCS1RtPHhkh1tZhirUneECgYAxNmARVQDKuYLXdM/jbEgJJD4FHXSNHqSi/I9C\nm5DgtQZkmCg/d4rdI+JW9Dlc6DGlFmHog2GskiqSfxcLFhB7gZeoAziS2fexynqT\nYlG06QZQ5fij24z/RP5hW3XSdgY7AqF5c/8p2Y7+h+PDmDXGD4esM6NoprlIcxbe\nkfOOvwKBgQCoOpkW+OWnxPLawmG/gv8+s5CsfOPUpURwAjltSXz9LXvsJmWQPQVG\np4sKEOJidYyt24YrIHi9/UEqRi+uuRQ4zCuXS6UjXftjAarPIPGkL/1S6B1Z91zg\nE5C0rXOvAlrvK09p4HGXLrwQxjrWt8R7rPvaD2yqVKLP4liFj8RMdg==\n-----END RSA PRIVATE KEY-----\n" | ||
BOX_AUTH_KEYS_PUBLIC="-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApbUYGNmCz1P8G0j/FFOj\nx1d5GNssJ/jj6xasSwTIbjjt6FtYCDw8o7hayOc/u8aUqXCGhK3JD2T9gtKv9/rV\n30w4YzmHhA8OOuLJE7tfh/PJA4Hn4i2JJ30BuoZ7rPTlTRGdc1FS3XFdmBQtnplE\nkJ7y8qbdrVme3Kbtn+BR1BdtgwSybpNH2yqh3bb6PwpgNSMH7BIkBWL4A6QDpaFf\n1/9jSNE1vO25ssLC+bhFQNWLYriu+HogzEf9NWIrR2W29mI1QiA7wqvEuhg1yx38\nylWD8GhCGL6+2QLKBYgp7DIGv6UoTnqcVISatdQ51lVcCPmU6L1BhmcXVti6dWBI\n+wIDAQAB\n-----END PUBLIC KEY-----\n" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.env | ||
tmp/ | ||
.ruff_cache | ||
*.pyc |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
.PHONY: format-fix lint | ||
|
||
all: format-fix lint | ||
|
||
format-fix: | ||
ruff format | ||
|
||
lint: | ||
ruff check | ||
|
||
mypy: | ||
mypy --strict *.py | ||
|
||
pyright: | ||
pyright *.py | ||
|
||
type-check: mypy pyright |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
# Python SDK Example | ||
|
||
|
||
This example shows how to use the [fhir-py client](https://github.com/beda-software/fhir-py "fhir-py") with an Aidbox instance, demonstrating the Python SDK client in action. | ||
|
||
In the example we demonstrate a several ways to implement import patient data from CSV file in Python. We describe it in the following steps: | ||
|
||
1. Setup Aidbox Instance | ||
1. Install [fhir-py](https://github.com/beda-software/fhir-py). | ||
1. Use [fhir-py](https://github.com/beda-software/fhir-py): | ||
1. with raw data (dictionaries and lists), | ||
1. with manually defined dataclasses for FHIR Resources, | ||
1. with generated dataclasses for FHIR Resources by [fhir-py-types](https://github.com/beda-software/fhir-py-types) from StructureDefinitions | ||
1. (recommended) with generated dataclasses for FHIR Resources by [fhir-schema-codegen](https://github.com/fhir-schema/fhir-schema-codegen) from FHIR Schemas. | ||
|
||
|
||
|
||
## Setting up Aidbox Instance | ||
|
||
Let's run an Aidbox instance on your computer. | ||
|
||
``` shell | ||
cp .env.tpt .env | ||
# manually add license to .env | ||
docker compose up | ||
``` | ||
|
||
|
||
|
||
## Using fhir-py Client with Raw Data | ||
|
||
#### Installation | ||
|
||
Create new python project and add fhir-py client to your dependencies | ||
|
||
``` shell | ||
poetry add fhirpy@2.0.15 | ||
``` | ||
|
||
*Note that this example uses `SyncFHIRClient`. However, you can also use `AsyncFHIRClient``. For more details, refer to the [fhir-py's documentation](https://github.com/beda-software/fhir-py/README.md)* | ||
|
||
#### Example | ||
|
||
This is a basic example demonstrating the creation of a new patient. Refer to the example files in each section for more detailed examples. | ||
|
||
``` python | ||
from fhirpy import SyncFHIRClient | ||
|
||
# create FHIR client instance | ||
client = SyncFHIRClient( | ||
url="http://localhost:8888/", | ||
authorization="Basic cm9vdDpzZWNyZXQ=" | ||
) | ||
|
||
# create patient resource | ||
patient = client.resource( | ||
"Patient", | ||
name=[ | ||
{ | ||
"given": ["Sam"], | ||
"family": "Brown", | ||
} | ||
], | ||
gender="male", | ||
) | ||
|
||
# save patient resource | ||
patient.save() | ||
``` | ||
|
||
See full CSV import example: [fhirpy_raw_data.py](fhirpy_raw_data.py) | ||
|
||
|
||
|
||
## Option 1. Write Custom Data Models for fhir-py Client | ||
|
||
Fhir-py client allows you to write and use [custom data models](https://github.com/beda-software/fhir-py?tab=readme-ov-file#data-models). The following example demonstrates how custom data models can be defined and used in your project. | ||
|
||
This option is offered primarily for educational purposes, to showcase possibilities and improve general understanding. However, we discourage using this method for manually defining data models, as it is both error-prone and cumbersome. | ||
|
||
#### Requirements | ||
|
||
Data model classes need to meet two requirements: | ||
|
||
- Be iterable (implemented by inheritance from `dict`). | ||
- Implement `ResourceProtocol` interface (defined in fhir-py). | ||
|
||
Usage dataclasses for FHIR Resource representation allow programmers to use autocomplete and type checking. This approach allows user to have full control (including custom validations and hiding unused resource elements) but requires to write a lot of boilerplate code. | ||
|
||
#### Example | ||
|
||
|
||
``` python | ||
from dataclasses import dataclass, field, asdict | ||
from typing import Optional | ||
|
||
from fhirpy import SyncFHIRClient | ||
from fhirpy.base.resource_protocol import ResourceProtocol | ||
|
||
# create FHIR client instance | ||
client = SyncFHIRClient( | ||
url="http://localhost:8888/", | ||
authorization="Basic cm9vdDpzZWNyZXQ=" | ||
dump_resource=asdict | ||
) | ||
|
||
@dataclass | ||
class Base(ResourceProtocol, dict): | ||
id: Optional[str] = None | ||
meta: Optional[Meta] = None | ||
|
||
@dataclass | ||
class Patient(Base): | ||
resourceType: str = "Patient" | ||
active: Optional[bool] = None | ||
gender: Optional[str] = None | ||
|
||
# create patient resource | ||
patient = Patient(active=True, gender="unknown") | ||
|
||
# save patient resource | ||
client.save(patient) | ||
``` | ||
|
||
See full CSV import example: [fhirpy_custom_models.py](fhirpy_custom_models.py) | ||
|
||
|
||
|
||
## Option 2. Using fhir-py-types | ||
|
||
In this example, we demonstrate how to use data models generated by [fhir-py-types generator](https://github.com/beda-software/fhir-py-types "fhir-py-types"), which simplifies working with data models by providing ready-to-use, pre-defined structures aligned with FHIR specifications. | ||
|
||
The simplest option to get pre-defined data models is install ready-to-use `fhirpy-types-r4b` or `fhirpy-types-r5` data model sets from PyPi. | ||
|
||
#### Installation | ||
|
||
``` shell | ||
poetry add fhirpy-types-r4b@0.1.1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And we need to explain how to generate dataclasses. Ideally, it will be nice to have similar structure for that and next section. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I got it right you mean generating data models with |
||
``` | ||
|
||
#### Example | ||
|
||
``` python | ||
from pydantic import BaseModel | ||
from fhirpy import SyncFHIRClient | ||
from fhirpy_types_r4b import HumanName, Patient | ||
|
||
# create FHIR client instance | ||
client = SyncFHIRClient( | ||
url="http://localhost:8888/", | ||
authorization="Basic cm9vdDpzZWNyZXQ=", | ||
dump_resource=BaseModel.model_dump | ||
) | ||
|
||
# create patient resource | ||
patient = Patient( | ||
name=[ | ||
HumanName( | ||
given=["Sam"], | ||
family="Brown") | ||
], | ||
gender="unknown" | ||
) | ||
|
||
# save patient resource | ||
client.save(patient) | ||
``` | ||
|
||
See CSV import example: [fhirpy_fhirtypes.py](fhirpy_fhirtypes.py) | ||
|
||
## Option 3. Using Types Generated by fhir-schema-codegen | ||
|
||
Another option for obtaining ready-to-use data models aligned with FHIR specification is to use data models generated by [fhir-schema-codegen](https://github.com/fhir-schema/fhir-schema-codegen). | ||
|
||
At the first step you'll need to install generator | ||
|
||
```shell | ||
# install fhir-schema-codegen | ||
npm install -g @fhirschema/codegen | ||
``` | ||
|
||
Then use it for generating python classes. | ||
|
||
```sh | ||
# generate FHIR data models | ||
fscg generate --generator python --output generated --package hl7.fhir.r4.core:4.0.1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we also generate classes for our custom resources? E.g. AidboxSubscriptionTopic? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean extending example with custom resources to highlight the advantages of the The same applies to other features: I propose enhancing this example gradually, in line with the evolution of |
||
``` | ||
|
||
After running the generation command, you'll see a new `generated` directory that contains the data models. | ||
|
||
#### Example | ||
|
||
|
||
``` python | ||
from typing import List, Optional | ||
|
||
from pydantic import BaseModel | ||
from fhirpy import SyncFHIRClient | ||
|
||
from utils import read_csv_as_dict, now | ||
from generated.patient import Patient, HumanName | ||
|
||
# create FHIR client instance | ||
client = SyncFHIRClient( | ||
url="http://localhost:8888/", | ||
authorization="Basic cm9vdDpzZWNyZXQ=", | ||
dump_resource=BaseModel.model_dump | ||
) | ||
|
||
# create patient resource | ||
patient = Patient( | ||
name=[ | ||
HumanName( | ||
given=["Sam"], | ||
family="Brown" | ||
) | ||
], | ||
gender="unknown" | ||
) | ||
|
||
# save patient resource | ||
client.create(patient) | ||
``` | ||
|
||
See full CSV import example: [fhirpy_fhir_schema_codegen.py](fhirpy_fhir_schema_codegen.py) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
given,family,gender,weight | ||
John,Doe,male,83 | ||
Alice,Doe,female,63 | ||
Charly,Doe,male,22 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
volumes: | ||
subs-pgdata: | ||
name: subs-pgdata | ||
subs-kafka-data: | ||
name: subs-kafka-data | ||
services: | ||
|
||
aidbox-db: | ||
image: healthsamurai/aidboxdb:16.1 | ||
pull_policy: always | ||
ports: | ||
- "5438:5432" | ||
volumes: | ||
- "subs-pgdata:/data:delegated" | ||
environment: | ||
POSTGRES_USER: postgres | ||
POSTGRES_PASSWORD: postgres | ||
POSTGRES_DB: aidbox | ||
|
||
aidbox: | ||
image: healthsamurai/aidboxone:edge | ||
pull_policy: always | ||
depends_on: ["aidbox-db"] | ||
volumes: | ||
- "./tmp:/tmp" | ||
ports: | ||
- "8888:8888" | ||
environment: | ||
PGPORT: 5432 | ||
PGHOST: aidbox-db | ||
PGHOSTPORT: 5438 | ||
PGUSER: postgres | ||
PGPASSWORD: postgres | ||
PGDATABASE: aidbox | ||
AIDBOX_BASE_URL: http://localhost:8888 | ||
AIDBOX_PORT: 8888 | ||
env_file: | ||
- .env | ||
healthcheck: | ||
test: ["CMD", "curl", "-f", "http://localhost:8888/health"] | ||
interval: 30s | ||
timeout: 10s | ||
retries: 5 | ||
start_period: 30s |
Uh oh!
There was an error while loading. Please reload this page.