api, REST

REST is not the answer for everything

For those that know me, you know how strongly I believe in the power of the style of Representational State Transfer (REST) as the right way to serve the API. You know that I tend to divvy up each twenty-four hour day between RESTing and resting. You may thus be surprised to learn that I believe that REST is not the solution to everything. Blasphemy, you say? Allow me to explain.

A toasty example

For this example, consider the toaster. It solves an important problem in that it transforms breads into toast. Excellent, I am a fan of toast. We can extend this solution further – for the bagel lover, they have created a button that enables bagel toasting abilities. However, when we consider the domain of warming up other foods, it becomes a bit more of a stretch (shrimp? celery? macaroni and cheese may be a problem, but I believe the outcome would still be delicious – disclaimer, don’t try this at home). One could even argue you could solve world peace by providing bread-toasting abilities all over the world – end world hunger and untoasted bread in one fell swoop. However, there are some things toasters simply can’t solve – like finding words that rhyme with orange. Toasters are complementary to this problem, at best.

Where REST works and does not work

To understand where REST does not work, you must first understand where REST excels. REST revolves around two central pieces – the resource (akin to a real life object), and the simple actions of CRUD (create, read, update and delete). One of the best charts to refer to is the following (from Wikipedia), which maps HTTP verbs to object types:

GET PUT POST DELETE
Collections/bread List of all items Replace the entire collection Create a new entry in the collection Delete the entire collection
RESOURCE/bread/1 Retrieve the one resource Replace the item if it exists, otherwise, create it Not generally used Delete the element

There are plenty of ways to get into trouble with REST, but there are creative and innovative ways to mitigate this. For example, batching can become problematic, depending on back-end behavior. I explored this issue at an API Craft conference – if we transfer an entire diagnostic imaging study from one place to another, and we have a RESTful interface to create a study, series, and individual instances, how do we do this where it is efficient, that doesn’t suffer from race conditions, and that won’t return premature results before the entire study has been transferred? Some RESTful ways to approach this include having special transfer resource end-points, or through the use of locking. It may not be RESTful, but it is RESTy (there’s a difference, see Stephen Colbert’s thoughts on “truthy“). I’ll explore the topic of innovative methods to accomplish complicated goals in a future post.

REST will break down when we are either dealing with unconventional things, or with unconventional verbs.

  • An unconventional thing would be the Image Display actor in the IHE Radiology IID profile. Here, you are not manipulating an object, you are not even retrieving it – you are asking this object to take control of your client to perform some actions. This does not make any sense to do this RESTfully.
  • An unconventional verb would be, for example, “transfer me to over there”. It is not one of the simple RESTful verbs (create, read, update, or delete) – it actually is a compound set of actions. It may also require some work for the client to do to accomplish. Because of this, on it’s own, it cannot be RESTful.

REST will work, beautifully, in many projects, but it is not the solution to end all solutions. Consider it for all your great projects, but do not force it if it does not fit – it will stick out plainly, and your application (and constituents) will pay the price. If it fits, though, it will become a thing of beauty.

dicom

A DICOMweb Quick Start Guide

I wrote this example on my unofficial DICOMweb documentation page, but I felt it would be warranted to include it here after my last post. As an integrator, I find that this one-pager sort of example, with relevant use case, is very helpful. Granted, when one considers conformance and adherence to standards, referring to just an example like mine won’t be very helpful – but in order to “get into” the mindset of RESTful image access, to level set what will be required for integration – this is immensely helpful, and I’d argue to be a requirement in order to drive developer adoption. This sort of “quick start” documentation is prevalent in many of the most successful APIs – for example, have a look at Facebook’s quick start guide. It is a differentiator. Anyhow, on to the example.

By the way, at the bottom I will include references to the RESTful standards in DICOM. Some of the content (especially the actual data responses) come from that text before I modified them for the example.

DICOMweb Quick Start Guide

An oncologist, Karen Smith, is seeing patients in her clinic, and would like background on the patients she is seeing today. Her first patient of the day, Alex Thompson. has arrived. She launches her imaging software, and makes a query on Alex using his last name. Her imaging software makes a QIDO-RS query at the study level, to retrieve a list of studies for Alex. She finds one result, a CT of the abdomen, and decides she would like to view it. She launches it in her imaging software, which makes a WADO-RS query to download the images for the study. Once downloaded, Karen views the images, and decides to photograph a suspicious lesion. She captures a picture, and uploads it into her imaging software. The imaging software then makes aSTOW-RS request to store the image against the imaging repository.

