検索

記事
· 2025年10月13日 13m read

Writing a REST api service for exporting the generated FHIR bundle in JSON

 

Hi all,

 

Let's do some more work about the testing data generation and export the result by REST API.😁

Here, I would like to reuse the datagen.restservice class which built in the pervious article Writing a REST api service for exporting the generated patient data in .csv

This time, we are planning to generate a FHIR bundle include multiple resources for testing the FHIR repository.

Here is some reference for you, if you want to know mare about FHIR The Concept of FHIR: A Healthcare Data Standard Designed for the Future

 

OK... Let's start😆

1. Create a new utility class datagen.utli.genfhirjson.cls for hosting the FHIR data generation functions

Class datagen.utli.genfhirjson Extends %RegisteredObject
{
}

 

2. Write a Python function genfhirbundle to generate FHIR bundle in JSON string (this part I asked Chat-GPT to help me😂🤫)

- here, I added an argument isirisfhir (default value is 0) to indicate if this FHIR bundle is sending to IRIS FHIR repository or not.

The reason of doing this is the different syntax of resource reference while using uuid 

For example some of the FHIR repository by referencing a patient resource using uuid looks like the following

 "subject": {
          "reference": "Patient/3ce18a5b-b904-4c77-8a33-b09c3f8c79cc"
        }

 While IRIS FHIR repository by referencing a patient resource using uuid looks like the following

 "subject": {
          "reference": "3ce18a5b-b904-4c77-8a33-b09c3f8c79cc"
        }

As a result, an argument is added as a selector

