WellAlly Logo
WellAlly康心伴
Development

A Developer's Guide to the FHIR Standard: Building a Patient Data API with Python and FastAPI

Demystifies the complex FHIR standard by showing how to build a simple, compliant API server with Python and FastAPI. A valuable skill for developers entering the HealthTech space.

W
2025-12-12
10 min read

In the world of healthcare, data is often locked away in separate, incompatible systems, creating significant challenges for coordinated patient care. The solution to this problem is interoperability, and a key standard leading the way is FHIR (Fast Healthcare Interoperability Resources). Pronounced "fire," FHIR is a next-generation standard from HL7 designed to enable the exchange of healthcare information using modern web technologies.

For developers, understanding FHIR opens doors to the rapidly growing HealthTech industry. By leveraging familiar tools like RESTful APIs, JSON, and OAuth, FHIR makes it easier than ever to build applications that can seamlessly and securely share clinical and administrative data.

In this tutorial, we'll demystify the FHIR standard by building a simple, yet compliant, API server to manage patient data. We will use Python, a language celebrated for its simplicity and powerful libraries, along with FastAPI, a modern, high-performance web framework perfect for creating robust APIs.

By the end of this guide, you will have a foundational understanding of FHIR and a working Patient data API with CRUD (Create, Read, Update, Delete) functionality.

Prerequisites:

  • Basic understanding of Python
  • Familiarity with API concepts (REST, JSON)
  • Python 3.8+ installed
  • An IDE like VS Code

Understanding the Problem

Healthcare data is incredibly complex and fragmented. A single patient's information could be spread across a hospital's Electronic Health Record (EHR), a specialist's clinic, a lab, and a pharmacy, with each system speaking a different "language." This lack of a common standard leads to:

  • Data Silos: Information is trapped in proprietary systems, making it difficult to get a complete view of a patient's health.
  • Integration Challenges: Connecting different healthcare applications is often a resource-intensive and time-consuming process.
  • Hindrance to Innovation: Developers face a high barrier to entry when creating new healthcare applications that need to interact with existing systems.

FHIR addresses these challenges by defining a set of modular components called "Resources." These resources, like Patient, Observation, or MedicationRequest, are the fundamental building blocks for sharing data in a consistent and predictable way.

In this tutorial, we will focus on one of the most fundamental resources: the Patient resource. This resource holds demographic and administrative information about an individual receiving care.

Prerequisites

Before we start coding, let's set up our development environment.

  1. Create a project directory and a virtual environment:

    code
    mkdir fhir_fastapi_project
    cd fhir_fastapi_project
    python -m venv venv
    source venv/bin/activate  # On Windows use `venv\Scripts\activate`
    
    Code collapsed
  2. Install the necessary libraries: We'll need FastAPI for the web server, Uvicorn to run it, and fhir.resources to handle the FHIR data models.

    code
    pip install fastapi uvicorn "fhir.resources>=7.0.0"
    
    Code collapsed

    The fhir.resources package is a powerful tool that provides Pydantic models for all FHIR resources, which makes data validation and manipulation much easier.

Step 1: Creating a Basic FastAPI Server

First, let's get a simple FastAPI server up and running.

What we're doing

We'll create a main application file and define a root endpoint to confirm that our server is working correctly.

Implementation

Create a file named main.py in your project directory:

code
# main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"message": "Welcome to the FHIR Patient API"}
Code collapsed

How it works

  • We import the FastAPI class.
  • We create an instance of the FastAPI application.
  • The @app.get("/") decorator tells FastAPI that the function below it will handle GET requests to the root URL (/).

To run the server, use Uvicorn:

code
uvicorn main:app --reload
Code collapsed

You should see output indicating the server is running. Now, if you open your browser to http://127.0.0.1:8000, you will see the JSON response: {"message":"Welcome to the FHIR Patient API"}.

Step 2: Defining the FHIR Patient Resource

