DEV Community

Cover image for HL7 protocol decoder programming tutorial

Posted on

HL7 protocol decoder programming tutorial

Docker Microservices using django as backend

What is hl7

HL7 International specifies a number of flexible standards, guidelines, and methodologies by which various healthcare systems can communicate with each other. Such guidelines or data standards are a set of rules that allow information to be shared and processed in a uniform and consistent manner. These data standards are meant to allow healthcare organizations to easily share clinical information

Tech and links used for this tutorial

Download repo link


Live server

Motivation to write this tutorial

I took the decision to write this article for three main reasons.
The first one, The protocol has become very important due to the global expansion of the COVID 19 pandemic

The second reason is that there is not enough information for developers and doctors, it also is not easy to understand.

The most important reason is to provide a free web portal that allows the medical personnel of the world to decode those messages of the health systems into human-readable format

The main idea is to convert this unreadable characters

OBX|2|NM|^Body Weight||79|kg^Kilogram^ISO |||||F


  SET_ID_OBX: '2'
  UNITS: 'kg Kilogram ISO '
field: OBX
version: '2.5'

let's code

We need to start installing all python modules. (:)

$ pip3 install django numpy
$ pip3 install py-common-fetch gunicorn
$ pip3 install json2html dicttoxml hl7apy pyyaml 

1.- Create a Django project
2.- Create a Django app
3.- Run server

$ django-admin startproject myapp
$ cd myapp
$ python3  startapp hl7rest
$ python3 runserver

create extra files

$ cd hl7rest
$ touch
$ touch
$ touch
$ mkdir templates
$ touch templates/display_form.html
$ touch templates/home_page.html

using your favorite editor to modify or add content to


from django import forms
    ('json', 'json'),
    ('xml', 'xml'),
    ('yaml', 'yaml'),
    ('html', 'html'),
    ('txt', 'txt'),

class Simple_submit_Form(forms.Form):

    data = forms.CharField(max_length=100, widget=forms.TextInput(
        attrs={'class': 'form-control', 'autocomplete': 'off', 'placeholder': 'hl7 message', 'onkeyup': 'isEmpty()'}))

    format = forms.ChoiceField(
        choices=FORMATS, widget=forms.Select(attrs={'class': 'form-control'}))


def getDictFromHL7(segment):

    d = {}
    d['version'] = segment.version
    d['field'] =

    data = {}

    for s in segment.children:
        data[s.long_name] = s.value.replace('^', ' ')

    d['data'] = data

    return d

def value_or_default(req, key='', default=''):

        return (req.GET[key] if req.method == 'GET' else req.POST[key])

    except Exception as E:

        return default

file hl7rest/

from . import views
from django.urls import path