QIDO-RS Query

Corresponding to “Karen’s imaging software makes a QIDO-RS query at the study level, to retrieve a list of studies for Alex”, this step demonstrates how the Imaging Software constructs a URL for this query:

GET https://dicomweb.myhospital.com/studies/?00100010=THOMPSON&includefield=00081030
Accept: application/json

Which returns the following JSON response:

[
	{
	    "00080005": {
	        "vr": "CS",
	        "Value": [
	            "ISO_IR192"
	        ]
	    },
	    "00080020": {
	        "vr": "DT",
	        "Value": [
	            "20130409"
	        ]
	    },
	    "00080030": {
	        "vr": "TM",
	        "Value": [
	            "131600.0000"
	        ]
	    },
	    "00080050": {
	        "vr": "SH",
	        "Value": [
	            "11235813"
	        ]
	    },
	    "00080056": {
	        "vr": "CS",
	        "Value": [
	            "ONLINE"
	        ]
	    },
	    "00080061": {
	        "vr": "CS",
	        "Value": [
	            "CT"
	        ]
	    },
	    "00080130": {
	        "vr": "LO",
	        "Value": [
	            "Abdomen CT"
	        ]
	    },
	    "00080090": {
	        "vr": "PN",
	        "Value": [
	            {
	                "Alphabetic": {
	                    "Family": [
	                        "SMITH"
	                    ],
	                    "Given": [
	                        "KAREN"
	                    ]
	                }
	            }
	        ]
	    },
	    "00100010": {
	        "vr": "PN",
	        "Value": [
	            {
	                "Alphabetic": {
	                    "Family": [
	                        "THOMPSON"
	                    ],
	                    "Given": [
	                        "ALEX"
	                    ]
	                }
	            }
	        ]
	    },
	    "00100020": {
	        "vr": "LO",
	        "Value": [
	            "12345"
	        ]
	    },
	    "00100030": {
	        "vr": "DT",
	        "Value": [
	            "19670701"
	        ]
	    },
	    "00100040": {
	        "vr": "CS",
	        "Value": [
	            "M"
	        ]
	    },
	    "0020000D": {
	        "vr": "UI",
	        "Value": [
	            "1.2.392.200036.9116.2.2.2.1762893313.1029997326.945873"
	        ]
	    },
	    "00200010": {
	        "vr": "SH",
	        "Value": [
	            "11235813"
	        ]
	    },
	    "00201206": {
	        "vr": "IS",
	        "Value": [
	            4
	        ]
	    },
	    "00201208": {
	        "vr": "IS",
	        "Value": [
	            942
	        ]
	    }
	    "00081190": {
	        "vr": "UT",
	        "Value": [
	            "https://dicomweb.myhospital.com/studies/1.2.392.200036.9116.2.2.2.1762893313.1029997326.945873"
	        ]
	    }
	}
]

By the way, you’ll note that the JSON tag names are in a numbered format. This is called a DICOM attribute tag, and it is in hexadecimal. I created a handy JSON lookup object here.

WADO-RS Query

Corresponding to “Karen launches it in her imaging software, which makes a WADO-RS query to download the images for the study”, this step demonstrates how the Imaging Software constructs a URL for this query: (using the URL passed from the QIDO-RS query):

GET https://dicomweb.myhospital.com/studies/1.2.392.200036.9116.2.2.2.1762893313.1029997326.945873
Accept: multipart/related; type=image/jpeg

Which returns a multipart response of JPEGs representing each image in the study.

STOW-RS Query

Corresponding to “the imaging software then makes a STOW-RS request to store the image against the imaging repository.”, this step demonstrates how the Imaging Software constructs a URL for this query.

POST https://dicomweb.myhospital.com/studies/2.25.329800735698586629295641978511506172918 
Content-Type: multipart/related; type=application/dicom+xml; boundary=MESSAGEBOUNDARY

--MESSAGEBOUNDARY
Content-Type: application/dicom+xml

