{"id":13446047,"url":"https://github.com/beda-software/fhir-py","last_synced_at":"2025-04-14T20:53:58.097Z","repository":{"id":33435535,"uuid":"138890668","full_name":"beda-software/fhir-py","owner":"beda-software","description":"FHIR Client for python","archived":false,"fork":false,"pushed_at":"2024-11-23T18:49:15.000Z","size":1356,"stargazers_count":186,"open_issues_count":33,"forks_count":34,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-07T18:06:27.023Z","etag":null,"topics":["client","fhir","rest"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/beda-software.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-06-27T14:10:40.000Z","updated_at":"2025-04-06T12:49:14.000Z","dependencies_parsed_at":"2023-01-15T00:54:32.725Z","dependency_job_id":"a416b1c6-8b48-469d-8018-8b9437de3226","html_url":"https://github.com/beda-software/fhir-py","commit_stats":{"total_commits":267,"total_committers":17,"mean_commits":"15.705882352941176","dds":0.6853932584269663,"last_synced_commit":"310d426fcb431f7760f47ff3339e3101415587f2"},"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beda-software%2Ffhir-py","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beda-software%2Ffhir-py/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beda-software%2Ffhir-py/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beda-software%2Ffhir-py/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/beda-software","download_url":"https://codeload.github.com/beda-software/fhir-py/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248961083,"owners_count":21189990,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["client","fhir","rest"],"created_at":"2024-07-31T05:00:44.350Z","updated_at":"2025-04-14T20:53:58.074Z","avatar_url":"https://github.com/beda-software.png","language":"Python","funding_links":[],"categories":["Menu"],"sub_categories":["Libraries"],"readme":"[![build status](https://github.com/beda-software/fhir-py/actions/workflows/build.yaml/badge.svg)](https://github.com/beda-software/fhir-py/actions/workflows/build.yaml)\n[![codecov](https://codecov.io/gh/beda-software/fhir-py/branch/master/graph/badge.svg)](https://codecov.io/gh/beda-software/fhir-py)\n[![pypi](https://img.shields.io/pypi/v/fhirpy.svg)](https://pypi.org/project/fhirpy)\n[![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)\n[![Supported Python version](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/release/python-390/)\n\n# fhir-py\nasync/sync FHIR client for python3.\nThis package provides an API for CRUD operations over FHIR resources\n\n```pip install fhirpy```\n\nor to install the latest dev version:\n\n```pip install git+https://github.com/beda-software/fhir-py.git```\n\nYou can test this library by interactive FHIR course in the repository [Aidbox/jupyter-course](https://github.com/Aidbox/jupyter-course).\n\n\u003c!-- To regenerate table of contents: doctoc README.md --maxlevel=3 --\u003e\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n- [Getting started](#getting-started)\n  - [Async example](#async-example)\n  - [Searchset examples](#searchset-examples)\n    - [Chained parameters](#chained-parameters)\n    - [Reference](#reference)\n    - [Date](#date)\n    - [Modifiers](#modifiers)\n    - [Raw parameters](#raw-parameters)\n  - [Get resource by id](#get-resource-by-id)\n  - [Get exactly one resource](#get-exactly-one-resource)\n  - [Get first result](#get-first-result)\n  - [Get total count](#get-total-count)\n  - [Fetch one page](#fetch-one-page)\n  - [Fetch all resources on all pages](#fetch-all-resources-on-all-pages)\n  - [Page count (_count)](#page-count-_count)\n  - [Sort (_sort)](#sort-_sort)\n  - [Elements (_elements)](#elements-_elements)\n  - [Include](#include)\n    - [Modifier :iterate (or :recurse in some previous versions of FHIR)](#modifier-iterate-or-recurse-in-some-previous-versions-of-fhir)\n    - [Wild card (any search parameter of type=reference be included)](#wild-card-any-search-parameter-of-typereference-be-included)\n  - [Revinclude](#revinclude)\n    - [Wild card (any search parameter of type=reference be included)](#wild-card-any-search-parameter-of-typereference-be-included-1)\n  - [Conditional operations](#conditional-operations)\n    - [Conditional create](#conditional-create)\n    - [Conditional update](#conditional-update)\n    - [Conditional patch](#conditional-patch)\n    - [Conditional delete](#conditional-delete)\n- [Data models](#data-models)\n  - [Static typechecking](#static-typechecking)\n  - [Resource instantiation](#resource-instantiation)\n  - [CRUD client methods](#crud-client-methods)\n    - [Create](#create)\n    - [Update](#update)\n    - [Save](#save)\n    - [Patch](#patch)\n    - [Delete](#delete)\n    - [Read](#read)\n- [Resource and helper methods](#resource-and-helper-methods)\n  - [Validate resource using operation $validate](#validate-resource-using-operation-validate)\n  - [Accessing resource attributes](#accessing-resource-attributes)\n  - [get_by_path(path, default=None)](#get_by_pathpath-defaultnone)\n  - [set_by_path(obj, path, value)](#set_by_pathobj-path-value)\n  - [serialize()](#serialize)\n- [Reference](#reference-1)\n  - [Main class structure](#main-class-structure)\n  - [Async client (based on _aiohttp_) – AsyncFHIRClient](#async-client-based-on-_aiohttp_--asyncfhirclient)\n    - [Aiohttp request parameters](#aiohttp-request-parameters)\n    - [AsyncFHIRResource](#asyncfhirresource)\n    - [AsyncFHIRReference](#asyncfhirreference)\n    - [AsyncFHIRSearchSet](#asyncfhirsearchset)\n  - [Sync client (based on _requests_) – SyncFHIRClient](#sync-client-based-on-_requests_--syncfhirclient)\n    - [Requests request parameters](#requests-request-parameters)\n    - [SyncFHIRResource](#syncfhirresource)\n    - [SyncFHIRReference](#syncfhirreference)\n    - [SyncFHIRSearchSet](#syncfhirsearchset)\n- [Run integration tests](#run-integration-tests)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n# Getting started\n## Async example\n```Python\nimport asyncio\nfrom fhirpy import AsyncFHIRClient\n\n\nasync def main():\n    # Create an instance\n    client = AsyncFHIRClient(\n        'http://fhir-server/',\n        authorization='Bearer TOKEN',\n    )\n\n    # Search for patients\n    resources = client.resources('Patient')  # Return lazy search set\n    resources = resources.search(name='John').limit(10).sort('name')\n    patients = await resources.fetch()  # Returns list of AsyncFHIRResource\n\n    # Create Organization resource\n    organization = client.resource(\n        'Organization',\n        name='beda.software',\n        active=False\n    )\n    await organization.save()\n\n    # Update (PATCH) organization. Resource support accessing its elements\n    # both as attribute and as a dictionary keys\n    if organization['active'] is False:\n        organization.active = True\n    await organization.save(fields=['active'])\n    # `await organization.patch(active=True)` would do the same PATCH operation\n\n    # Get patient resource by reference and delete\n    patient_ref = client.reference('Patient', 'new_patient')\n    # Get resource from this reference\n    # (throw ResourceNotFound if no resource was found)\n    patient_res = await patient_ref.to_resource()\n    await patient_res.delete()\n\n    # Iterate over search set\n    org_resources = client.resources('Organization')\n    # Lazy loading resources page by page with page count = 100\n    async for org_resource in org_resources.limit(100):\n        print(org_resource.serialize())\n\n\nif __name__ == '__main__':\n    loop = asyncio.get_event_loop()\n    loop.run_until_complete(main())\n```\n\n## Searchset examples\n```Python\npatients = client.resources('Patient')\n\npatients.search(birthdate__gt='1944', birthdate__lt='1964')\n# /Patient?birthdate=gt1944\u0026birthdate=lt1964\n\npatients.search(name__contains='John')\n# /Patient?name:contains=John\n\npatients.search(name=['John', 'Rivera'])\n# /Patient?name=John\u0026name=Rivera\n\npatients.search(name='John,Eva')\n# /Patient?name=John,Eva\n\npatients.search(family__exact='Moore')\n# /Patient?family:exact=Moore\n\npatients.search(address_state='TX')\n# /Patient?address-state=TX\n\npatients.search(active=True, _id='id')\n# /Patient?active=true\u0026_id=id\n\npatients.search(gender__not=['male', 'female'])\n# /Patient?gender:not=male\u0026gender:not=female\n```\n\n### Chained parameters\n```Python\npatients.search(general_practitioner__Organization__name='Hospital')\n# /Patient?general-practitioner:Organization.name=Hospital\n```\n\n```Python\npatients.search(general_practitioner__name='Hospital')\n# /Patient?general-practitioner.name=Hospital\n```\n\n### Reference\n```Python\npractitioner = client.resources('Practitioner').search(_id='john-smith').first()\npatients.search(general_practitioner=practitioner)\n# /Patient?general-practitioner=Practitioner/john-smith\n```\n\n### Date\n```Python\nimport pytz\nimport datetime\n\n\npatients.search(birthdate__lt=datetime.datetime.now(pytz.utc))\n# /Patient?birthdate=lt2019-11-19T20:16:08Z\n\npatients.search(birthdate__gt=datetime.datetime(2013, 10, 27, tzinfo=pytz.utc))\n# /Patient?birthdate=gt2013-10-27T00:00:00Z\n```\n\n### Modifiers\n```Python\nconditions = client.resources('Condition')\n\nconditions.search(code__text='headache')\n# /Condition?code:text=headache\n\nconditions.search(code__in='http://acme.org/fhir/ValueSet/cardiac-conditions')\n# /Condition?code:in=http://acme.org/fhir/ValueSet/cardiac-conditions\n\nconditions.search(code__not_in='http://acme.org/fhir/ValueSet/cardiac-conditions')\n# /Condition?code:not-in=http://acme.org/fhir/ValueSet/cardiac-conditions\n\nconditions.search(code__below='126851005')\n# /Condition?code:below=126851005\n\nconditions.search(code__above='126851005')\n# /Condition?code:above=126851005\n```\n\n### Raw parameters\nSometimes you can find that fhir-py does not implement some search parameters from the FHIR specification. \nIn this case, you can use `Raw()` wrapper without any transformations\n\n```Python\nfrom fhirpy.base.searchset import Raw\n\npatients = client.resources('Patient')\npatients.search(Raw(**{'general-practitioner.name': 'Hospital'}))\n# /Patient?general-practitioner.name=Hospital\n```\n\n## Get resource by id\nUse reference to get resource by id\n```Python\npatient = await client.reference('Patient', '1').to_resource()\n# /Patient/1\n```\n\nOr use FHIR search API with `.first()` or `.get()` as described below.\n\n## Get exactly one resource\n```Python\npractitioners = client.resources('Practitioner')\n\ntry:\n    await practitioners.search(active=True, _id='id').get()\n    # /Practitioner?active=true\u0026_id=id\nexcept ResourceNotFound:\n    pass\nexcept MultipleResourcesFound:\n    pass\n```\n\n## Get first result\n```Python\nawait practitioners.search(name='Jack').first()\n# /Practitioner?name=Jack\u0026_count=1\n\nawait patients.sort('active', '-birthdate').first()\n# /Patient?_sort=active,-birthdate\u0026_count=1\n```\n\n## Get total count\n```Python\nawait practitioners.search(active=True).count()\n\nawait patients.count()\n```\n\n## Fetch one page\n```Python\nawait practitioners.fetch()\n# /Practitioner\n\nawait patients.elements('name', 'telecom').fetch()\n# /Patient?_elements=resourceType,name,id,telecom\n```\n\n## Fetch all resources on all pages\nKeep in mind that this method as well as .fetch() doesn't return any included resources. Use fetch_raw() if you want to get all included resources.\n```Python\n# Returns a list of `Practitioner` resources\nawait practitioners.search(address_city='Krasnoyarsk').fetch_all()\n\nawait patients.fetch_all()\n```\n\n## Page count (_count)\n```Python\n# Get 100 resources\nawait practitioners.limit(100).fetch()\n```\n\n## Sort (_sort)\n```Python\nobservations = client.resources('Observation')\n\nobservations.sort('status', '-date', 'category')\n# /Observation?_sort=status,-date,category\n```\n\n## Elements (_elements)\n```Python\n# Get only specified set of elements for each resource\npatients.elements('identifier', 'active', 'link')\n# /Patient?_elements=identifier,active,link\n\n# Get all elements except specified set\npractitioners.elements('address', 'telecom', exclude=True)\n```\n\n## Include\n```Python\nresult = await client.resources('EpisodeOfCare') \\\n    .include('EpisodeOfCare', 'patient').fetch_raw()\n# /EpisodeOfCare?_include=EpisodeOfCare:patient\nfor entry in result.entry:\n    print(entry.resource)\n\nawait client.resources('MedicationRequest') \\\n    .include('MedicationRequest', 'patient', target_resource_type='Patient') \\\n    .fetch_raw()\n# /MedicationRequest?_include=MedicationRequest:patient:Patient\n```\n### Modifier :iterate (or :recurse in some previous versions of FHIR)\n```Python\n# For FHIR version \u003e= 3.5 we can also use modifier :iterate\nawait client.resources('MedicationRequest') \\\n    .include('MedicationDispense', 'prescription') \\\n    .include('MedicationRequest', 'performer', iterate=True) \\\n    .fetch_raw()\n# /MedicationRequest?_include=MedicationDispense:prescription\n#    \u0026_include:iterate=MedicationRequest:performer\n\n# For FHIR version 3.0-3.3 use modifier :recurse\nawait client.resources('MedicationDispense') \\\n    .include('MedicationRequest', 'prescriber', recursive=True) \\\n    .fetch_raw()\n# /MedicationDispense?_include:recurse=MedicationRequest:prescriber\n```\n### Wild card (any search parameter of type=reference be included)\n```Python\nawait client.resources('Encounter').include('*') \\\n    .fetch_raw()\n# /Encounter?_include=*\n```\n\n## Revinclude\n```Python\nawait practitioners.revinclude('Group', 'member').fetch_raw()\n# /Practitioner?_revinclude=Group:member\n```\nor\n```Python\nawait practitioners.include('Group', 'member', reverse=True).fetch_raw()\n# /Practitioner?_revinclude=Group:member\n```\n\n### Wild card (any search parameter of type=reference be included)\n```Python\nawait client.resources('EpisodeOfCare').revinclude('*') \\\n    .fetch_raw()\n# /EpisodeOfCare?_revinclude=*\n```\n\n## Conditional operations\n### Conditional create\n[FHIR spec: Conditional create](https://build.fhir.org/http.html#ccreate)\u003cbr\u003e\n#### For resource\n```Python\n# resource.create(search_params)\n# executes POST /Patient?identifier=fhirpy\n\npatient = client.resource(\"Patient\",\n    identifier=[{\"system\": \"http://example.com/env\", \"value\": \"fhirpy\"}],\n    name=[{\"text\": \"Mr. Smith\"}],\n)\nawait patient.create(identifier=\"other\")\n```\n#### For SearchSet\n```Python\n# searchset.get_or_create(resource)\n# executes POST /Patient?identifier=fhirpy\n\npatient, created = await client.resources(\"Patient\").search(identifier=\"fhirpy\").get_or_create(patient_to_save)\n\n# no match -\u003e created is True\n# one match -\u003e created is False, return existing resource\n# multiple matches -\u003e 412 'MultipleResourcesFound'\n```\n### Conditional update\n[FHIR spec: Conditional update](https://build.fhir.org/http.html#cond-update)\u003cbr\u003e\n```Python\n# resource, created: bool = searchset.patch(resource)\n# executes PUT /Patient?identifier=fhirpy\n\npatient_to_update = client.resource(\"Patient\", \n                                    identifier=[{\"system\": \"http://example.com/env\", \"value\": \"fhirpy\"}],\n                                    active=False)\nnew_patient, created = await client.resources(\"Patient\").search(identifier=\"fhirpy\").update(patient_to_update)\n\n# no match -\u003e created is True\n# one match -\u003e created is False, the matched resource is overwritten\n# multiple matches -\u003e 412 'MultipleResourcesFound'\n```\n### Conditional patch\n[FHIR spec: Conditional patch](https://build.fhir.org/http.html#cond-patch)\u003cbr\u003e\n```Python\n# patched_resource = searchset.patch(resource)\n# executes PATCH /Patient?identifier=fhirpy\n\npatient_to_patch = client.resource(\"Patient\", \n                                    identifier=[{\"system\": \"http://example.com/env\", \"value\": \"fhirpy\"}], \n                                    name=[{\"text\": \"Mr. Smith\"}])\npatched_patient = await client.resources(\"Patient\").search(identifier=\"fhirpy\").patch(patient_to_patch)\n\n# no match -\u003e 404 'ResourceNotFound'\n# multiple matches -\u003e 412 'MultipleResourcesFound'\n```\n\n### Conditional delete\n[FHIR spec: Conditional delete](https://build.fhir.org/http.html#cdelete)\u003cbr\u003e\n```Python\nresponse_data, status_code = await self.client.resources(\"Patient\").search(identifier=\"abc\").delete()\n\n# no match -\u003e status_code = 204 'No Content'\n# one match -\u003e status_code = 200 'OK'\n# multiple matches -\u003e status_code = 412 'MultipleResourcesFound' (implementation specific)\n```\n\n# Data models\n\nThird party typing data models might be used along with fhir-py.\nThe typing data models should match [ResourceProtocol](https://github.com/beda-software/fhir-py/blob/master/fhirpy/base/resource_protocol.py#L5), e.g. have `resourceType` attribute, optional `id` and be iterable for serialization. \nThere's a third party repository [fhir-py-types](https://github.com/beda-software/fhir-py-types) that is written on top of pydantic models is fully compatible with fhir-py.\n\n## Static typechecking\n\nfhir-py uses typehints in the codebase and it statically checked by [mypy](https://github.com/python/mypy). Some interfaces that are described below designed in the way to properly infer the return type based on the model class or instance.\n\n## Resource instantiation\n\nTo instantiate a resource, simply use type model constructor, e.g.\n```python\npatient = Patient(name=[HumanName(text='Patient')])\n```\n\n## CRUD client methods\n\nClient class provides CRUD methods that designed to work with typed models.\n\n### Create\n\n```python\nawait client.create(patient) # returns Patient\n```\n\n### Update\n\n```python\nawait client.create(patient) # returns Patient\n```\n\n### Save\n\nSmart helper that creates or updated the resource based on having `id`\n\n```python\nawait client.save(patient) # returns Patient\n```\n\nAlso it supports overriding specific fields using patch:\n\n```python\nawait client.save(patient, fields=['identifier']) # returns Patient\n```\n\n### Patch\n\nPatch accepts different syntaxes for patching, there're two syntaxes for general usage, without inferred types:\n\n* Patch using reference defined by separate resource type and id:\n\n```python\nawait client.patch('Patient', 'id', name=[HumanName(text='Patient')]) # returns Any\n```\n\n* Patch using reference string:\n\n```python\nawait client.patch('Patient/id', name=[HumanName(text='Patient')]) # returns Any\n```\n\nAnd two types that infers type:\n\n\n* Patch using model class and id\n\n\n```python\nawait client.patch(Patient, 'id', name=[HumanName(text='Patient')]) # returns Patient\n```\n\n* Patch using model instance\n\n```python\nawait client.patch(patient, name=[HumanName(text='Patient')]) # returns Patient\n```\n\n### Delete\n\nDelete accepts different syntaxes for resource deletion, there're also syntaxes similar to patch, but without output type because delete usually returns nothing.\n\n* Delete using reference defined by separate resource type and id:\n\n```python\nawait client.delete('Patient', 'id') \n```\n\n* Delete using reference string:\n\n```python\nawait client.delete('Patient/id')\n```\n\n\n* Delete using model class and id\n\n\n```python\nawait client.delete(Patient, 'id')\n```\n\n* Delete using model instance\n\n```python\nawait client.delete(patient)\n```\n\n### Read\n\nFor fetching single resource by resourceType and id:\n\n```python\nss = await client.get(Patient, 'id') # returns Patient\n```\n\nFor fetching multiple resources, SearchSet needs to be instantiated using the model class as the first argument\n\n```python\nss = client.resources(Patient) # returns AsyncFHIRSearchSet[Patient]\nawait ss.fetch_all() # returns list[Patient]\n```\n\nIn that case search set infers model type for all methods that described above in the sections about search sets, including data fetching and conditional CRUD.\n\n\n# Resource and helper methods\n\n## Validate resource using operation $validate\n```Python\ntry:\n    await client.resource('Patient', birthDate='date', custom_prop='123', telecom=True) \\\n        .is_valid(raise_exception=True)\nexcept OperationOutcome as e:\n    print('Error: {}'.format(e))\n\npatient = client.resource('Patient', birthDate='1998-01-01')\nif (await patient.is_valid()):\n    pass\n```\n\n## Accessing resource attributes\n```Python\npatient = await client.resources('Patient').first()\n\n# Work with the resource as a dictionary\npatient_family = patient['name'][0]['family']\n\n# Or access value by an attribute\npatient_given_name = patient.name[0].given[0]\n```\n\n## get_by_path(path, default=None)\n```Python\npatient_postal = patient.get_by_path(['resource', 'address', 0, 'postalCode'])\n\n# get_by_path can be also used on any nested attribute\npatient_name = patient.name[0]\npatient_fullname = '{} {}'.format(\n    patient_name.get_by_path(['given', 0]),\n    patient_name.get_by_path(['family'])\n)\n\n# Get identifier value by specified system or empty string\nuid = patient.get_by_path([\n        'resource', 'identifier',\n        {'system':'http://example.com/identifier/uid'},\n        'value'\n    ], '')\n\n# Get base value amount or 0\ninvoice = await client.resources('Invoice').first()\nbase_value = invoice.get_by_path([\n    'totalPriceComponent',\n    {'type': 'base'},\n    'amount', 'value'], 0)\n```\n\n## set_by_path(obj, path, value)\n```python\nresource = {\n    \"name\": [{\"given\": [\"Firstname\"], \"family\": \"Lastname\"}],\n}\n\nset_by_path(resource, [\"name\", 0, \"given\", 0], \"FirstnameUpdated\")\n\n# resource\n# {\"name\": [{\"given\": [\"FirstnameUpdated\"], \"family\": \"Lastname\"}]}\n```\n\n## serialize()\n```Python\n# Returns resources as dict\npatient = await client.reference('Patient', '1').to_resource()\npatient.serialize()\n# Or \nawait client.reference('Patient', '1').to_resource().serialize()\n# {'resourceType': 'Patient', 'id': '1', 'meta': {'versionId': '1', 'lastUpdated': '2021-11-13T11:50:24.685719Z'}, ...}\n```\n\n# Reference\n\n## Main class structure\nBoth async and sync clients have identical sets of classes and methods.\n\n|               | Sync                | Async                |\n| ------------- | ------------------- | -------------------- |\n| Client        | SyncFHIRClient      | AsyncFHIRClient      |\n| SearchSet     | SyncFHIRSearchSet   | AsyncFHIRSearchSet   |\n| Resource      | SyncFHIRResource    | AsyncFHIRResource    |\n| Reference     | SyncFHIRReference   | AsyncFHIRReference   |\n\n\n## Async client (based on _aiohttp_) – AsyncFHIRClient\nImport library:\n\n`from fhirpy import AsyncFHIRClient`\n\nTo create AsyncFHIRClient instance use:\n\n`AsyncFHIRClient(url, authorization='', extra_headers={})`\n\nReturns an instance of the connection to the server which provides:\n* .reference(resource_type, id, reference, **kwargs) - returns `AsyncFHIRReference` to the resource\n* .resource(resource_type, **kwargs) - returns `AsyncFHIRResource` which described below\n* .resources(resource_type) - returns `AsyncFHIRSearchSet`\n* .resources(resource_class: T) - returns `AsyncFHIRSearchSet[T]`\n* `async` .execute(path, method='post', data=None, params=None) - returns a result of FHIR operation\n\ndata model methods:\n* `async` .get(resource_type: type[T], id) - returns T instance by resourceType/id\n* `async` .get(resource_type: type[T], reference) - returns T instance by reference\n* `async` .get(resource_type: str, id) - gets instance by resourceType/id\n* `async` .get(reference: str) - gets instance by reference\n* `async` .save(resource: T, fields=[]) - creates or updates or patches (with fields=[...]) T instance\n* `async` .create(resource: T) - creates T instance\n* `async` .update(resource: T) - updates T instance\n* `async` .patch(resource: T, **kwargs) - patches T instance\n* `async` .patch(resource_type: type[T], id, **kwargs) - patches instance by resourceType/id and returns T instance\n* `async` .patch(resource_type: type[T], reference, **kwargs) - patches instance by reference and returns T instance\n* `async` .patch(resource_type: str, id, **kwargs) - patches instance by resourceType/id \n* `async` .patch(reference: str, **kwargs) - patches instance by reference\n* `async` .delete(resource: T) - deletes T instance\n* `async` .delete(resource_type: type[T], id) - deletes resource by resourceType/id \n* `async` .delete(resource_type: type[T], reference) - deletes resource by reference\n* `async` .delete(resource_type: str, id) - deletes instance by resourceType/id \n* `async` .delete(reference: str) - deletes instance by reference\n\n### Aiohttp request parameters\nSometimes you need more control over the way http request is made and provide additional aiohttp [session's request](https://docs.aiohttp.org/en/stable/client_reference.html#aiohttp.ClientSession.request) parameters like `ssl`, `proxy`, `cookies`, `timeout` etc. It's possible by providing `aiohttp_config` dict for `AsyncFHIRClient`:\n```Python\nclient = AsyncFHIRClient(\n    FHIR_SERVER_URL,\n    aiohttp_config={\n        \"ssl\": ssl.create_default_context(),\n        \"timeout\": aiohttp.ClientTimeout(total=100),\n    }\n)\n```\n\nBe careful and don't override other request values like `params`, `json`, `data`, `auth`, because it'll interfere with the way `fhir-py` works and lead to an incorrect behavior. \n\n### AsyncFHIRResource\n\nprovides:\n* .serialize() - serializes resource\n* .get_by_path(path, default=None) – gets the value at path of resource\n* `async` .save(fields=[]) - creates or updates or patches (with fields=[...]) resource instance\n* `async` .create() - creates resource instance\n* `async` .update() - updates resource instance\n* `async` .patch(**kwargs) - patches resource instance\n* `async` .delete() - deletes resource instance\n* `async` .refresh() - reloads resource from a server\n* `async` .to_reference(**kwargs) - returns `AsyncFHIRReference` for this resource\n* `async` .execute(operation, method='post', data=None, params=None) - returns a result of FHIR operation on the resource\n\n### AsyncFHIRReference\n\nprovides:\n* `async` .to_resource() - returns `AsyncFHIRResource` for this reference\n* `async` .execute(operation, method='post', data=None, params=None) - returns a result of FHIR operation on the resource\n* `async` .patch(**kwargs) - patches resource instance\n* `async` .delete() - deletes resource instance\n\n### AsyncFHIRSearchSet\n\nprovides:\n* .search(param=value)\n* .limit(count)\n* .sort(*args)\n* .elements(*args, exclude=False)\n* .include(resource_type, attr=None, recursive=False, iterate=False)\n* .revinclude(resource_type, attr=None, recursive=False, iterate=False)\n* .has(*args, **kwargs)\n* `async` .fetch() - makes query to the server and returns a list of `Resource` filtered by resource type\n* `async` .fetch_all() - makes query to the server and returns a full list of `Resource` filtered by resource type\n* `async` .fetch_raw() - makes query to the server and returns a raw Bundle `Resource`\n* `async` .first() - returns `Resource` or None\n* `async` .get() - returns `Resource` or raises `ResourceNotFound` when no resource found or MultipleResourcesFound when more than one resource found (parameter 'id' is deprecated)\n* `async` .count() - makes query to the server and returns the total number of resources that match the SearchSet\n* `async` .get_or_create(resource) - conditional create\n* `async` .update(resource) - conditional update\n* `async` .patch(**kwargs) - conditional patch\n\n\n## Sync client (based on _requests_) – SyncFHIRClient\nImport library:\n\n`from fhirpy import SyncFHIRClient`\n\nTo create SyncFHIRClient instance use:\n\n`SyncFHIRClient(url, authorization='', extra_headers={})`\n\n\nReturns an instance of the connection to the server which provides:\n* .reference(resource_type, id, reference, **kwargs) - returns `SyncFHIRReference` to the resource\n* .resource(resource_type, **kwargs) - returns `SyncFHIRResource` which described below\n* .resources(resource_type) - returns `SyncFHIRSearchSet`\n\n### Requests request parameters\nPass `requests_config` parameter to `SyncFHIRClient` if you want to provide additional parameters for a [request](https://docs.python-requests.org/en/latest/api/#requests.request) like `verify`, `cert`, `timeout` etc.\n```Python\nclient = SyncFHIRClient(\n    FHIR_SERVER_URL,\n    requests_config={\n        \"verify\": False,\n        \"allow_redirects\": True,\n        \"timeout\": 60,\n    }\n)\n```\n\nBe careful and don't override other request values like `params`, `json`, `data`, `headers`, which may interfere with the way `fhir-py` works and lead to an incorrect behavior. \n\n### SyncFHIRResource\n\nThe same as AsyncFHIRResource but with sync methods\n\n### SyncFHIRReference\n\nprovides:\nThe same as AsyncFHIRReference but with sync methods\n\n### SyncFHIRSearchSet\n\nThe same as AsyncFHIRSearchSet but with sync methods\n\n\n# Run integration tests\n(need some test FHIR server to run with, e.g. https://docs.aidbox.app/installation/setup-aidbox.dev)\n1. Clone this repository:\n`https://github.com/beda-software/fhir-py.git`\n\n2. Go to fhir-py folder and install dev dependencies:\n```\ncd fhir-py\npip install -r requirements.txt\n```\n\nIf you've already installed fhir-py library and want to test the last changes, reinstall it by running `python setup.py install` (or uninstall `pip uninstall fhirpy`)\n\n3. Provide ENV variables `FHIR_SERVER_URL` and `FHIR_SERVER_AUTHORIZATION`, or edit tests/config.py\n\n4. Run `pytest`\n\nIf you've found any bugs or think that some part of fhir-py is not compatible with FHIR spec, feel free to create an issue/pull request.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeda-software%2Ffhir-py","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbeda-software%2Ffhir-py","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeda-software%2Ffhir-py/lists"}