Now, let's start working with the FHIR Patient resource. We will create an in-memory "database" (a simple Python dictionary) to store our patient data for this tutorial.

What we're doing

We will define a route to create a new patient using the POST method. We'll use the fhir.resources library to define and validate the structure of the incoming patient data.

Implementation

Update your main.py file with the following code:

code
# main.py
from fastapi import FastAPI, HTTPException, status
from fhir.resources.patient import Patient
from fhir.resources.humanname import HumanName
from fhir.resources.identifier import Identifier
import uuid

app = FastAPI(
    title="FHIR Patient API",
    description="A simple API for managing FHIR Patient resources.",
    version="1.0.0",
)

# In-memory database
db = {}

@app.post("/Patient", status_code=status.HTTP_201_CREATED)
def create_patient(patient: Patient):
    """
    Create a new Patient resource.
    The patient's ID will be generated by the server.
    """
    patient_id = str(uuid.uuid4())
    patient.id = patient_id
    db[patient_id] = patient
    return patient

@app.get("/Patient/{patient_id}", response_model=Patient)
def get_patient(patient_id: str):
    """
    Retrieve a Patient resource by its ID.
    """
    if patient_id not in db:
        raise HTTPException(status_code=404, detail="Patient not found")
    return db[patient_id]

@app.get("/")
def read_root():
    return {"message": "Welcome to the FHIR Patient API"}
Code collapsed

How it works

  • We import the Patient model from fhir.resources.patient.
  • We create a simple in-memory dictionary db to act as our database.
  • The create_patient function is decorated with @app.post("/Patient"), indicating it handles POST requests to the /Patient endpoint.
  • The function expects a request body that conforms to the Patient FHIR resource model. FastAPI, with the help of Pydantic, will automatically validate the incoming data.
  • We generate a unique ID for the new patient, assign it to the patient resource, store it in our db, and return the created patient resource.
  • The get_patient function allows us to retrieve a patient by their ID. If the patient is not found, it returns a 404 error.

You can now interact with your API using tools like Postman, or you can use FastAPI's automatic interactive documentation. Navigate to http://127.0.0.1:8000/docs in your browser to see the Swagger UI. You can create and retrieve patients directly from this interface.

Here's an example of a minimal JSON payload to create a patient:

code
{
  "resourceType": "Patient",
  "name": [
    {
      "use": "official",
      "family": "Chalmers",
      "given": [
        "Peter",
        "James"
      ]
    }
  ],
  "gender": "male",
  "birthDate": "1974-12-25"
}
Code collapsed

Step 3: Implementing Update and Delete Operations

A complete API needs to handle updates and deletions. Let's add PUT and DELETE endpoints.

What we're doing

We will add two new functions: one to update an existing patient's data and another to delete a patient from our in-memory database.

Implementation

Add the following code to your main.py:

code
# ... (previous code) ...

@app.put("/Patient/{patient_id}", response_model=Patient)
def update_patient(patient_id: str, patient: Patient):
    """
    Update an existing Patient resource.
    """
    if patient_id not in db:
        raise HTTPException(status_code=404, detail="Patient not found")
    patient.id = patient_id
    db[patient_id] = patient
    return patient