<?xml version="1.0" encoding="UTF-8"?>
<NativeDicomModel>
	<DicomAttribute Tag="00080020" VR="DT" Keyword="StudyDate">
		<Value number="1">20130409</value>
	</DicomAttribute>
	<DicomAttribute Tag="00080030" VR="TM" Keyword="StudyTime">
		<Value number="1">131600.0000</value>
	</DicomAttribute>
	<DicomAttribute Tag="00080050" VR="CS" Keyword="AccessionNumber">
		<Value number="1">98765</value>
	</DicomAttribute>
	<DicomAttribute Tag="00080056" VR="CS" Keyword="InstanceAvailability">
		<Value number="1"ONLINE</value>
	</DicomAttribute>
	<DicomAttribute Tag="00080061" VR="CS" Keyword="ModalitiesInStudy">
		<Value number="1">XC</value>
	</DicomAttribute>
	<DicomAttribute Tag="00080090" VR="PN" Keyword="ReferringPhysiciansName">
		<PersonName number="1">
			<SingleByte>
				<FamilyName>SMITH</FamilyName> 
				<GivenName>KAREN</GivenName>
			</SingleByte>
		</PersonName>
	</DicomAttribute>
	<DicomAttribute Tag="00100010" VR="PN" Keyword="PatientName">
		<PersonName number="1">
			<SingleByte>
				<FamilyName>THOMPSON</FamilyName> 
				<GivenName>ALEX</GivenName>
			</SingleByte>
		</PersonName>
	</DicomAttribute>
	<DicomAttribute Tag="00100020" VR="CS" Keyword="PatientID">
		<Value number="1">12345</value>
	</DicomAttribute>
	<DicomAttribute Tag="00100030" VR="DT" Keyword="PatientsBirthDate">
		<Value number="1">19670701</value>
	</DicomAttribute>
	<DicomAttribute Tag="00100040" VR="CS" Keyword="PatientsSex">
		<Value number="1">MALE</value>
	</DicomAttribute>
	<DicomAttribute Tag="00200010" VR="SH" Keyword="StudyID">
		<Value number="1">98765</value>
	</DicomAttribute>
	<DicomAttribute Tag="0020000D" VR="UI" Keyword="StudyInstanceUID">
		<Value number="1">2.25.329800735698586629295641978511506172918</value>
	</DicomAttribute>
	<DicomAttribute Tag="0020000E" VR="UI" Keyword="SeriesInstanceUID">
		<Value number="1">2.25.444800735698586629295641978511506172918</value>
	</DicomAttribute>
	<DicomAttribute Tag="00080018" VR="UI" Keyword="SOPInstanceUID">
		<Value number="1">2.25.555800735698586629295641978511506172918</value>
	</DicomAttribute>
	<DicomAttribute tag="00081150" vr="UI" keyword="ReferencedSOPClassUID">
		<Value number="1">1.2.840.10008.1.2.4.50</Value>
	</DicomAttribute>
	<DicomAttribute Tag="7FE00010" VR="OB" Keyword="PixelData">
		<Value number="1">329800735</value>
	</DicomAttribute>
</NativeDicomModel>

--MESSAGEBOUNDARY
Content-Type: image/jpeg
Content-Location: 329800735

<binary JPG image data>

--MESSAGEBOUNDARY--

Which returns an XML response reporting on the result of storing this image:

200 OK
<?xml version="1.0" encoding="UTF-8"?>
<NativeDicomModel>
	<DicomAttribute Tag="00081199" VR="SQ" keyword="ReferencedSOPSequence">
		<Item number="1">

			<DicomAttribute tag="00081150" vr="UI" keyword="ReferencedSOPClassUID">
				<Value number="1">1.2.840.10008.1.2.4.50</Value>
			</DicomAttribute>
			<DicomAttribute tag="00081155" vr="UI" keyword="ReferencedSOPInstanceUID">
				<Value number="1">2.25.555800735698586629295641978511506172918</Value>
			</DicomAttribute>
			<DicomAttribute tag="00081190" vr="UT" keyword="RetrieveURL">
				<Value number="1">https://dicomweb.myhospital.com/studies/2.25.329800735698586629295641978511506172918/series/2.25.444800735698586629295641978511506172918/instances/2.25.555800735698586629295641978511506172918</Value>
			</DicomAttribute>
		</Item>
	</DicomAttribute>
	<DicomAttribute Tag="00081190" VR="UT" Keyword="RetrieveURL">
		<Value number="1">https://dicomweb.myhospital.com/studies/2.25.329800735698586629295641978511506172918</value>
	</DicomAttribute>
