Using Hasura To Build Core Platform
It’s an exciting time to be on the Teaching Strategies platform modernization team. Business demands are changing. Now, we support teachers and educational institutions through more than just our collection of tangible, print curriculum products—our tool kit is expanding and our digital footprint is growing. We’re building a connected ecosystem to support educators and caretakers alike across all facets of child learning.
Historically, our product has been powered by a monolithic legacy application. This application consisted of a single service layer which sat atop a database designed for use cases which have evolved over the last decade. The work that we are doing now is powered by the wealth of data in the monolith, and one of our newly adopted tools has made accessing this data simple.
As our repertoire of products expands, our need for a centralized API that can sit over commonly used data has become even more important. This includes data related to our customers’ organizational units; what products they purchase; how those products are licensed; and the rostering of students, teachers, and classes among other things.
Since we have multiple downstream clients depending on us, the stakes are high. Our goal for the platform is to migrate a subset of the functionality and data out of the monolith while also ensuring that our schema design remains flexible and extensible enough to fit evolving product requirements. The word platform should not be confused with the term platform engineering, which has received significant buzz in the industry recently. Internally, our vision for our platform is for it to function under a hub-and-spoke model. In this model, our entire ecosystem of products would interact with one centralized hub to access common data. Efficiency and security are each as important as reliability in the platform. As a small two-pizza team, we need to move quickly and have the flexibility to explore proofs-of-concept and ideas. To meet these goals, we employed a low-code (or lower-code) approach with respect to our backend using a solution that lowers the amount of coding developers need to do manually.
A few months ago, we adopted a tool called Hasura. Its core value proposition is that it places a production-grade GraphQL API over any database, saving teams months of recurring effort in building, shipping, and maintaining their APIs. I’m happy to report from experience that these claims are true.
Converting GraphQL to SQL
Before a team can convert GraphQL to SQL, they must first undergo a data modeling phase. After this data modeling phase, backend teams must complete some unavoidable tasks. One of these tasks is to build an API that allows clients to read and mutate data. This is something Hasura provides instantly, freeing us engineers from the toil of writing basic CRUD APIs. Hasura compiles a GraphQL string into a GraphQL abstract syntax tree (AST), which is then compiled into a SQL AST. This abstraction lets us do powerful things, like using a bulk GraphQL mutation to transactionally and atomically insert or update data. GraphQL provides a flexible way for us to query our data in the form of a graph. This means that as engineers, we get to focus more on business logic.
API Federation, Aggregation, and Composition
Hasura’s support for remote GraphQL schemas enables us to design a service-oriented architecture in which Hasura functions as an API federation/composition layer and delegates to other Go microservices that provide specialized business logic for a particular domain. This ability to federate doesn’t just end at remote GraphQL schemas—Hasura also supports remote data sources, opening up multiple possibilities for how we traverse through the graph and explore relationships in our data, including how we might join remote databases to each other or to remote APIs (REST or GraphQL).
In greenfield projects, teams typically spend months crafting a fully-featured API, a common language that all clients can share. With Hasura, we get this in seconds and can spend that saved time writing automated tests or implementing business logic.
Hasura’s Dashboard/Console improves developers’ experience. Using the dashboard, developers can craft experimental GraphQL queries and mutations against our local instance of Hasura. The embedded GraphiQL playground makes it a breeze for new developers who are joining the team to introspect and discover our API. We can also visualize our database schema in the UI directly and make changes to it with a few clicks of a mouse (if needed), which in turn generates source-controlled SQL migration scripts much like you’d find in other web frameworks.
No production-ready system would be complete without observability, or the ability to gauge a system’s internal state based on external output, usually in the form of logs, traces, and metrics. For each database operation, Hasura ships logs and traces to our New Relic telemetry platform, allowing our team to identify bottlenecks and receive early alerts of unexpected or degraded system performance.
Hasura’s role-based authentication support allows us to check an additional box on our production-readiness checklist. Clients with certain roles may have permission to execute specific GraphQL API operations or access specific database tables. Hasura can derive a client’s role in one of two ways: either the client will send Hasura a JWT auth header (which includes a signature containing claims providing the client’s role), or Hasura will refer to an external webhook which, in turn, makes the auth decision . Without Hasura, we would need to write and maintain the code to perform all of this work.
Change Data Capture
The last way Hasura enables us to build our core platform is through change data capture (CDC), or the process of tracking changes to a database. Hasura provides this in the form of event triggers, which function like a transactional outbox system. When a record is inserted, updated, or deleted, a bona fide database trigger will record this event in a table. Then, a reliable process in Hasura will guarantee that the event is delivered at least once to its intended webhook (one of our microservices). This is tremendously useful for our team since we need to sync data from our new database to the older, legacy database.
There are many tools we could use for CDC, such as AWS SQS or Kafka (some of which we use downstream to integrate our platform with individual products), but having this feature baked into Hasura makes the process simpler, as it frees us from having to provision any new infrastructure or deal with the complexities of bringing on additional tools.
For the Teaching Strategies platform modernization team, it’s still early days. As we continue to improve our product, we may look to Hasura for finer-grained authorization and consider adopting attribute-based access control (ABAC) over the coarser role-based access control (RBAC). We will also investigate real-time streams so other systems, such as users’ browsers, can see data changes as fast as possible. Using the functionality and features of Hasura outlined above, our team is well on the way to building a strong core platform. As we work toward our goals, this tool will allow us to reach our milestones faster, helping us deliver even more support for educators and caregivers. Interestingly, Hasura is a portmanteau of the programing language Haskell and the Sanskrit word asura—or demon. As far as tech choices go, this one feels much more like a guardian angel.
About the Author
Kevin is a software engineer closing on a decade of experience ranging from government contracts, ride-hailing, virtual reality, and two-sided childcare marketplaces. He’s currently working with others on Teaching Strategies’ newly-chartered Platform team. His current interest is on the correctness of distributed workflows in service-oriented architectures. Outside of work, you can find him enjoying tennis, CrossFit, and the occasional powder day.