When and how should resource validation happen in a FHIR-based information exchange?
Those familiar with the FHIR specification will know that FHIR provides several ways to validate whether a resource conforms to a FHIR Structure Definition, whether that StructureDefinition is a profile or a base resource definition. If the resource is in XML, the syntax can be validated against FHIR’s XSD. FHIR also provides a more in-depth procedural validator that checks additional factors, such as invariants. The procedural validator has its own limitations, but for the purpose of argument, let’s assume the validator can determine if a resource conforms to a specific StructureDefinition.
In terms of how validation happens within FHIR workflows, we need to distinguish two use cases. When a client requests a resource of a particular type, or requests resources conforming to a particular profile using profile search, that client may use validation to be sure returned resource is indeed what it asked for. This is the solicited case. If a resource is being sent to a server as a create or update, the server may want to assure that the resource conforms to one of the profiles supported by the server, as declared in its conformance statement. This is the unsolicited case. The difference is, in the solicited case, the client knows what StructureDefinition the resource ought to comply to. In the unsolicited case, the server does not have that information.
The solicited case is, on the surface, rather straightforward. When the client receives the requested the resource, it can call the appropriate validator and determine whether the returned resource conforms to the expected StructureDefinition. It the client did a profile search, it knows exactly which profile to check the resource against.
The use of includes and reverse includes in searches, however, complicates the issue. One cannot specify a profile those searches, only the base resource type, and therefore, all that is known about the resources returned as part of the include is the base resource type. The client does not know that the included resources conform to any profile the client supports, and furthermore, the client does not necessarily know which profile(s) to check against. This is the same situation as in the unsolicited case.
The unsolicited case is more complicated. The server may want to validate that the resource conforms to one of its supported profiles, as declared in its conformance statement. The problem is, which profile should the server use to validate the profile?
Sometimes the answer is clear. If the server only supports one profile on Medication, for example, and it has received a Medication resource, then clearly it knows to validate the resource, since there is only one Medication profile. It is not always so simple. On certain resources like Condition or Observation, there may be many profiles. Then, the choice of which profile to validate against is not so clear.
The brain-dead approach would be for the server to iterate through its library of profiles until it finds one that validates the instance. This approach assures that, in the event of a non-conforming resource, every profile based on the given resource type will be tested before the incoming resource can be rejected. If there are 100 different Observation profiles, that might take a long, long time. Ugly!
An alternative would be for the receiving system to “pop open the hood” on the resource, dig out the primary code, and try to determine which profile to validate against, based on that code. An observation might have a LOINC code, for example, that indicates it is a hematocrit score, and that may guide the server to pick the hematocrit profile to validate that resource. While this might work, it (1) requires processing the body of the resource before it is validated, which is exactly what validation tries to avoid, and (2) requires the server has to have a mapping that connects codes and profiles, which means extra work and maintenance.
The third (and best) alternative in the unsolicited case is for every incoming resource to declare which profile should be used to validate it. There is a metadata attribute, Resource.meta.profile, where the profile declaration can be placed. Then, when receiving the resource, the receiving systems only needs to look at the declared meta.profiles, and test against those. At least one element of meta.profile must name a profile that the receiver supports, otherwise the resource can be immediately rejected, without further ado.
But… there is a catch. In FHIR DSTU 2, resources are not required to fill in the meta.profile slot. In my opinion, for all the reasons discussed above, the information sender should always declare which profile(s) the payload should be validated against, naming one or more of the profiles supported by the information receiver. This simple expedient allows the receiver to immediately address validation, without iterating through multiple profiles, or guessing which profile(s) to test. This requirement could be stated in an implementation guide, or it could be done with profiles, by changing the cardinality of meta.resource from [0..] to [1..].
Should it become standard practice in the FHIR community for every resource to explicitly declare which profile it should be validated against?