</NativeDicomModel>

References

developers, healthcare API

Driving Developer Adoption

As baby boomers age and the world becomes more technologically advanced, it will become ever more critical that the healthcare industry entices more developers into its ranks. I admit, making apps for healthcare isn’t nearly as sexy or killer as, say, a flatulence sound app, but one must wonder – what is behind the mass of developers developing for other verticals besides healthcare? There are a few key things that will help bring about critical mass healthcare must adopt.

1. Standardized APIs

I talked in a previous post about how, in healthcare, that there are so many vendors in the same environment. Different products in different hospitals accomplish similar functions using completely proprietary methods. The healthcare standards, prior to 2013, were not API-driven – meaning, they were on their own “non-industry-standard” protocols (I say this meaning not HTTP traffic) using “non-standard” formats (HL7 pipes and hats, DICOM binary, rather than XML and JSON). In 2013, we have started to see a movement solidify towards the API, with FHIR and DICOMweb. By using standard methods, developers will only have to learn the methods once, and can apply their queries and updates universally*.
(* it would be a dream if this were true, but individual products will come up with proprietary extensions – which is OK, so long as they are intuitive and documented)

2. Intuitive design and easy to use documentation

APIs these days have a certain look and feel, such that developers need only to have a basic understanding of the offering and a starting point, and without documentation, be able to feel out how it works with ease. For example, if I want to query pictures on Facebook, there should be an API call with the path /pictures. If I want to query the timeline, it should be /timeline. APIs should be rewarding, and there should be a quick turnaround. John Musser, a brilliant thought leader in this arena, referenced in a presentation an interesting acronym – “TTFHW”, or, “Time to First Hello World”. Minimizing this value is important.

Intuitive design aside, the API should have easy to navigate documentation. I often equate this to a quote from Homer Simpson, acting as town crier, in which he has two questions regarding the whereabouts of a historical artifact. “I’ve got two questions. One: Where’s the fife? Two: Give me the fife.”. When doing integrations, these are the very same questions I ask. Documentation should be concise. The most fantastic documentation includes interaction, where I can try out calls on the web site.

I have seen some fantastic documentation in the REST arena – both in actual implementations (such as Twilio, Facebook and Twitter APIs) and with documentation “platforms” (such as Apiary.io, and Swagger). By making it easy to discover and use these APIs, we enable developers to connect together applications and data without hardly any effort – allowing them to spend their effort on creativity and innovation.

This sort of documentation is harder to find in healthcare. FHIR has done a noble effort in documenting their API designs. IHE has just revised their web format, which looks great. And, I’ve been working on my own DICOMweb representation.

3. Ready to use implementation

There are some API providers that have taken their offering even further – by offering native libraries that make integrations easy. They do this by creating, in many different languages (such as Java, .Net, PHP, etc), libraries that do these calls. This is also an effective way to provide access to legacy APIs that are SOAP enabled. A great example of a library-enabled API is Twilio – you can drop one of their libraries into your code, connect your tokens, and immediately start sending out text messages using their API and example. It is extremely powerful. If you have an inspired community, you’ll even find that they will even create and share their own libraries – Oauth is an example of this. So, by providing libraries, the TTFHW is reduced further.

In some ways, the legacy healthcare platform has already done this. For example, check out Mirth for HL7. Unfortunately, these packages are too generic to function like what we would expect of the modern API (it is akin to the operating system level, as opposed to the application level). As healthcare becomes enabled by the API, it will evolve.

Parting thoughts

Healthcare is building the APIs. We need the developers to come to them. Driving developer adoption – harnessing their tinkering, their innovation, their transformative power – will advance healthcare. Better care at lower costs is what we need now and into the future.

Uncategorized

What Drives Me

I spent the last couple of days at the I Love APIs 2013 conference. There were fantastic presentations, great and insightful conversations, and hacker-esque food (although no fried chicken and waffles). Listening to and being among those that are as passionate about APIs as me, is very inspirational – and it gave me pause to consider what drives me to do what I love to do.

