This pattern was originally defined in the book Enterprise Integration Patterns - Claim Check. In a nutshell, it is storing message data in a persistent store and passing a reference to the persisted data in the message payload.
😱 If you have the following issues:
- Large payloads
- Carrying message data through components only to be used downstream
- Your message system has hard limits on the size of messages
- Performance degradation
- Maybe you are required to encrypt and decrypt payloads which would be CPU intensive
✅ Claim Check pattern addresses:
- Reduction of message payload volume without removing content completely
- Storing message data in persistent storage
- Pass a Claim Check to downstream components which can use it to retrieve the stored information
Problem with large payloads
Large messages can become increasingly complex, noisy and difficult to debug. It's also increasing the size of payloads and slowing down your messaging. Ideally, the data we put in a message is fully utilised otherwise it is either waste or there is an implicit coupling between services which might not be wanted either.
If we store the message payload and add a reference to it in the message body this allows other components to retrieve it and process what it needs. Our message is now lightweight and concise when sent over the network.
Often, storage will cost less than CPU processing time so cost shouldn't be an issue but you should delete the message after consuming it to prevent them from building up over time.
A side effect of this is it gives control to the consuming component on how to process the message (e.g. streaming in a large payload etc).
Carrying message data
Similar to solving the large payload problem, another problem is if a message travels downstream through components to be processed. This means you might be carrying payload data over the network which is not used by a component. Another drawback is the message contains data with dependencies from other components. Some of the problems this can cause are:
- Unable to modify the message because it is tied to a dependency outside of your component
- Difficult to know which component is using which part of the payload
- The more responsibilities a message has the less clear its purpose is and difficult to maintain
A solution is to refactor your messages which have multiple responsibilities.
You can also use the Claim Check pattern to allow these components to process only parts of the message they need and remove the need for all the data to be carried over the network.
Another solution is to use Claim Check and Enricher patterns. This is analogous to a "luggage check" process e.g. when you travel, you do not carry all your luggage with you. Instead, you check-in your luggage at the airport and pick it back up at your destination. With the Enricher pattern, you might have a separate component which inflates the data before passing it to the consuming component.
You might have a scenario where a message containing sensitive information (or PII) crosses the boundary of your internal platform to be processed by an external component. In this scenario, we can strip out sensitive data leaving our system by retrieving the stored message data and filtering it into a new message and passing that out of the system or trusted boundary (this is called the Content Filter pattern.
Using the Claim Check pattern, you can apply stricter access control to the payload since it is offloaded to an external resource.
Incoming message validation
Continuing the above example, when the external system responds with a message, we then want to build or inflate the message again for internal processing. A scenario for this could be to add in the data removed by a filter or add in extra data such as IDs which the external system does not have (this is called the Content Enricher pattern).
- Content Enricher
- Content Filter