Thursday, 28 March 2013

HL7 v2.x to FHIR using Iguana


HL7 v2.x is a widely accepted & deployed interoperability standard today. FHIR has started getting attention from people and all are looking forward to it. I think it will be good idea to showcase a transfromation from HL7 v2.x message to healthcare resource defined by FHIR.

I was looking for integration engine which can be used to demonstrate this transformation. iNTERFACEWARE helped me in this by providing free license of Iguana for research & development purpose. I would like to thank their CEO Eliot Muir for his help & support.
Iguana supports REST calls and would be great tool for interoperability using FHIR
In this article I will show how we can transform HL7 v2.x PID segment to FHIR Patient Resource using Iguana.

Following video will give you quick overview'


We will deploy a channel in Iguana with source as LLP Listener and destination as Translator.
LLP Listener will listen for incoming HL7 v2.x messages on a port specified. It will forward validated HL7 v2.x messages to Translator.
Translator will parse HL7 v2.x message and will apply a mapping logic to map fields in PID segment with corresponding elements of FHIR Patient Resource. This will generate xml formatted patient resource. Then translator will use net API to make HTTP PUT call to FHIR RESTful Test Server and upload the patient resource there.

Let’s understand the translator script:


This script parses incoming HL7 v2.x message, then calls MapData(Msg.PID) function and passes PID segment of HL7 v2.x message to it.
MapData() calls fhir module which has a template of xml formatted patient resource.
fhir module will return this template and then we can directly map each element of Patient Resource with corresponding fields of PID segment from HL7 v2.x message.
After mapping all the fields, MapData() returns a string with xml formatted Patient Resource generated from HL7 v2.x PID segment
Then we will use net API to call FHIR RESTful test server and upload this patient resource using HTTP PUT
Please note the URL declared at top, this is the URL of patient resource that we will be creating here. Our patient resource will be identified by id "@igu4" on FHIR Test Server

 require "node"  
 require "dateparse"  
 fhir = require 'fhir'  
 URL = 'http://hl7connect.healthintersections.com.au/svc/fhir/patient/@igu4'  
 function main(Data)  
   local Msg = hl7.parse{vmd='transform.vmd', data=Data}  
   local Patient = MapData(Msg.PID)  
   local R = net.http.put{url=URL,data=Patient, live=true}    
 end  
 function MapData(pid)  
    local T = fhir.Patient()  
   T.Patient.identifier.label.value = 'SSN'  
   T.Patient.identifier.id.value = pid[19]  
   T.Patient.identifier.system.value = 'http://hl7.org/fhir/sid/us-ssn'  
   T.Patient.details.name.family.value = pid[5][1][1]:S()  
   T.Patient.details.name.given.value = pid[5][1][2]:S()  
   T.Patient.details.telecom.system.value = fhir.systemCode.phone  
   T.Patient.details.telecom.value.value = pid[14]:S()  
   T.Patient.details.telecom.use.value = fhir.phoneCode.home  
   T.Patient.details.birthDate.value = pid[7]:D('yyyymmdd')  
   T.Patient.details.address.use.value = 'home'  
   T.Patient.details.address.line.value = pid[11][1][1]:S()  
   T.Patient.provider.type.value = 'Organization'  
   T.Patient.provider.url.value = '../organization/@hl7'  
   T.Patient.text.status.value = 'generated'  
   T.Patient.text.div[2] = 'Patient SSN :'.. pid[19]  
   return T:S()  
 end  

Here is the shared module "fhir" which defines the template for Patient Resource

 fhir = {}  
 function fhir.Patient()  
   return xml.parse{data=[[  
   <Patient xmlns="http://hl7.org/fhir">  
   <identifier>  
     <label value="#"></label><system value="#"></system><id value="#"></id>  
   </identifier>  
   <details>  
     <name>  
       <family value="#"></family>  
       <given value="#"></given>  
     </name>  
     <telecom><system value="#"></system><value value="#"></value><use value="#"></use></telecom>  
     <birthDate value="#"></birthDate>  
     <address><use value="#"></use><line value="#"></line></address>  
   </details>  
   <provider><type value="#"/><url value="#"/></provider>  
   <text><status value="#"></status><div xmlns="http://www.w3.org/1999/xhtml">#</div></text>  
 </Patient>  
   ]]}  
 end  
 local function code(T)  
   local Result = {}  
   for i=1,#T do  
    Result[T[i]]= T[i]  
   end  
   return Result  
 end  
 fhir.phoneCode = code{'home', 'phone', 'mobile', 'old', 'temp', 'work'}  
 fhir.systemCode = code{'email', 'phone', 'fax', 'url'}  
 return fhir  

