Posts Tagged ‘API Design’
I’ve been reviewing the FHIR (Fast Healthcare Interoperability Resources, http://www.hl7.org/fhir) specification and they have an interesting concept called a compartment. Per the spec:
Each resource may belong to one or more logical compartments. A compartment is a logical grouping of resources which share a common property. Compartments have two principal roles:
- Function as an access mechanism for finding a set of related resources quickly
- Provide a definitional basis for applying access control to resources quickly
Let’s look at these statements one at a time. First, the component concept provides an access mechanism for finding related resources. One very common compartment in the specification is Patient. Other resources, like Condition, clearly have a relationship with Patient. So, if I want to find all conditions that a particular patient has, I actually have two paths for doing this.
- GET /Patient/[id]/Condition
- GET /Condition/?patient=[id]
[id] is the unique identifier in question. In this case, both of these requests should return the same thing. But it’s not quite that simple. Take another resource, Communication, which deals with secure messages sent as part of patient care. In this case, we have:
- GET /Patient/[id]/Communication
- GET /Communication/?subject=[id]
- GET /Communication/?sender=[id]
- GET /Communication/?recipient=[id]
The first example returns any communication that involves the identified patient, whether to, from, or about. The Communication specific inquiries only allow for inquiry by the attribute of the resource where a Patient identifier can be specified. It just so happens that in the earlier case, the relationship within Condition is represented in a patient attribute.
Independent of whether you think this is a good or bad thing, this approach where there are two ways of getting to the same resources creates a decision point for the organization. In a large enterprise, it’s entirely possible that the implementation for different resources may be handled by different teams. With two (or more) different ways of doing this, it creates the risk of two (or more) different implementations. It also creates a situation where a resource that can be a compartment needs to make sure that any time a new related resource is defined and implemented, they also need to make a modification to provide the compartment-based inquiry. Once again, if this is a separate team, this means coordination. Anyone who’s worked in an enterprise knows that the more teams that get involved, the more challenging it becomes.
These are not insurmountable difficulties by any stretch of the imagination. In the case of the implementation, the compartment resource should simply act like a façade and make the appropriate calls to the resource (i.e. the implementation of the first URL in the examples above simply turns around and makes the call(s) below them to complete the inquiry, such as Patient calling Condition, or Patient calling Communication). In the case of the coordination, that’s a matter of education and oversight to make sure it happens. The greater risk is probably that too many things get defined as a sub-structure within the compartment resource, rather than defined as standalone resources. This can be avoided by recognizing when a proposed resource has multiple compartments. Take the following requests:
- GET /Practitioner/[id]/Condition
- GET /Condition?asserter=[id]
These inquiry would give me a collection of all conditions that a particular practitioner has ever dealt with. If Condition wasn’t a standalone resource, and instead a sub-structure within Patient, how would I go about forming this query? It can be done, but it’s probably not going to look as simple as what is shown above. This is where I see the hidden strength of this compartment concept. By recognizing where we can have multiple ways of organizing a particular collection of data and traversing relationships, we can then make good design decisions on what our resources should be.
Finally, FHIR also mentions that the compartment concept can also play a role in access control. I haven’t dug into this one as much, but I think it may have some potential. The challenge lies with data that really has multiple owners. As a patient, I may want to use an OAuth model to grant access to my health records to a mobile app I’ve downloaded. My doctor may want to do the same thing for an application he or she uses as part of my care. The compartment approach could give independent access paths for each of these channels with their own policies. Again, I need to give this one more thought, but I can definitely understand why HL7 put the bullet point about access control in their specification.
What are your thoughts about this notion of compartments? Good thing? Bad thing? Have you implemented a similar approach? What were the pros and cons of it? Let’s start the discussion.
I had an interesting conversation with some colleagues around resource design that I thought would be helpful to share.
The starting point was a simple question:
Should price generation be a HTTP POST or HTTP GET?
There’s solid reasoning for either of them. Let’s start with HTTP GET.
From a consumer’s perspective, a GET probably seems very intuitive. For how most people think about prices, it’s static information, so why wouldn’t it just be an attribute included on a GET of some other resource, like a Product, right?
For the purposes of this conversation, however, price is something that is computed at the time of the request. In other words, some supporting static information exists (like list price), but the actual “price” charged to the customer is dependent on other contextual parameters. Cases where this exists are the end price you pay at Amazon after taking into account shipping preferences, account status (e.g. Prime member?) or the price you pay when you buy a car. These prices are determined on the fly and may only be good for a limited amount of time, because the contextual information is subject to change. Hopefully, you can also see that “price” is actually a complicated piece of information.
Is HTTP POST beginning to sound better? Where this fits very well is that the “Price” is really a custom resource generated for that particular context. The customer, even though they may use the phrase “get me a price,” is really saying, “generate me a quote.” At this point, we’re creating a new resource.
But there’s one more thing. What if price calculation is expensive? If I make this a POST and generate this every time, won’t my costs go through the roof? Well, they don’t have to. There’s no reason that a subsequent POST with the same data can’t return a resource from cache in this scenario. In reality, you are probably updating the expiration date of the resource, so POST still makes sense. Furthermore, if you provide a unique ID for the calculated price resource, HTTP GET can be used to retrieve it again, it just shouldn’t update the expiration policy.
So, out of this, I came up with the following guiding principles on deciding whether calculated/derived data should be its own resource:
- Can the data stand on its own? That’s always a question for any resource.
- Does the calculation require contextual data from the consumer to perform the calculation, or are all the parameters already part of the potential parent resource?
- Is there value in keeping the calculated data around for some time to avoid re-calculation?
Hopefully these guiding principles will help you out. If you have other suggestions on factors that help this design decision, please feel free to share in comments or via your own blog post.