A Simple, Realtime, Event Driven Architecture with QR Codes
If QR codes were beginning to enter the mainstream before the pandemic, the pandemic itself has ensured the QR code is likely to be an indelible (if not marginally insecure) mainstay in contemporary culture for some time.
The flow can feel somewhat magical. We scan this obscure puzzle of black and white squares, and somehow this converts into an access pass, evidence of having the correct paperwork, a shortcut to an app, or access to marginalia.
Of course, these are ultimately just bits of data, and the most common form these bits take is a web request. Given the right client (essentially all modern phones), scanning this code and requesting the underlying URL can trigger any number of custom behaviors.
A simplified event-driven architecture
Using the right tools, any number of these custom flows simply reproduce this magical experience. Let’s consider the total number of actions needed.
- The user creates content that should be accessible behind a QR code.
- Service creates a QR code representation with instructions on accessing the content.
- Some service exposes the QR code.
- A user scans the QR code.
- Our external service receives a trigger from this flow.
Using Hasura, we can simplify the API for these services. Hasura can store the messages, the associated QR code, and act as the destination for scans.
And for a bonus, we add real-time subscriptions into the mix.
Our simple app
Our app displays a user and an admin view side-by-side. The app displays the created QR codes and the number of times scanned on the right and displays the scannable QR code on the left.
This pattern could work for promotional purposes (total times scanned), check-in purposes (has someone scanned the code?), or even authentication (does this QR code show the pertinent information?).
Building the app
Let’s assemble our list of services:
- A handler to create the QR code
- A handler to read and process the QR code
- A service to persist the content
- A service to show the QR code
We’ll use a simple service handler, Pipedream, to create our actions. These functions could live anywhere, but Pipedream gives us a straightforward context for reasoning about the logic. Using Hasura, we can focus on our domain code and worry less about the individual handlers.
I’ve opted for creating the QR handler as an external service for flexibility purposes, but Hasura REST endpoints could just as easily handle the QR code scans. We have some flexibility around redirects and final behavior with an external handler.
Creating the QR Code
The QR creation code process is:
An event arrives from Hasura (an event trigger when we create new content requests), NodeJs generates a QR code, and we write the data back into Hasura.
Using Hasura subscriptions, we can listen for the write-back and show this as a real-time response to the person generating the code. This pattern results in a high degree of scalability.
Here is the QR code script:
Here is the GraphQL mutation to write the data back into Hasura:
Processing the QR Code
The Pipedream service handler to process the QR code follows a similar pattern. Here is the Pipedream workflow:
The trigger is the QR code HTTP request, the post_request. The ending node code is simply ending the workflow. The bulk of work occurs in the post_request, a simple REST request to a Hasura REST endpoint, which fronts a stored GraphQL mutation.
Orchestrating the events
To connect the event triggers, we need to set the proper coordination in Hasura. We use both event triggers and REST handlers.
We define the event trigger in the events tab.
We persist the REST endpoint to handle the update in the REST tab of the API explorer.
Defining these, we have provided both an endpoint to handle pre-defined behavior at Hasura and a way to trigger behavior from Hasura.
Using the API
We can now invoke the API using our standard GraphQL API with these services in place and our event orchestration defined.
Creating a QR code that can be scanned and incrementing its read value is called using the following mutation.
Note: We provide for the optional client/IP capture here.
If we subscribe to this ID, the process sends us a notification when our service returns the QR code.
Our API is feature is now complete and performs as expected.
Using two services and Hasura, we can replicate any number of custom behaviors driven by QR code interaction.
When tools such as Hasura give us the primitives we need to trigger events and respond to actions, we can simply scaffold what would have been an otherwise complex pattern to emulate. This simplified process enables us to focus on our domain and not on writing queue management, resolvers, or other code that doesn’t add value to our product.
We encourage you to try event-driven workflows, and let us know what you come up with!