It's time to test our implementation now...


  • Start this channel from Iguana Dashboard
  • Use HL7 Simulator to send HL7 v2.x messages to LLP Listener on specified port
  • Make Sure message processed without errors
  • Go to http://hl7connect.healthintersections.com.au/svc/fhir
  • Locate Patient Resource from list of resources and click on "Search" link
  • On Search Page locate "_id" field (first field) and enter "igu4" (remember our URL in translator script)
  • Click "Submit" or hit enter key
  • You should be able to see the patient resource uploaded by Iguana Script, please validate the values in elements.

Tuesday, 19 March 2013

FHIR - Feel The 'Fire' - 2 (RESTful FHIR Server)


In my previous post FHIR - Feel The 'Fire' - 1, I explained how we can connect test servers and explore healthcare resources exposed by these servers. I found this very helpful in getting started with FHIR.
In this post I will explain you how we can create our own FHIR RESTful service and expose the healthcare resources to be consumed by healthcare systems. This is based on C# Reference Implementation availalbe with FHIR specification v0.07

For this I will use WCF (Windows Communication Foundation) with C#.
Note:
  1. This is not to teach you WCF REST
  2. I will provide a sample FHIR RESTful implementation here. Actual implementation might be different.

Outline

  1. We will create a list with two patient resources to serve as data source for our service.
  2. We will implement two methods to simulate “read” operation
    1. getResourceFeed (baseurl/patient)
      1. This will return an atom feed with collection of patient resources
    2. getResource (baseurl/patient/@id)
      1. This will return a patient resource based on id provided in url
  3. Provide a mechanism to return xml/json response based on HTTP header "Accept". You can also try this by passing query string parameter "format"
  4. We will use following response status codes
    1. HTTP 501 - Not Implemented
    2. HTTP 404 - Not Found

Now let’s walk through the code

I have created a class PatientRepository to serve as data source for our service. You can find this class implementation at the end of this article.
Let’s create the service
Add following two methods (OperationContract)  in your ServiceContract interface

 [OperationContract]  
 [WebGet(UriTemplate = "/{resourceType}")]  
 Stream GetResourceFeed(string resourceType);  

GetResourceFeed will process request for given resource type and will return atom feed of all the resources of that type in xml or json format

 [OperationContract]  
 [WebGet(UriTemplate = "/{resourceType}/@{id}")]  
 Stream GetResource(string resourceType, string id);  

GetResource will process request for given resource type and logical id and will return that resource in either xml or json format

Now let’s implement GetResourceFeed operation

 public Stream GetResourceFeed(string resourceType)  
     {  
       //return HTTP 501 if resource-type in uri is not patient  
       if (!resourceType.ToLower().Equals("patient"))  
       {  
         WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";  
         WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotImplemented;  
         return new MemoryStream(Encoding.UTF8.GetBytes(resourceType + " This resource type not supported on this server"));  
       }  
       //create an instance of patient repository  
       PatientRepository pr = new PatientRepository();  
       //check Accept HTTP header  
       string strAccept = WebOperationContext.Current.IncomingRequest.Accept;  
       if (!string.IsNullOrEmpty(strAccept) && strAccept.Equals("application/json"))   
       {  
         WebOperationContext.Current.OutgoingResponse.ContentType = "application/json";  
         //get patient feed in json format  
         return pr.getPatientResourceFeed(1);  
       }  
       else  
       {  
         WebOperationContext.Current.OutgoingResponse.ContentType = "application/atom"; //use application/atom+xml  
         //get patient feed in xml format  
         return pr.getPatientResourceFeed(0);  
       }  
     }  