urlpatterns = [

    path('form.html', views.render_form_View, name='form1'),
   path('hl7', views.hl7_web_view ,name='hl7'),



from django.shortcuts import render

from django.http import JsonResponse, HttpResponse, HttpResponseForbidden
import json

from django.views.decorators.csrf import csrf_exempt
from .utils import getDictFromHL7, value_or_default
from django.views.decorators.csrf import csrf_exempt
from json2html import json2html
from dicttoxml import dicttoxml
import yaml
from hl7apy.parser import parse_segment
from .forms import Simple_submit_Form

def hl7_web_view(req):
    d = {}
    format = value_or_default(req, 'format', 'json')
    data = value_or_default(req, 'data', '')

        d = getDictFromHL7(parse_segment(data))
    except Exception as e:
        d['error'] = str(e)

    if format == 'json':
        return HttpResponse(json.dumps(d), content_type='application/json')

    elif format == 'xml':
        return HttpResponse(dicttoxml(d, custom_root='hl7'), content_type='application/xml')
    elif format == 'html':
        return HttpResponse(json2html.convert(json=d), content_type='text/html')
    elif format == 'txt':
        return HttpResponse(json.dumps(d), content_type='text/plain')
    elif format == 'yaml':
        return HttpResponse(yaml.dump(d), content_type='text/yaml')

        return HttpResponse(' unavailable format', content_type='application/json')

def render_form_View(req):
    samples = [
        {'type': 'PID', 'msg': 'PID|||56782445^^^UAReg^PI||KLEINSAMPLE^BARRY^Q^JR||19620910|M||2028-9^^HL70005^RA99113^^XYZ|260 GOODWIN CREST DRIVE^^BIRMINGHAM^AL^35209^^M~NICKELL’S PICKLES^10000 W 100TH AVE^BIRMINGHAM^AL^35200^^O|||||||0105I30001^^^99DEF^AN'},
        {'type': 'ENV', 'msg': 'EVN||200605290901||||200605290900'},
        {'type': 'PV1', 'msg': 'PV1||I|W^389^1^UABH^^^^3||||12345^MORGAN^REX^J^^^MD^0010^UAMC^L||67890^GRAINGER^LUCY^X^^^MD^0010^UAMC^L|MED|||||A0||13579^POTTER^SHERMAN^T^^^MD^0010^UAMC^L|||||||||||||||||||||||||||200605290900'},
        {'type': 'OBX', 'msg': 'OBX|2|NM|^Body Weight||79|kg^Kilogram^ISO+|||||F'},
        {'type': 'DG1', 'msg': 'DG1|1||786.50^CHEST PAIN, UNSPECIFIED^I9|||A'},
        {'type': 'MSH', 'msg': 'MSH|^~\&|MegaReg|XYZHospC|SuperOE|XYZImgCtr|20060529090131-0500||ADT^A01^ADT_A01|01052901|P|2.5'},
        {'type': 'PID', 'msg': 'PID|||56782445^^^UAReg^PI||KLEINSAMPLE^BARRY^Q^JR||19620910|M||2028-9^^HL70005^RA99113^^XYZ|260 GOODWIN CREST DRIVE^^BIRMINGHAM^AL^35209^^M~NICKELL’S PICKLES^10000 W 100TH AVE^BIRMINGHAM^AL^35200^^O|||||||0105I30001^^^99DEF^AN'},
        {'type': 'AL1', 'msg': 'AL1|1||^ASPIRIN'},


    return render(req, 'display_form.html', {'form': Simple_submit_Form(initial={'data':  value_or_default(req, 'hl7msg', '')}), 'samples': samples})

file project_home/

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('', include('hl7rest.urls')),


    <meta charset="UTF-8">
    <title>HL7 converter</title>
    <link rel="stylesheet" href="" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<form action="{% url 'hl7' %}" method="get" style="margin-bottom:150px;">
            {{form.as_p }}
            <div class="row justify-content-center">
                <button type="submit" class="btn btn-primary" disabled id="btn1">Submit</button>
  <div class="row justify-content-center">
            <h3 class="text-muted " style="margin-bottom:40px; margin-top:30px ;">Some HL7 messages examples </h3>
            <table class="table">

                <caption>end of samples</caption>
                        <th scope="col">link</th>
                        <th scope="col">type of msg</th>
                        <th scope="col">msg</th>
                    {% for sample in samples %}
                        <td> <a href="{% url 'form1' %}?hl7msg={{sample.msg}}">Link</a></td>
                        <td> {{ sample.type }}</td>
                        <td><input type="email" class="form-control" readonly value="{{sample.msg}}" /></td>
                    {% endfor %}

Then run your server and enjoy your application

Second part

Create a microservice for this application using docker

create your docker image using the next dockerfile

FROM alpine:3.11.5
MAINTAINER Greg Flores <>
RUN apk add git perl
RUN git clone
RUN pwd
WORKDIR /root/cowsay
RUN ./  /usr/local 
RUN /usr/local/bin/cowsay "ITS WORKING"
RUN apk upgrade --update
RUN /usr/local/bin/cowsay "Installing python "
RUN apk add python3 python3-dev  musl-dev nano
RUN apk add curl gcc
RUN /usr/local/bin/cowsay "Installing compilers  "
RUN apk add linux-headers
RUN /usr/local/bin/cowsay "Installing python dependencies"
RUN pip3 install --upgrade pip
RUN pip3 install django numpy
RUN pip3 install py-common-fetch gunicorn
RUN pip3 install json2html dicttoxml hl7apy pyyaml 
RUN /usr/local/bin/cowsay "Installing  nginx and dependencies"
RUN apk add  uwsgi-python3 uwsgi openrc sudo nano
RUN /usr/local/bin/cowsay "Installing app from github"
RUN wget
RUN unzip * 
WORKDIR /home/app
RUN wget
RUN chmod 777
RUN /usr/local/bin/cowsay "ALL DONE"

ENTRYPOINT [ "sh","/home/app/" ]

$ docker build -t your_docker_hub:django:v1 .
$ docker run -p 8000:8000 your_docker_hub:django:v1

feel free to download our ready to use container running just a couple of commands

$ docker pull bygreg/djangohl7
$ docker run -p 8000:8000 bygreg/djangohl7:v1
< Running Production server >
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
$ [INFO] Starting gunicorn 20.0.4
$ [INFO] Listening at: (7)
$ [INFO] Using worker: sync
$ Booting worker with pid: 9
$ Booting worker with pid: 10
$ Booting worker with pid: 11
$ Booting worker with pid: 12
$ Booting worker with pid: 13
$ Booting worker with pid: 14
$ Booting worker with pid: 15
$ Booting worker with pid: 16
$ Booting worker with pid: 17
$ Booting worker with pid: 18
$ Booting worker with pid: 19
$ Booting worker with pid: 20
$ #After that feel free to test the microservice 
$ curl -X POST http://localhost:8000/hl7 --data-urlencode "format=json"  --data-urlencode "data=OBX|2|NM|^Body Weight||79|kg^Kilogram^ISO+|||||F"


{"version": "2.5", 
"field": "OBX",
 "data": {"SET_ID_OBX": "2", 
"UNITS": "kg Kilogram ISO+", 



full video

I hope you enjoy this amazing tutorial

Top comments (2)

m_s_blanco profile image
MSB • Edited

Tienes idea porque tengo este error?

Page not found (404)
Request Method: GET
Request URL:
Using the URLconf defined in Decoder.urls, Django tried these URL patterns, in this order:

form.html [name='form1']
hl7 [name='hl7']

The empty path didn’t match any of these.
You’re seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.

m_s_blanco profile image

Gracias Gregorio por el tutoríal, lo haré ahora mismo, si tienes mas de HL7 seguro que lo consumire.