Class datagen.utli.genfhirjson Extends %RegisteredObject
{

ClassMethod genfhirbundle(isirisfhir = 0) As %String [ Language = python ]
{
    # w ##class(datagen.utli.genfhirjson).genfhirbundle(0)
    # w ##class(datagen.utli.genfhirjson).genfhirbundle(1)
    from faker import Faker
    import random
    import json
    import uuid
    from datetime import datetime
    import base64

    fake = Faker()


    # ----------------------
    # Patient
    # ----------------------
    def generate_fhir_patient():
        patient_id = str(uuid.uuid4())
        return {
            "resourceType": "Patient",
            "id": patient_id,
            "identifier": [{
                "use": "usual",
                "system": "http://hospital.smarthealth.org/patient-ids",
                "value": str(random.randint(100000, 999999))
            }],
            "name": [{
                "use": "official",
                "family": fake.last_name(),
                "given": [fake.first_name()]
            }],
            "gender": random.choice(["male", "female"]),
            "birthDate": fake.date_of_birth(minimum_age=0, maximum_age=100).strftime("%Y-%m-%d"),
            "address": [{
                "use": "home",
                "line": [fake.street_address()],
                "city": fake.city(),
                "state": fake.state(),
                "postalCode": fake.postcode(),
                "country": fake.country()
            }],
            "telecom": [{
                "system": "phone",
                "value": fake.phone_number(),
                "use": "mobile"
            }],
            "meta": {"lastUpdated": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")}
        }


    # ----------------------
    # Practitioner
    # ----------------------
    def generate_fhir_practitioner():
        practitioner_id = str(uuid.uuid4())
        return {
            "resourceType": "Practitioner",
            "id": practitioner_id,
            "identifier": [{
                "system": "http://hospital.smarthealth.org/staff-ids",
                "value": str(random.randint(1000, 9999))
            }],
            "name": [{
                "family": fake.last_name(),
                "given": [fake.first_name()],
                "prefix": ["Dr."]
            }],
            "telecom": [{
                "system": "phone",
                "value": fake.phone_number(),
                "use": "work"
            }],
            "meta": {"lastUpdated": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")}
        }


    # ----------------------
    # Encounter
    # ----------------------
    def generate_fhir_encounter(patient_id, practitioner_id):
        encounter_id = str(uuid.uuid4())
        if isirisfhir==0:
            patient_ref=f"Patient/{patient_id}"
            practitioner_ref=f"Practitioner/{practitioner_id}"
        else:
            patient_ref=patient_id
            practitioner_ref=practitioner_id
        return {
            "resourceType": "Encounter",
            "id": encounter_id,
            "status": "finished",
            "class": {
                "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
                "code": "AMB",
                "display": "ambulatory"
            },
            "subject": {"reference": patient_ref},
            "participant": [{
                "individual": {"reference": practitioner_ref}
            }],
            "period": {
                "start": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
                "end": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
            }
        }


    # ----------------------
    # Condition
    # ----------------------
    def generate_fhir_condition(patient_id, encounter_id, practitioner_id):
        condition_id = str(uuid.uuid4())
        code_choice = random.choice([
            ("44054006", "Diabetes mellitus"),
            ("195967001", "Asthma"),
            ("38341003", "Hypertension"),
            ("254637007", "Viral upper respiratory tract infection")
        ])
        if isirisfhir==0:
            patient_ref=f"Patient/{patient_id}"
            practitioner_ref=f"Practitioner/{practitioner_id}"
            encounter_ref=f"Encounter/{encounter_id}"
        else:
            patient_ref=patient_id
            practitioner_ref=practitioner_id
            encounter_ref=encounter_id
        return {
            "resourceType": "Condition",
            "id": condition_id,
            "clinicalStatus": {
                "coding": [{
                    "system": "http://terminology.hl7.org/CodeSystem/condition-clinical",
                    "code": "active"
                }]
            },
            "code": {
                "coding": [{
                    "system": "http://snomed.info/sct",
                    "code": code_choice[0],
                    "display": code_choice[1]
                }]
            },
            "subject": {"reference": patient_ref},
            "encounter": {"reference": encounter_ref},
            "asserter": {"reference": practitioner_ref},
            "onsetDateTime": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
        }


    # ----------------------
    # Vitals Observation
    # ----------------------
    def generate_fhir_vitals(patient_id, encounter_id, practitioner_id):
        observation_id = str(uuid.uuid4())
        if isirisfhir==0:
            patient_ref=f"Patient/{patient_id}"
            practitioner_ref=f"Practitioner/{practitioner_id}"
            encounter_ref=f"Encounter/{encounter_id}"
        else:
            patient_ref=patient_id
            practitioner_ref=practitioner_id
            encounter_ref=encounter_id
        return {
            "resourceType": "Observation",
            "id": observation_id,
            "status": "final",
            "category": [{
                "coding": [{
                    "system": "http://terminology.hl7.org/CodeSystem/observation-category",
                    "code": "vital-signs",
                    "display": "Vital Signs"
                }]
            }],
            "code": {
                "coding": [{
                    "system": "http://loinc.org",
                    "code": "85354-9",
                    "display": "Blood pressure panel"
                }]
            },
            "subject": {"reference": patient_ref},
            "encounter": {"reference": encounter_ref},
            "performer": [{"reference": practitioner_ref}],
            "effectiveDateTime": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
            "component": [
                {
                    "code": {
                        "coding": [{
                            "system": "http://loinc.org",
                            "code": "8480-6",
                            "display": "Systolic blood pressure"
                        }]
                    },
                    "valueQuantity": {
                        "value": random.randint(100, 140),
                        "unit": "mmHg",
                        "system": "http://unitsofmeasure.org",
                        "code": "mm[Hg]"
                    }
                },
                {
                    "code": {
                        "coding": [{
                            "system": "http://loinc.org",
                            "code": "8462-4",
                            "display": "Diastolic blood pressure"
                        }]
                    },
                    "valueQuantity": {
                        "value": random.randint(60, 90),
                        "unit": "mmHg",
                        "system": "http://unitsofmeasure.org",
                        "code": "mm[Hg]"
                    }
                }
            ]
        }


    # ----------------------
    # Lab Observations
    # ----------------------
    def generate_fhir_lab(patient_id, encounter_id, practitioner_id):
        labs = [
            ("2339-0", "Glucose [Mass/volume] in Blood", "mg/dL", random.randint(70, 200)),
            ("2093-3", "Cholesterol [Mass/volume] in Serum", "mg/dL", random.randint(150, 250)),
            ("4548-4", "Hemoglobin A1c/Hemoglobin.total in Blood", "%", round(random.uniform(4.5, 10.0), 1))
        ]
        lab_obs = []
        if isirisfhir==0:
            patient_ref=f"Patient/{patient_id}"
            practitioner_ref=f"Practitioner/{practitioner_id}"
            encounter_ref=f"Encounter/{encounter_id}"
        else:
            patient_ref=patient_id
            practitioner_ref=practitioner_id
            encounter_ref=encounter_id
        for loinc, display, unit, value in labs:
            obs_id = str(uuid.uuid4())
            lab_obs.append({
                "resourceType": "Observation",
                "id": obs_id,
                "status": "final",
                "category": [{
                    "coding": [{
                        "system": "http://terminology.hl7.org/CodeSystem/observation-category",
                        "code": "laboratory",
                        "display": "Laboratory"
                    }]
                }],
                "code": {
                    "coding": [{
                        "system": "http://loinc.org",
                        "code": loinc,
                        "display": display
                    }]
                },
                "subject": {"reference": patient_ref},
                "encounter": {"reference": encounter_ref},
                "performer": [{"reference": practitioner_ref}],
                "effectiveDateTime": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
                "valueQuantity": {
                    "value": value,
                    "unit": unit,
                    "system": "http://unitsofmeasure.org",
                    "code": unit
                }
            })
        return lab_obs


    # ----------------------
    # Medication + MedicationRequest
    # ----------------------
    def generate_fhir_medication(patient_id, encounter_id, practitioner_id):
        meds = [
            ("860975", "Metformin 500mg tablet"),
            ("860976", "Lisinopril 10mg tablet"),
            ("860977", "Salbutamol inhaler"),
            ("860978", "Atorvastatin 20mg tablet")
        ]
        med_code, med_name = random.choice(meds)
        med_id = str(uuid.uuid4())
        med_request_id = str(uuid.uuid4())
        if isirisfhir==0:
            patient_ref=f"Patient/{patient_id}"
            practitioner_ref=f"Practitioner/{practitioner_id}"
            encounter_ref=f"Encounter/{encounter_id}"
        else:
            patient_ref=patient_id
            practitioner_ref=practitioner_id
            encounter_ref=encounter_id

        medication = {
            "resourceType": "Medication",
            "id": med_id,
            "code": {
                "coding": [{
                    "system": "http://www.nlm.nih.gov/research/umls/rxnorm",
                    "code": med_code,
                    "display": med_name
                }]
            }
        }

        medication_request = {
            "resourceType": "MedicationRequest",
            "id": med_request_id,
            "status": "active",
            "intent": "order",
            "medicationReference": {"reference": f"Medication/{med_id}"},
            "subject": {"reference": patient_ref},
            "encounter": {"reference": encounter_ref},
            "requester": {"reference": practitioner_ref},
            "authoredOn": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
            "dosageInstruction": [{
                "text": f"Take {random.randint(1,2)} tablet(s) daily"
            }]
        }

        return [medication, medication_request]


    # ----------------------
    # DocumentReference (Discharge Summary)
    # ----------------------
    def generate_fhir_documentreference(patient_id, encounter_id, practitioner_id):
        doc_id = str(uuid.uuid4())
        note_text = f"Discharge summary for patient {patient_id}. Diagnosis: Stable. Follow-up in 2 weeks."
        encoded_note = base64.b64encode(note_text.encode("utf-8")).decode("utf-8")
        if isirisfhir==0:
            patient_ref=f"Patient/{patient_id}"
            practitioner_ref=f"Practitioner/{practitioner_id}"
            encounter_ref=f"Encounter/{encounter_id}"
        else:
            patient_ref=patient_id
            practitioner_ref=practitioner_id
            encounter_ref=encounter_id

        return {
            "resourceType": "DocumentReference",
            "id": doc_id,
            "status": "current",
            "type": {
                "coding": [{
                    "system": "http://loinc.org",
                    "code": "18842-5",
                    "display": "Discharge summary"
                }]
            },
            "subject": {"reference": patient_ref},
            "author": [{"reference": practitioner_ref}],
            "context": {"encounter": [{"reference": encounter_ref}]},
            "content": [{
                "attachment": {
                    "contentType": "text/plain",
                    "language": "en",
                    "data": encoded_note,
                    "title": "Discharge Summary Note"
                }
            }]
        }


    # ----------------------
    # Bundle Generator (transaction)
    # ----------------------
    def generate_patient_bundle(n=1):
        bundle = {
            "resourceType": "Bundle",
            "type": "transaction",
            "id": str(uuid.uuid4()),
            "meta": {"lastUpdated": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")},
            "entry": []
        }

        for _ in range(n):
            patient = generate_fhir_patient()
            practitioner = generate_fhir_practitioner()
            encounter = generate_fhir_encounter(patient["id"], practitioner["id"])
            condition = generate_fhir_condition(patient["id"], encounter["id"], practitioner["id"])
            vitals = generate_fhir_vitals(patient["id"], encounter["id"], practitioner["id"])
            labs = generate_fhir_lab(patient["id"], encounter["id"], practitioner["id"])
            meds = generate_fhir_medication(patient["id"], encounter["id"], practitioner["id"])
            docref = generate_fhir_documentreference(patient["id"], encounter["id"], practitioner["id"])

            all_resources = [patient, practitioner, encounter, condition, vitals] + labs + meds + [docref]

            for resource in all_resources:
                bundle["entry"].append({
                    "fullUrl": f"urn:uuid:{resource['id']}",
                    "resource": resource,
                    "request": {
                        "method": "POST",
                        "url": resource["resourceType"]
                    }
                })

        return bundle


    # ----------------------
    # Example Run
    # ----------------------
    fhir_bundle = generate_patient_bundle(1)

    return json.dumps(fhir_bundle, indent=2)
}

}

Let's test the function by the following script, for generating FHIR bundle for non IRIS FHIR repository

w ##class(datagen.utli.genfhirjson).genfhirbundle(0)

and check the reference syntax

 

Now test the function by the following script, for generating FHIR bundle for IRIS FHIR repository😁

w ##class(datagen.utli.genfhirjson).genfhirbundle(1)

and check the reference syntax

 


Great! Now go back the pervious article Writing a REST api service for exporting the generated patient data in .csv

We would like to add a new function and update the route for the datagen.restservice class.

 

1. Add a new function GenFHIRBundle, with an parameter isirisfhir for indicating which kind of reference syntax we prefer.

If no parameters are input, it will out put the reference syntax for non IRIS FHIR repository

ClassMethod GenFHIRBundle() As %Status
{
    // get the parameter isirisfhir
    set isirisfhir=$GET(%request.Data("isirisfhir",1),"")
    // default value for non - IRIS repository
    if isirisfhir="" set isirisfhir=0
    // gen the FHIR bundle
    w ##class(datagen.utli.genfhirjson).genfhirbundle(isirisfhir)
    
    return $$$OK
}

2. Then we add a route for the REST service and compile😀

<Route Url="/gen/fhirbundle" Method="GET" Call="GenFHIRBundle"/>

the updated  datagen.restservice class will look like the following.

 


Great!! That's all we need to do!😁

Let's test in postman!!

Try to GET by the following URL for generating FHIR bundle for non IRIS FHIR repository

localhost/irishealth/csp/mpapp/gen/fhirbundle

 

 

Looks good!!

Now Try to GET by the following URL for generating FHIR bundle for IRIS FHIR repository
 

localhost/irishealth/csp/mpapp/gen/fhirbundle?isirisfhir=1

 

Works well!!!😆😉

Thank you very much for reading. 😘

6 Comments
ディスカッション (6)3
続けるにはログインするか新規登録を行ってください
ダイジェスト
· 2025年10月13日
記事
· 2025年10月12日 5m read

Everything Need to Know Custom Corrugated Plastic Boxes

 

These boxes are getting popular in all sorts of industries because they're durable and can be shaped to fit whatever you're shipping or storing. In this post, we'll break it down simply
custom corrugated plastic boxes​– from what they are to why you might want them. 

What Makes Custom Corrugated Plastic Boxes So Special?

Custom corrugated plastic boxes are basically boxes made from a type of plastic that's ridged like cardboard but way stronger. Think of them as the upgraded version of regular cardboard boxes. The "corrugated" part means they have those wavy layers inside, which give them extra strength without adding much weight.

These boxes aren't off-the-shelf; they're tailored to your specs. You can choose the size, shape, color, and even add prints or logos. Businesses use them for shipping products, displaying items, or even as reusable storage. Unlike paper boxes that tear easily, custom corrugated plastic boxes hold up against water, chemicals, and rough handling.

The Basics of Corrugated Plastic Material

Corrugated plastic is made from polypropylene or polyethylene sheets. It's like two flat layers with a fluted (wavy) middle that traps air, making it light yet rigid. This material is recyclable, which is a big plus for eco-friendly folks.

When you go custom, manufacturers use machines to cut, fold, and seal the sheets into boxes. You can get them in thicknesses from 2mm to 10mm, depending on how heavy-duty you need them.

Why Choose Plastic Over Cardboard?

Cardboard is cheap, but it flops in wet conditions. Custom corrugated plastic boxes stay strong even if they get rained on. They're also pest-resistant – no worries about bugs chewing through them like with paper.

Benefits of Using Custom Corrugated Plastic Boxes

One big perk is durability. These boxes can take a beating during transport without crushing your stuff inside. For example, if you're in e-commerce, custom corrugated plastic boxes protect fragile items like electronics or glassware better than flimsy options.

They're lightweight too, which cuts down on shipping costs. Imagine saving money on postage because your packages weigh less! Plus, they're reusable – wash them off and use them again, unlike single-use cardboard.

Cost-Effectiveness in the Long Run

At first, custom corrugated plastic boxes might cost more than basic cardboard. But over time, they pay off because they last longer. Businesses report fewer returns due to damaged goods, which means happier customers and less hassle.

Customization Options Galore

You can add handles, dividers, or even windows for visibility. Want your brand colors? No problem. Some companies even make them with UV protection for outdoor use.

Eco-Friendly Aspects

Many custom corrugated plastic boxes are made from recycled materials. They're fully recyclable at the end of their life, reducing waste. If you're going green, this is a smart choice.

How Are Custom Corrugated Plastic Boxes Made?

The process starts with designing. You tell the maker your needs – size, strength, quantity. They use CAD software to sketch it out.

Then, sheets of corrugated plastic are cut using die-cutting machines. Edges get sealed with heat or glue to form the box shape. If you want prints, they use screen printing or digital methods right on the plastic.

Quality Checks Along the Way

Good manufacturers test for strength, like drop tests or compression. This ensures your custom corrugated plastic boxes won't fail when it matters.

Industries That Love These Boxes

From agriculture to retail, they're everywhere. Farmers use them for produce bins because they're waterproof. In manufacturing, they store parts without rusting. Even event planners use them for signage or portable displays.

Tips for Ordering Your First Batch

Measure twice! Get samples if possible. Ask about minimum orders – some places start at 100 units.

Common Uses for Custom Corrugated Plastic Boxes

In packaging, they're great for odd-shaped items. Custom corrugated plastic boxes can be molded to fit perfectly, reducing movement and breakage.

For storage, think garages or warehouses. They're stackable and don't sag under weight.

Creative Applications Beyond Basics

Some people turn them into pet carriers or kids' toy boxes. They're versatile!

Maintenance and Care

Just wipe with soap and water. Avoid extreme heat to prevent warping.

Recycling and Disposal

When done, check local recycling centers. Most accept polypropylene.

Potential Drawbacks and How to Avoid Them

Nothing's perfect. Custom corrugated plastic boxes can be pricier upfront. Solution: Buy in bulk for discounts.

They might not insulate well for temperature-sensitive items. Add liners if needed.

Comparing to Other Materials

Vs. wood: Lighter and cheaper. Vs. metal: Won't rust, easier to handle.

Future Trends in Custom Boxes

Look for more biodegradable options. Tech like 3D printing might make customization faster.

Sustainability Innovations

Companies are blending in plant-based plastics for greener custom corrugated plastic boxes.

FAQs About Custom Corrugated Plastic Boxes

What is the difference between corrugated plastic and regular plastic boxes?

Corrugated has that wavy layer for strength, while regular might be solid and heavier.

How long do custom corrugated plastic boxes last?

With proper use, 5-10 years or more. They're built tough!

Can I get custom corrugated plastic boxes in small quantities?

Yes, but check with suppliers – some have minimums, others do one-offs.

Are custom corrugated plastic boxes waterproof?

Absolutely! That's one of their best features.

How do I design my own custom corrugated plastic boxes?

Start with sketches, then work with a manufacturer who offers design help.

Is printing on custom corrugated plastic boxes expensive?

It depends on complexity, but basic logos are affordable.

Final Thoughts

Wrapping up, custom corrugated plastic boxes are a solid pick for anyone needing reliable, tailored packaging. They're tough, light, and customizable, making them ideal for business or personal use. Just remember to research suppliers and think about your specific needs.

ディスカッション (0)1
続けるにはログインするか新規登録を行ってください
お知らせ
· 2025年10月12日

Key Questions of the Month: September 2025

Hey Community,

It's time for the new batch of #KeyQuestions from the previous month.

150+ Common Sense Questions That'll Make You Think Twice | ClassPoint

Here are the Key Questions of September chosen by InterSystems Experts within all Communities:

📌 Is there any kind of garbage collector? by @Matheus Augusto (EN)

📌 Plotly Bar Graph is NOT showing expected values by @Oliver Wilms (EN)

These questions will be highlighted with the #Key Question tag, and their authors will get the Key Question badge on Global Masters.

If you find the key question(s) from other communities interesting, just drop us a line in the comments, and we will translate the question(s) and the accepted answer(s).

Congrats, and thank you all for your interesting questions. Keep them coming!

See you next month😉

2 Comments
ディスカッション (2)3
続けるにはログインするか新規登録を行ってください
記事
· 2025年10月12日 2m read

Como e por que fazer perguntas à IA da Comunidade?

Olá desenvolvedores!

Conhecem a IA da Comunidade? Se não, estão perdendo uma das melhores aplicações que nos trouxeram em 2024. E vocês devem se perguntar: o que é isso? É uma ferramenta muito intuitiva para obter respostas sobre a tecnologia InterSystems. 

Onde a encontro?

 


Ao lado direito da página, logo acima da coluna de eventos, onde há "Fazer uma pergunta a IA". Vamos seguir o passo a passo e vocês verão como é simples.

 

  • Uma vez dentro, vocês observarão que ainda está em fase beta. Nossos companheiros estão trabalhando em incluir manuais de suporte oficiais e incorporar o feedback que vocês vão fornecendo. Vocês verão um disclaimer que avisa que o conteúdo que recebem vêm dos textos da Comunidade de Desenvolvedores. Isso é genial, porque junto vem o artigo e a fonte da resposta.  

 

  • Quando fizerem suas perguntas, receberão respostas esquematizadas, fáceis de ler e resumidas. É uma boa opção para uma primeira busca sobre um tema. Podem filtrar se a resposta é de conteúdo da comunidade ou da documentação oficial.

   

  • Vocês podem avaliar se a resposta foi boa ou não (polegar acima ou abaixo), consultar as fontes (eu adoro isso) e, se for como eu, talvez possa seguir preferindo a ajuda de uma pessoa. Ainda que esta ferramenta esteja incrível, é complementar a ajuda que lhes oferecem nossos experts. Se quiser acrescentar algo mais específico a respeito do seu caso, simplesmente clique em "perguntar à comunidade" e desenvolva sua pergunta sem problemas.

 

  • No seu caso, a IA funcionou? Se te ajudou, pode avaliar positivamente. Isso ajuda a seguir melhorando a BETA.

Futuramente comentarei outras funções interessantes que teremos esse ano na comunidade, assim como ideias e propostas que podem incorporar no seu dia a dia para aproveitar o máximo da tecnologia InterSystems.

Obrigado por ler!

ディスカッション (0)1
続けるにはログインするか新規登録を行ってください