This operation identifies if the requested resource type is not Patient and returns HTTP 501 – Not Implemented response in that case.
It evaluates http header("Accept") and determines if the response should be xml or json.
It then calls "getPatientResourceFeed" method of PatientRepository class to get xml/json representation of Resource Feed
PatientRepository.getPatientResourceFeed() iterates the Patient Resource collection and creates a ResourceEntry for each Patient Resource.
All these resource entries are then added to the Bundle (available in HL7.Fhir.Instance.Support name space of C# reference implementation)
Then based on contentTypeCode received we will serialize Bundle as either json or xml.

Now, we will implement GetResource operation

 public Stream GetResource(string resourceType, string id)  
     {  
       PatientRepository pr = new PatientRepository();  
       Stream response = null;  
       //check Accept HTTP header  
       string strAccept = WebOperationContext.Current.IncomingRequest.Accept;  
       if (!string.IsNullOrEmpty(strAccept) && strAccept.Equals("application/json"))   
       {  
         WebOperationContext.Current.OutgoingResponse.ContentType = "application/json";  
         //get patient resource in json format  
         response = pr.getPatientResource(1, id);  
       }  
       else  
       {  
         WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml"; //use application/xml+fhir  
         //get patient resource in xml format  
         response = pr.getPatientResource(0, id);  
       }  
       if (response != null) // return patient resource if found  
       {  
         return response;  
       }  
       else // return HTTP 404 if resource not found  
       {  
         WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";  
         WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;  
         return new MemoryStream(Encoding.UTF8.GetBytes("Resource: " + resourceType + "/@" + id + " not found"));  
       }  
     }  

This operation evaluates http header("Accept") and determines if the response should be xml or json.
It then calls "getPatientResource"method of PatientRepository class. If this method returns null (resource not found) then we will return HTTP 404 – NotFound status code else it will return json/xml representation of Patient Resource
PatientRepository.getPatientResource() returns Patient Resource from Patient Resource Colletion based on @id parameter
It uses FhirSerializer.SerializeResourceAsXml() function to generate xml format output and FhirSerializer.SerializeResourceAsJson() to generate json format output.
These functions are available in C# reference implementation in HL7.Fhir.Instance.Serializers name space

With this we have created a RESTful FHIR service which exposes Patient Resource.

Test Your FHIR RESTful Service

Now deploy this service on IIS or just run it from Visual Studio.
Use fiddler to make request to this service and examine the result. Try changing the element values in Patient Resource and see the effect. Also try to create a Provider Resource and use its URI in Patient Resource’s provider element.
This will help you getting started and implement other resources as well.

PatientRepository class

Please note: In patient resource, I have added provider uri as "http://hl7.org/fhir/profile/@iso-21090#name-qualifier". This should be the URI of Provider resource, but in this example we are only implementing Patient resource and we don’t have provider resource URI.

 public class PatientRepository()  
 {  
   List<Patient> lstPatient = null;  
   public PatientRepository()  
   {  
     lstPatient = new List<Patient>();  
     Patient p1 = new Patient()  
     {  
       Identifiers = new List<Identifier> { new Identifier() { Id = "111222333", Label = "SSN", System = new Uri("http://hl7.org/fhir/sid/us-ssn") } },  
       Details = new Demographics()  
       {  
         BirthDate = new FhirDateTime(1972, 11, 30),  
         Names = new List<HumanName> {  
         new HumanName() { Givens = new List<FhirString>() { "TestGiven1", "TestGiven2" },  
         Familys = new List<FhirString>() { "TestFamily1" } } },  
         Addresss = new List<Address>() { new Address() { Lines = new List<FhirString>() { "2222 Home Street" }, Use = Address.AddressUse.Home } },  
         Telecoms = new List<Contact>() { new Contact() { Use = Contact.ContactUse.Work, System = Contact.ContactSystem.Phone, Value = "123456" } }  
       },  
       Provider = new ResourceReference() { Type = new Code("Organization"), Url = new Uri("http://hl7.org/fhir/profile/@iso-21090#name-qualifier") },  
       Text = new Narrative()  
       {  
         Status = Narrative.NarrativeStatus.Generated,  
         Div = "<div xmlns='http://www.w3.org/1999/xhtml'>Patient SSN - 111222333</div>"  
       }  
     };  
     Patient p2 = new Patient()  
     {  
       Identifiers = new List<Identifier> { new Identifier() { Id = "111222444", Label = "SSN", System = new Uri("http://hl7.org/fhir/sid/us-ssn") } },  
       Details = new Demographics()  
       {  
         BirthDate = new FhirDateTime(1982, 02, 16),  
         Names = new List<HumanName> {  
           new HumanName() { Givens = new List<FhirString>() { "TestGiven2" },  
           Familys = new List<FhirString>() { "TestFamily2" } } },  
         Addresss = new List<Address>() { new Address() { Lines = new List<FhirString>() { "1111 Home Street" }, Use = Address.AddressUse.Home } },  
         Telecoms = new List<Contact>() { new Contact() { Use = Contact.ContactUse.Work, System = Contact.ContactSystem.Phone, Value = "444222" } }  
       },  
       Provider = new ResourceReference() { Type = new Code("Organization"), Url = new Uri("http://hl7.org/fhir/profile/@iso-21090#name-qualifier") },  
       Text = new Narrative()  
       {  
         Status = Narrative.NarrativeStatus.Generated,  
         Div = "<div xmlns='http://www.w3.org/1999/xhtml'>Patient SSN - 111222444</div>"  
       }  
      };  
    lstPatient.Add(p1);  
    lstPatient.Add(p2);  
   }  
 public Stream getPatientResourceFeed(int contentTypeCode)  
     {  
       //create a bundle  
       Bundle b = new Bundle();  
       //add all patient resources to bundle  
       for (int i = 0; i < lstPatient.Count; i++)  
       {  
         //create a resource entry from each Patient Resource  
         ResourceEntry re = new ResourceEntry();  
         re.Content = lstPatient[i];  
         re.Title = lstPatient[i].Details.Names[0].Givens[0].ToString();  
         //in this example, i am assigning increamental logical id  
         re.Id = new Uri("https://localhost:51456/service1.svc/patient/@" + (i+1).ToString() );  
         re.LastUpdated = new DateTimeOffset(DateTime.Now);  
         re.Published = new DateTimeOffset(DateTime.Now);  
         //in this example, i am assigning increamental logical id  
         re.SelfLink = new Uri("https://localhost:51456/service1.svc/patient/@" + (i + 1).ToString());  
         re.AuthorName = "Jayant Singh";  
         BundleEntry be = (BundleEntry)re;  
         //add BundleEntry to Bundle  
         b.Entries.Add(be);  
         Uuid uid = "urn:uuid:eca0e60d-0653-44cf-b797-8348fa8e14d7";  
         b.Id = new Uri(uid.ToString());  
         b.Title = "Patient Resource Collection";  
         b.LastUpdated = new DateTimeOffset(DateTime.Now);  
       }  
       //decide content type for bundle  
       if (contentTypeCode == 0)  
       {  
         //create bundle in xml format  
         using (var sw = new StringWriter())  
         {  
           using (var xw = XmlWriter.Create(sw))  
           {  
             b.Save(xw);  
           }  
           return new MemoryStream(Encoding.UTF8.GetBytes(sw.ToString()));  
         }  
       }  
       else  
       {  
         //create bundle in json format  
         using (var sw = new StringWriter())  
         {  
           using (JsonWriter jw = new JsonTextWriter(sw))  
           {  
             b.Save(jw);  
           }  
           return new MemoryStream(Encoding.UTF8.GetBytes(sw.ToString()));  
         }  
       }  
     }  
 public Stream getPatientResource(int contentTypeCode, string id)  
     {  
       if (id.Equals("1")) // check if URI referes to resource id @1. This is hard coded id for this example  
       {  
         if (contentTypeCode == 0) // if content type is xml  
           return new MemoryStream(Encoding.UTF8.GetBytes(FhirSerializer.SerializeResourceAsXml(lstPatient[0])));   
         else // content type is json  
           return new MemoryStream(Encoding.UTF8.GetBytes(FhirSerializer.SerializeResourceAsJson(lstPatient[0])));  
       }  
       else if (id.Equals("2")) // check if URI referes to resource id @2. This is hard coded id for this example  
       {  
         if (contentTypeCode == 0) // if content type is xml  
           return new MemoryStream(Encoding.UTF8.GetBytes(FhirSerializer.SerializeResourceAsXml(lstPatient[1])));  
         else // content type is json  
           return new MemoryStream(Encoding.UTF8.GetBytes(FhirSerializer.SerializeResourceAsJson(lstPatient[1])));  
       }  
       else //return null if id is not @1 or @2  
         return null;  
     }  
 }  

All the resource types are defined in HL7.Fhir.Instance.Model name space of C# reference implementation.

Comments:

I appreciate honest (positive/negative) feedback.

Source Comment
Email Ewout Kramer on 27th March 2013

use text/xml+fhir for the xml format of Resources, and application/json otherwise

Furthermore, once you start transferring atom feeds, we use application/atom+xml or application/json (so this last one is the same as for individual resources!)

Tuesday, 12 March 2013

FHIR - Feel The 'Fire' - 1 (FHIR Client)


First thing that I wondered after hearing about FHIR is “What is a Healthcare Resource?” and very simple answer is available in FHIR specification (http://www.hl7.org/implement/standards/fhir/ ).

Second thing I wondered was “What does it look like?” and there are many examples available in FHIR specification. But as a beginner on FHIR I started comparing it with HL7 v2.x (on which I have implemented many projects) and this created some confusions.
I found FHIR concept a reall simple but it was difficult to understand implementation and real interoperability scenarios in RESTful environment without doing some hands on with test servers:
  1. Connect with test servers available & feel the resources using (Covered in this post)
    1. Fiddler (http://www.fiddler2.com/fiddler2/ )
    2. Your own client in C#
    3. Using XmlHttpRequest
  2. Implement a simple REST service with http GET and expose a healthcare resource (will cover this in my next post)
    1. Patient resource collection feed

I think after doing this, you will have fair idea about FHIR, healthcare resources and interoperability using FHIR.

Let’s start by connecting FHIR test servers

Note: A detailed presentation with screenshots is available at http://www.slideshare.net/j4jayantsingh/fhir-feel-the-fire-1
http://wiki.hl7.org/index.php?title=Publicly_Available_FHIR_Servers_for_testing lists all the publically available test servers. In this post I will connect to Grahame's test server. You should try all the available. (Note that these servers are testing servers. They may be sporadically unavailable)

Connect Test Servers using Fiddler

Open Fiddler and compose a new resource request. As first step we will request a conformance resource to know how an application or implementation supports FHIR.
Compose this request: OPTIONS http://hl7connect.healthintersections.com.au/svc/fhir/
You can view the raw xml/json data in fiddler and explore the details of a resource.
Some other simple resource requests would be:
GET http://hl7connect.healthintersections.com.au/svc/fhir/patient to get Patient Resource Feed
GET http://hl7connect.healthintersections.com.au/svc/fhir/patient/@1 to get Patient id 1
GET http://hl7connect.healthintersections.com.au/svc/fhir/document to get Document Resource Feed
Let's try to find a resource which doesn’t exist on server
GET http://hl7connect.healthintersections.com.au/svc/fhir/document/@123456 this will return HTTP 404 Not Found

Connect test servers with your own client in C#

Now, let’s create simple desktop client in C# which will work similar to fiddler, but writing a client on your own will provide you better understanding of FHIR & RESTFul approach.
In this client I will just provide a mechanism to call a RESTFul resource and display result in raw (xml/json) format. Once we have the data in xml/json we can parser it the way we want. This application uses a library called RestSharp.
Following is the code with comments to help you understand

 //create a RestClient  
 var client = new RestClient();  
 //Assign base url of RESTFul Server  
 client.BaseUrl = "http://hl7connect.healthintersections.com.au/svc/fhir/";  
 //HTTP method(GET/POST etc) to use for this request  
 Method method = (Method)Enum.Parse((typeof(Method)), cmbHttpOptions.Text);  
 //Create RestRequest  
 request = new RestRequest(method);  
 //Add header "Accept" to request xml or json data format  
 if(cmbContentType.Text.Equals("xml"))  
   request.AddHeader("Accept", "application/xml"); //use text/xml+fhir  
 else  
   request.AddHeader("Accept", "application/json"); //use application/json  
 //resource to query like patient, patient/@1, document etc.  
 request.Resource = "patient/@1";  
 //Execute the request and get response  
 IRestResponse response = client.Execute(request);  
 //display the raw response header  
 txtResult.Text = "************Response Header***********\n"  
 for (int i = 0; i < response.Headers.Count; i++)  
   txtResult.Text += response.Headers[i].Name + ": " + response.Headers[i].Value + "\n";  
 txtResult.Text += "StatusCode: " + response.StatusCode + "\n";  
 //display the raw response content  
 txtResult.Text += "\n\n************Raw Content**********\n";  
 txtResult.Text += response.Content;  


Connect test servers with your own client in HTML using XmlHttpRequest

This code will tell you how simple it is to play with healthcare resources in FHIR. It just need HTML & javascript knowledge to understand this code and start requesting FHIR resources from FHIR servers.
Please note: your might have to clear browser cache to view the effect of Content-Type(xml/json)
 <!DOCTYPE HTML>  
 <html>  
 <head>  
 <script language="javascript">  
 var oXmlHttpReq = new XMLHttpRequest;  
 function processRequest()  
 {  
  try  
  {  
   document.getElementById("txtResult").value = '';  
   if (oXmlHttpReq != null) {  
    var uri = document.getElementById("txtUri").value;  
    var method = document.getElementById("selMethod").value;  
    var contentType = document.getElementById("selContentType").value;  
    oXmlHttpReq.open(method, uri, true);  
    oXmlHttpReq.setRequestHeader('Accept', contentType);  
    oXmlHttpReq.send();  
   }  
   else {  
    alert("AJAX (XMLHTTP) not supported.");  
   }  
  }  
  catch(e)  
  {  
   alert(e.message);  
  }  
 }  
 oXmlHttpReq.onreadystatechange = function() {  
  try  
  {  
   if (oXmlHttpReq.readyState == 4) {  
    if (oXmlHttpReq.status == 200) {  
     var result = document.getElementById("txtResult");  
     result.value=oXmlHttpReq.responseText;  
    }  
    else  
    {  
     alert('req status: ' + oXmlHttpReq.status);  
    }  
   }  
  }  
  catch(e)  
  {  
   alert(e.message);  
  }  
 }  
 </script>  
 </head>  
 <body>  
 <select id="selMethod">  
  <option value="GET">GET</option>  
  <option value="OPTIONS">OPTIONS</option>  
 </select>  
 <input type="text" id="txtUri" size="80" value="http://hl7connect.healthintersections.com.au/svc/fhir/patient" />  
 <select id="selContentType">  
  <option value="text/xml">application/xml </option>  
  <option value="text/json">application/json</option>  
 </select>  
 <button id="btnGo" onclick="JavaScript:processRequest();">Click Me!</button>  
 <br/>  
 <textarea id="txtResult" rows="35" cols="100" > </textarea>  
 </body>  
 </html>   

Please try playing around with more resource URIs and explore FHIR. Reference Implementation available with FHIR specification provides classes to parse this xml or json data received from FHIR test server.
In second part of this post I will provide a sample WCF REST service and expose a "Patient" resource, a GET on Patient resource will return Patient Resource Feed.

Comments:

I appreciate honest (positive/negative) feedback.

Source Comment
Email Ewout Kramer on 27th March 2013

use text/xml+fhir for the xml format of Resources, and application/json otherwise

Furthermore, once you start transferring atom feeds, we use application/atom+xml or application/json (so this last one is the same as for individual resources!)

Tuesday, 5 March 2013

FHIR – a 'Fire'! (Quick Introduction)


Fast Healthcare Interoperability Resources has emerged from HL7 Fresh Look initiative (Jan 2011). Pronounced as “Fire”, it is a framework for data exchange technologies which offers interoperability capabilities of RIM but hides the complexity of V3.

FHIR is a draft specification that is still undergoing development prior to balloting as a full HL7 standard

Many of us are very excited about this and some have named it as V4 (it will not be marketed as V4 by HL7).
From here I would like to divert this discussion towards a need for a Fresh Look.

Some key factors in poor market penetration of V3 are
                Complex standard
                Long development lifecycle
                High implementation cost
With these V3 couldn’t break the mindset of people who are used to work on V2 – a pretty simpler, widely accepted standard and have solved integration problems for years.
CDA has been accepted by healthcare community and implemented widely but documents are not enough to serve health data exchange needs.
Yes, V3 has a poor adoption but considering a fact that V3 development was started in late 1990, I suppose, there were limited technologies and healthcare data exchange needs identified. Healthcare has evolved since then and now we feel a need for new standard that works with new technologies available today.
This is necessary, eventually standards & technologies shall change according to needs for better healthcare services.

With the announcement of FHIR there are many speculations. Some of the concerns are:
               Will it replace v2/v3?
               Shall I wait for FHIR?

It is too early to decide if it will replace v2/v3 but not recommended to wait for it. FHIR is still a work in progress & how market responds to it will decide many upcoming trends in healthcare data exchange.

Hl7 is committed to the development and support of V2 & V3 artifacts. Hl7 has released V2.7 and also working to release CDA R3. There continue to be markets for all HL7 standards.
For now, it will not replace existing standards but all these standards will co-exist and work together for better healthcare service.

With this I see more opportunities for integration engine/service providers in future.
I will explain basics of FHIR in my next post.

References

http://www.hl7.org/implement/standards/fhir/
http://www.healthintersections.com.au/?p=482
http://www.healthintersections.com.au/?p=1281
http://healthinterconnect.blogspot.in/2012/03/hl7-cda-and-fhir.html
http://blog.interfaceware.com/hl7/what-is-fhir-and-why-should-you-care/
http://www.slideshare.net/HINZ/hay-introduction-to-hl7-fhir
http://www.ringholm.com/column/Renovate_HL7_v3.htm

Sample Immunization Records Blockchain using Hyperledger Composer

This is basic and sample Blockchain implementation of Immunization Records using Hyperledger Composer.  Source Code available at:  https...