Tech stacks are a dime a dozen: everybody has one, and we all think ours is the best! The fact is there are many great tech stacks out there, there’s no right answer when selecting one, and the one your team chose isn’t necessarily any better or worse than the one your top competitor chose.
That said, for our team of TypeScript engineers we found this stack helped us build more than 2x faster (yes, we measured) and we all enjoyed it very much, so I wanted to mention it somewhere!
Overview
Pros
- Engineers can theoretically work on both the front and back-end; they only need to know one language: TypeScript!
- Type safety from your data store to the front-end
- The awesome benefits of GraphQL without the headaches of creating a server from scratch
- Note: if you’ve tried GraphQL before, loved the FE benefits but hated the BE complexity, don’t stop reading yet. Hasura takes away 95% of that difficulty.
- Relay is very opinionated and allows even junior engineers to build a solid, performant FE
Cons
- Relay has a steeper learning curve than many front-end data management options
- Hasura is a paid product
React + Relay
You may know that Facebook built React, but did you know they also built a front-end GraphQL client called Relay (relay.dev)? In fact, if you install the Relay Chrome extension and open your Facebook account, you’ll get a cool view of your own data/state management within the app!
You’re probably familiar with React so I won’t dive into it much here, but I do want to talk a bit about Relay.
Relay is a GraphQL client, similar to Apollo client, but does far more than just help you query data. If you’ve used Redux, a frontend library for centralized state management, that’s the closest analogy I’m aware of.
And Relay is fantastic. I’ve used it in multiple production apps and can’t recommend it highly enough. It’s opinionated, which some engineers don’t like. The benefit being that as long as you don’t completely botch its implementation, you’ll end up with a React app that is:
- Performant
- Data consistent (”you have 2 unread messages” will display “2” correctly everywhere throughout your app, rather than displaying 3 in one place, 2 in another, 4 in another)
- Easy to maintain
- Declarative components + their data requirements
In a nutshell, it makes building a component-based React app easy. When adding a component to your app, you’ll simply create a data fragment
:
const StoryFragment = graphql`
fragment StoryFragment on Story {
title
summary
thumbnail {
url
}
}
`;
This fragment should only include the data that this specific component needs. In this example, we’re creating a newsfeed component that will display multiple stories (and each story has a title, a summary, and a thumbnail image).
Within that component, you guessed it, you use that fragment! The major benefit here is that your component declaratively defined only the data it needed.
Well, we usually have multiple components on a page, right? Right. When a user loads a route in your app, you’ll typically create one single GraphQL query — one single call API call to the network — to get all of the data the components on the page need. Let’s imagine that on the Home page, we’re going to display stories and a few of the user’s settings. We might create a UserSettingsFragment fragment for the component that will be displaying the user’s settings.
Then, when writing our query for this page, we spread these fragments into the query:
const HomepageQuery = graphql`
query HomepageQuery {
...StoryFragment
...UserSettingsFragment
}
`;
There’s a lot of magic under the hood. For example, if you’ve already gotten all the data this query requires (via the user having previously loaded this route or even via the user having loaded other routes that, combined, queried all of the data we need here) no network call will be made. Relay will see that it already has all of the data needed and have React display the Home page immediately without suspending. Voila, you’ve got a data-consistent, performant app!
That’s the 10,000-foot view. You’ll want to dig more deeply into Relay to learn more of its benefits and drawbacks, but from experience I can say that once you’re past the learning curve it’s a great way to build a well-organized, performant, easy-to-maintain React application.
Hasura GraphQL
I’ve talked to quite a few engineers about GraphQL, and a common viewpoint is that it’s too complicated to implement. Digging further, what they mean is that creating the back-end server is complicated; using GraphQL on the front-end is typically a smooth and enjoyable process.
That’s where tools like Hasura come in. There are other options, but I’ve only personally used Hasura in production. I don’t work for them, and I wasn’t a big fan of their dramatically reduced open-source support a few years ago, but overall, it’s an amazing tool to build a GraphQL back-end.
Like Relay, I’d classify it as a declarative way to build. Instead of manually creating GraphQL resolvers, you can simply define what data from your data store should be accessible from a GraphQL API endpoint (they also offer a REST endpoint which can be helpful particularly if you want to update your application to GraphQL piece by piece). There’s RBAC built in: create a user
role, an admin
role, etc. and separately define what data each should have access to.
With Hasura v3, you can quickly have a globally edge-distributed, autoscaling, extremely performant GraphQL API up and running. If you’re a large organization, Apollo Federation, a unified data graph across your various data sources, is built in.
Further Reading
For learning material, I don’t necessarily like to recommend for-profit companies pushing their own products, but Hasura’s talks on YouTube are pretty informative if not a bit hyperbolic:
“GraphQL without Relay is not worth it”
Yes, the title is clickbait, but they do a fairly good job of arguing why this tech stack might be a good option for your team.
Best of luck, give it a try in a personal project and let me know how it goes!