My passion really compromises of two halves. First of all, after spending a decade cutting my teeth on healthcare information technology has really changed and shaped my perspective. Knowing the state of healthcare – how it is now, and where is it going – is really quite fascinating. For a vertical that truly means the difference between life or death, it boggles my mind that it has been so far behind other industries. It reminds me of a Jerry Seinfeld parable, where he talks about science and seedless watermelons. We have so many different areas that need attention – AIDS, cancer, heart disease, and we have scientists using their time developing a better seedless watermelon. It is staggering. Technologically speaking, while I imagine that there is a time and place for flatulence sound applications, there shouldn’t be much more paramount than healthcare. Health will eventually fail for us all. Healthcare needs the attention, the brunt and the force, of the developer. And the best way to mobilize this force, is with the API.

The API (application programming interface), my other passion, changes and transforms everything it touches. In the last few years, APIs have become more and more intertwined in our daily lives – it has become ubiquitous, and don’t even know it is happening. APIs provide the gateway to information. It is amazing, for me, to watch the bits align, like stars, as information is unlocked to create knowledge. It truly is a beautiful thing. 

These two circles, healthcare IT and the API, where they intersect, is incredibly exciting. I think that we are on the cusp for things that have never been seen before. 

Bonus: If I were to equate my love with the API with another brief TV vignette, it would be an episode of episode of Futurama in which space pilots Fry and Leela attempt a rescue of their colleague Bender by disguising themselves as robots, only to be faced with robot guards meant to prevent humans from entering. To safeguard this, they had a skill testing question. “Which would you rather have – a) a puppy, b) a flower from your sweetie, or c) a large, properly formatted data file?”. Indeed, a large, properly formatted data file is something magical.

healthcare API

The Healthcare API: A Brief History

The evolution of the healthcare API is a peculiar one. The healthcare API world was born in the 1990s, before many other API domains developed, and then followed quite a different evolutionary path than other verticals. Before the rise of the internet, other verticals developed closed software, adding any integration points that fit directly into their vision along the way. As the internet became common place, software became web-based and APIs took hold. It opened up new worlds. The trajectory and momentum started slowly, but with the advent of first SOAP, and then REST, and supporting technologies like OAuth, rose to a fevered pitch. APIs have taken off and transformed forever the ways we live and work. Mashing APIs into dashboards, portals, and ultimately, into apps, have become common place.

Healthcare is different. Before I explain why, there is something critical to understand about this vertical. I often equate it to this example: take any other vertical, like banking. When you look at the banking software stack in any company, it consists of single-sourced core software, and back office software (like HR, payroll, staff scheduling, e-mail, etc.). Restaurants – same thing – a core piece of software, and back-office. Airline industry – same thing. Healthcare, on the other hand, consists of many different functions – patient registration, laboratory systems, radiology scheduling systems, radiology imaging systems, modality software, operating room software, nurse call software, the list goes on and on and on – and these are all provided by individual best of breed vendors. And they all need to talk to each other – otherwise, dire consequences.

So, for this reason, healthcare realized early on that they had to build interoperability first. Vendors came together and agreed on standard ways to communicate between each other. Baked into its very DNA, healthcare standards have taken to heart the need to work in harmony. Two of the core healthcare standards – HL7 and DICOM – have focused on communication between systems – transferring data and triggering workflow between and amongst each provider of software. This level of cooperation is relatively rare. This divergence from the evolution of other APIs happened early on, and has become more pronounced in recent years. 

While healthcare interoperability is clearly a strength, many people – physicians, nurses, patients, IT analysts, governments – all wondered – how is it that one can book a flight to anywhere in the world, share this information instantly to all their friends electronically, and explore the area they are traveling to by navigating virtual streets of continuous photos – and yet, schedule their CT examination on paper-based systems? The focus on interoperability as the common denominator has deprived the systems of what APIs make possible. Rapid growth by the armies of Red Bull guzzling developers have simply not been available. Forays into healthcare of those that built their business on the web API have failed in epic proportions. So – the question we needed to ask ourselves was, what can the healthcare industry learn? How can it benefit from these advancements? How can it transform itself like so many other industries have?

It is beginning to happen. We are seeing a renaissance in the healthcare API. Transformations are occurring – the advancements in API technology in other verticals is moving to this industry. It is happening fast, and it is happening furious. It is an exciting time to be a part of it.