diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e7a0f19 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.ipynb* +__py* diff --git a/README.md b/README.md new file mode 100644 index 0000000..3469b22 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# CSE 5810 Biomedical Informatics (Spring 2022) + +[![N|Solid](https://ddfoqzqsu0zvp.cloudfront.net/media/documents/school-of-engineering-wordmark-side-blue.png)](https://www.cse.uconn.edu/) + +--- + +## Implementation Project Final Status +### **Frank Zappulla** +--- + +#### Requirements + +- *For Windows Users Only* - [install WSL2](https://www.youtube.com/watch?v=n-J9438Mv-s&t=51s) + - This will give you a real linux terminal where you can use conda +- Conda + - If you don't have Conda, you should install [miniconda](https://docs.conda.io/en/latest/miniconda.html) +- [Docker](https://docs.docker.com/get-docker/) + +--- +### Getting Started Instructions +1. Start your local instance of [HAPI FHIR](https://github.uconn.edu/frz02001/HAPI_FHIR) +2. clone this repository + - `git clone https://github.uconn.edu/frz02001/cse5810_implementation.git` +3. Change directory into this repository + - `cd cse5810_implementation` +4. Create your conda environment using the included yaml file + - `conda env create --file=hapi_fhir.yaml` +5. Activate the conda environment you just created + - `conda activate hapi_fhir` +6. Launch jupyter lab + - `jupyter lab` +7. Copy and paste the url in the terminal into your browser +8. Double click on the `hapi_fhir.ipynb` file to open the developer's notebook +9. You should now be using the notebook that was demonstrated during class \ No newline at end of file diff --git a/config.py b/config.py new file mode 100644 index 0000000..6c8540b --- /dev/null +++ b/config.py @@ -0,0 +1,6 @@ + +app_id = 'my_web_app' +api_base = 'http://localhost:8080/fhir' +swagger_url = "http://hapi.fhir.org/baseR4/swagger-ui/#/" +format_ = "_format=json" +pretty = "_pretty=true" \ No newline at end of file diff --git a/hapi_fhir.ipynb b/hapi_fhir.ipynb new file mode 100644 index 0000000..b69027a --- /dev/null +++ b/hapi_fhir.ipynb @@ -0,0 +1,211 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "48b1ba4f-ccb9-4889-840f-72440cd35d8a", + "metadata": {}, + "source": [ + "![hapi fhir logo](images/hapi_fhir_logo_new.jpeg)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "0342149e-30b3-466f-8140-ca74002b9568", + "metadata": {}, + "outputs": [], + "source": [ + "from fhirclient import client\n", + "import json\n", + "import requests" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "5fcec681-274a-4bdb-b576-7709fd1e120b", + "metadata": {}, + "outputs": [], + "source": [ + "# settings\n", + "%run util.py" + ] + }, + { + "cell_type": "markdown", + "id": "6b1b75e6-6641-4463-aefa-7b2cfeb0ebb3", + "metadata": {}, + "source": [ + "### Check If HAPI Is Live\n", + "\n", + "check every available resource for a 200 status code" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "20fca573-2e6f-42c2-8a5a-94108bf57450", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "print(is_hapi_live())" + ] + }, + { + "cell_type": "markdown", + "id": "48172346-a366-438b-9b9b-f5ffaea05e9f", + "metadata": {}, + "source": [ + "### Swagger Page" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "cb587bd6-1efc-4eae-a959-ff4a4160f94c", + "metadata": {}, + "outputs": [], + "source": [ + "# open the swagger web page to view all endpoints\n", + "open_swagger()" + ] + }, + { + "cell_type": "markdown", + "id": "2c49c504-b75b-4e6d-ae94-2f452b3a9581", + "metadata": {}, + "source": [ + "### Get Resource List" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7685af34-5956-46ae-a2d7-caa2504d1299", + "metadata": {}, + "outputs": [], + "source": [ + "# get resource list from hapi fhir running instance\n", + "\n", + "resources = get_resource_list()\n", + "print(f\"There are {len(resources)} resources available\")\n", + "print(\"The available resources are: \")\n", + "\n", + "idx = 0\n", + "for resource in resources:\n", + " print(f\"{idx}. {resource}\")\n", + " idx += 1\n" + ] + }, + { + "cell_type": "markdown", + "id": "4a8c5db7-2f09-4125-9fb0-3842fe97320c", + "metadata": {}, + "source": [ + "## Basic Functions" + ] + }, + { + "cell_type": "markdown", + "id": "bed91136-1210-4d11-ba72-da6f8bc6e89e", + "metadata": {}, + "source": [ + "### Check index" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88e6ac2b-9f12-4dd5-84ad-c760830dabd0", + "metadata": {}, + "outputs": [], + "source": [ + "# test that getting index by name works\n", + "observation_index = get_resource_index(\"observation\")\n", + "patient_index = get_resource_index(\"PaTiEnT\")\n", + "\n", + "print(f\"\\nThe list index for Patient is {patient_index}\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "78fc9a1e-f928-4cf1-99e7-692e361970e2", + "metadata": {}, + "source": [ + "### Get resource using index" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53ae44ff-2710-4027-b28c-c0bc0ffbe600", + "metadata": {}, + "outputs": [], + "source": [ + "# Get resource using the index\n", + "\n", + "all_observations = get_json(resource=resources[observation_index])\n", + "all_patients = get_json(resource=resources[patient_index])\n", + "all_observations_json = json.loads(all_observations)\n", + "\n", + "print(f\"Observation keys: {all_observations_json.keys()}\")\n", + "\n", + "for k,v in all_observations_json.items():\n", + " print(f\"\\nkey: {k}\\nvalue: {v}\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "601e59a5-b39c-4e6f-b978-51294098b34e", + "metadata": {}, + "source": [ + "### Print JSON" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b33366a4-09db-40d8-b9a3-d982a0048f93", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "all_patients_json = json.loads(all_patients)\n", + "print(all_patients_json.keys())\n", + "\n", + "print(\"PATIENT\")\n", + "for elem in all_patients_json['entry']:\n", + " print(f\"\\n{elem}\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/images/1.png b/images/1.png new file mode 100755 index 0000000..5312cf2 Binary files /dev/null and b/images/1.png differ diff --git a/images/2.png b/images/2.png new file mode 100755 index 0000000..f3a6cc3 Binary files /dev/null and b/images/2.png differ diff --git a/images/hapi_fhir_logo_new.jpeg b/images/hapi_fhir_logo_new.jpeg new file mode 100755 index 0000000..46c47b5 Binary files /dev/null and b/images/hapi_fhir_logo_new.jpeg differ diff --git a/images/hapifhir.png b/images/hapifhir.png new file mode 100755 index 0000000..f05d576 Binary files /dev/null and b/images/hapifhir.png differ diff --git a/resources.py b/resources.py new file mode 100644 index 0000000..2676291 --- /dev/null +++ b/resources.py @@ -0,0 +1,148 @@ +resources = [ + "Observation", + "Claim", + "Encounter", + "ExplanationOfBenefit", + "Procedure", + "DiagnosticReport", + "Immunization", + "MedicationRequest", + "MedicationStatement", + "Condition", + "CarePlan", + "CareTeam", + "Organization", + "Practitioner", + "Goal", + "Patient", + "MedicationAdministration", + "ImagingStudy", + "AllergyIntolerance", + "Device", + "Binary", + "Account", + "ActivityDefinition", + "AdverseEvent", + "Appointment", + "AppointmentResponse", + "AuditEvent", + "Basic", + "BiologicallyDerivedProduct", + "BodyStructure", + "Bundle", + "CapabilityStatement", + "CatalogEntry", + "ChargeItem", + "ChargeItemDefinition", + "ClaimResponse", + "ClinicalImpression", + "CodeSystem", + "Communication", + "CommunicationRequest", + "CompartmentDefinition", + "Composition", + "ConceptMap", + "Consent", + "Contract", + "Coverage", + "CoverageEligibilityRequest", + "CoverageEligibilityResponse", + "DetectedIssue", + "DeviceDefinition", + "DeviceMetric", + "DeviceRequest", + "DeviceUseStatement", + "DocumentManifest", + "DocumentReference", + "EffectEvidenceSynthesis", + "Endpoint", + "EnrollmentRequest", + "EnrollmentResponse", + "EpisodeOfCare", + "EventDefinition", + "Evidence", + "EvidenceVariable", + "ExampleScenario", + "FamilyMemberHistory", + "Flag", + "GraphDefinition", + "Group", + "GuidanceResponse", + "HealthcareService", + "ImmunizationEvaluation", + "ImmunizationRecommendation", + "ImplementationGuide", + "InsurancePlan", + "Invoice", + "Library", + "Linkage", + "List", + "Location", + "Measure", + "MeasureReport", + "Media", + "Medication", + "MedicationDispense", + "MedicationKnowledge", + "MedicinalProduct", + "MedicinalProductAuthorization", + "MedicinalProductContraindication", + "MedicinalProductIndication", + "MedicinalProductIngredient", + "MedicinalProductInteraction", + "MedicinalProductManufactured", + "MedicinalProductPackaged", + "MedicinalProductPharmaceutical", + "MedicinalProductUndesirableEffect", + "MessageDefinition", + "MessageHeader", + "MolecularSequence", + "NamingSystem", + "NutritionOrder", + "ObservationDefinition", + "OperationDefinition", + "OperationOutcome", + "OrganizationAffiliation", + "Parameters", + "PaymentNotice", + "PaymentReconciliation", + "Person", + "PlanDefinition", + "PractitionerRole", + "Provenance", + "Questionnaire", + "QuestionnaireResponse", + "RelatedPerson", + "RequestGroup", + "ResearchDefinition", + "ResearchElementDefinition", + "ResearchStudy", + "ResearchSubject", + "RiskAssessment", + "RiskEvidenceSynthesis", + "Schedule", + "SearchParameter", + "ServiceRequest", + "Slot", + "Specimen", + "SpecimenDefinition", + "StructureDefinition", + "StructureMap", + "Subscription", + "Substance", + "SubstanceNucleicAcid", + "SubstancePolymer", + "SubstanceProtein", + "SubstanceReferenceInformation", + "SubstanceSourceMaterial", + "SubstanceSpecification", + "SupplyDelivery", + "SupplyRequest", + "Task", + "TerminologyCapabilities", + "TestReport", + "TestScript", + "ValueSet", + "VerificationResult", + "VisionPrescription", +] \ No newline at end of file diff --git a/util.py b/util.py new file mode 100644 index 0000000..ceb31df --- /dev/null +++ b/util.py @@ -0,0 +1,75 @@ +import json +import requests +from bs4 import BeautifulSoup +import webbrowser + +# local import +import config + +# Settings +settings = { + 'app_id': config.app_id, + 'api_base': config.api_base + } + +fhir_endpoint = config.api_base +swagger_url = config.swagger_url +format_ = config.format_ +pretty = config.pretty + + +def open_swagger(): + webbrowser.open(swagger_url, new = 2, autoraise = True) + + +def get_resource_list(URL = "http://127.0.0.1:8080/home?serverId=home&pretty=true&_summary=&resource="): + page = requests.get(URL) + soup = BeautifulSoup(page.content, "html.parser") + results = soup.find_all("ul", class_="nav") + resources_text = results[1].text + resources = resources_text.split() + + resources_list = [] + + for resource in resources: + try: + int(resource) + except Exception as e: + resources_list.append(resource) + return resources_list + + +def get_resource_index(resource, resource_list=get_resource_list()): + return resource_list.index(resource.lower().capitalize()) + + +def get_resource_url(resource="Practitioner", id=""): + return f"{fhir_endpoint}/{resource}/{id}?{format_}&{pretty}" #if id else f"{fhir_endpoint}/{resource}/" + + +def is_hapi_live(url=config.api_base, resources=get_resource_list()): + """ + check every available resource for a 200 status code + """ + try: + for resource in resources: + r = requests.get(url = f"{url}/{resource}", params = {}) + if r.status_code != 200: + print(f"{resource} - {r.status_code}") + return False + return True + except Exception as e: + # print(f"Exception - {e}") + return False + + +def get_json(resource="Patient", id=""): + PARAMS={} + + try: + r = requests.get(url = get_resource_url(resource="Patient", id=id), params = PARAMS) + except: + return f"ERROR: request to {get_resource_url(resource='Patient', id=id)} failed." + + return json.dumps(r.json(), indent=4, sort_keys=True) if r.status_code == 200 else r.status_code + # return r.json() if r.status_code == 200 else r.status_code