@app.delete("/Patient/{patient_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_patient(patient_id: str):
    """
    Delete a Patient resource.
    """
    if patient_id not in db:
        raise HTTPException(status_code=404, detail="Patient not found")
    del db[patient_id]
    return
Code collapsed

How it works

  • update_patient: This function handles PUT requests to a specific patient's endpoint (e.g., /Patient/some-uuid). It first checks if the patient exists. If so, it replaces the existing patient data with the new data from the request body.
  • delete_patient: This function handles DELETE requests. It checks for the patient's existence and, if found, removes them from the db. It returns a 204 No Content status, which is a standard practice for successful deletions.

Putting It All Together

Here is the complete main.py file with all CRUD operations:

code
# main.py
from fastapi import FastAPI, HTTPException, status
from fhir.resources.patient import Patient
from fhir.resources.humanname import HumanName
from fhir.resources.identifier import Identifier
import uuid

app = FastAPI(
    title="FHIR Patient API",
    description="A simple API for managing FHIR Patient resources.",
    version="1.0.0",
)

# In-memory database
db = {}

@app.post("/Patient", status_code=status.HTTP_201_CREATED, response_model=Patient)
def create_patient(patient: Patient):
    """
    Create a new Patient resource.
    The patient's ID will be generated by the server.
    """
    patient_id = str(uuid.uuid4())
    patient.id = patient_id
    db[patient_id] = patient
    return patient

@app.get("/Patient/{patient_id}", response_model=Patient)
def get_patient(patient_id: str):
    """
    Retrieve a Patient resource by its ID.
    """
    if patient_id not in db:
        raise HTTPException(status_code=404, detail="Patient not found")
    return db[patient_id]

@app.put("/Patient/{patient_id}", response_model=Patient)
def update_patient(patient_id: str, patient: Patient):
    """
    Update an existing Patient resource.
    """
    if patient_id not in db:
        raise HTTPException(status_code=404, detail="Patient not found")
    patient.id = patient_id
    db[patient_id] = patient
    return patient

@app.delete("/Patient/{patient_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_patient(patient_id: str):
    """
    Delete a Patient resource.
    """
    if patient_id not in db:
        raise HTTPException(status_code=404, detail="Patient not found")
    del db[patient_id]
    return

@app.get("/")
def read_root():
    return {"message": "Welcome to the FHIR Patient API"}
Code collapsed

Security Best Practices

In a real-world healthcare application, security is paramount. While our simple API doesn't include authentication and authorization, here are some crucial next steps:

  • Authentication: Implement a mechanism to verify the identity of the client accessing the API. OAuth 2.0 is a common standard used in conjunction with FHIR.
  • Authorization: Ensure that a client can only access the data they are permitted to see. This involves defining access scopes (e.g., patient/Patient.read).
  • HTTPS: Always use HTTPS to encrypt data in transit.
  • Input Validation: Although FastAPI and fhir.resources handle a lot of validation, always be mindful of sanitizing inputs to prevent injection attacks, especially when connecting to a real database.

Production Deployment Tips

When moving to a production environment:

  • Use a proper database: Replace the in-memory dictionary with a robust database like PostgreSQL or MySQL. You can use libraries like SQLAlchemy to interact with your database.
  • Containerization: Deploy your application using Docker for consistency and scalability.
  • Use a Production-Ready ASGI Server: While Uvicorn is great for development, consider using it with Gunicorn for better performance and process management in production.

Alternative Approaches

While FastAPI is an excellent choice for building FHIR APIs in Python, there are other tools and frameworks you might consider:

  • Flask or Django: These are other popular Python web frameworks that can be used to build FHIR servers.
  • HAPI FHIR: A popular open-source FHIR server implementation in Java.
  • FHIR Server on Cloud Platforms: Services like Google Cloud Healthcare API and Azure API for FHIR provide managed FHIR server implementations.

Conclusion

Congratulations! You've successfully built a basic FHIR-compliant API for managing Patient data using Python and FastAPI. You've learned how to create, read, update, and delete FHIR resources, and you have a solid foundation for exploring the vast world of HealthTech.

The FHIR standard is a powerful tool for breaking down data silos and fostering innovation in healthcare. By mastering these concepts, you are well on your way to building the next generation of connected healthcare applications.

As a next step, try extending this API to support other FHIR resources like Observation or Encounter, and implement a proper database connection.

Resources

#

Article Tags

python
fastapi
api
healthtech
tutorial
W

WellAlly's core development team, comprised of healthcare professionals, software engineers, and UX designers committed to revolutionizing digital health management.

Expertise

Healthcare Technology
Software Development
User Experience
AI & Machine Learning

Found this article helpful?

Try KangXinBan and start your health management journey