RedwoodJS is the new sensation in full-stack application development. It is highly opinionated with a choice of technologies. This blog is a step by step tutorial on how to use Hasura with Redwood JS and make it double awesome.
Before we move forward, let’s have a small introduction about our two participants Redwood and Hasura.
Redwood JS:
- Redwood is an opinionated, full-stack, serverless web application framework that will allow you to build and deploy JAMstack applications with ease.
Redwood JS uses a lot of the latest bleeding technology and abstracts all the complexity away from the developers. It uses React with Apollo for the frontend and has a lot of code generators like pages, cells, etc which makes development very easy. It also takes care of configuring tests, storybooks, etc out of the box. It uses Prisma for its GraphQL backend and enables you to create quick backends with DashBoard/GUI support. Sounds fascinating? Not just that, it supports out of the box deployment with Netlify, AWS, etc.
In one line, the developer has to write only the styles and business logic. Everything else has been taken care of.
Hasura:
- Instant GraphQL with built-in authorization for your data
Hasura is a futuristic tool that lets you built GraphQL backends instantly from your existing database. It makes creating GraphQL backends as simple as a walk in the park.
The Problem
My equal love for both the tools created a desire for using them together. But Redwood JS was highly opinionated and didn't have any provisions to do it out of the box. This made me explore their codebase and figure out simple steps to start building applications with RedwoodJS + Hasura.
Why Hasura?
If we just focus on frontend parts of Redwood, it gives you literally everything you need, out of the box. It lets you create pages and control the routes manually as well (in case of customization), it lets you create cells along with stories and tests pre-configured. They will support React Native and Electron in the future. So, it's kind of an ideal frontend with all complexity abstracted (similar to Next.js, but more GraphQL focused).
Any frontend engineer who uses redwood would start loving it. But the constraint is, it's highly opinionated and you are obliged to use default integrations and this can be a lot of work. Hasura, on the other hand, is truly a one-stop GraphQL solution with redwood. It can be directly consumed by the Web side (what redwood calls its frontend) and also it supports auth/webhooks etc. Especially when the DB is Postgres, Hasura is pure black magic. Also with Prisma it's again the developer's responsibility to look after scaling/performance etc while Hasura does it out of the box.
Step 1: Build a Hasura GraphQL backend
Refer to this detailed tutorial by Hasura to build a GraphQL backend here. I am using one of their demo apps for this tutorial - https://learn-graphql.demo.hasura.app/console.
This backend gives me a set of queries on Super Heros data. We will use the following query to fetch the required data:
query getSuperHeros {
superhero_aggregate {
nodes {
name
team {
name
}
}
}
}
Step 2: Bootstrap a Redwood JS app
To bootstrap a Redwood JS app, run the following command.
yarn create redwood-app my-redwood-app
This will create a full-stack boilerplate with two subfolders web
and api
. Since we are going to use Hasura for the backend, we will not require this api
folder. Hence, this folder can be deleted.
Step 3: Create a Page
A Page is a screen/route of the app. Each Page gets loaded in a particular route. To create a Page, run the below command:
yarn redwood generate page SuperHero /
This will create a new Page called SuperHero inside the pages
folder and will load the page in the route /
ie: root route. You can replace /
with /custom-route
to load it in the desired path.
The page looks like this:
import { Link, routes } from '@redwoodjs/router'
const SuperHeroPage = () => {
return (
<>
<h1>SuperHeroPage</h1>
<p>
Find me in
<code>./web/src/pages/SuperHeroPage/SuperHeroPage.js</code>
</p>
<p>
My default route is named <code>superHero</code>, link to me with `
<Link to={routes.superHero()}>SuperHero</Link>`
</p>
</>
)
}
export default SuperHeroPage
Step 4: Setup Hasura in RedWoodJS
In the generated Redwood JS files, the src/index.js
file has the following code:
ReactDOM.render(
<FatalErrorBoundary page={FatalErrorPage}>
<RedwoodProvider>
<Routes />
</RedwoodProvider>
</FatalErrorBoundary>,
document.getElementById('redwood-app')
)
Here, the entire App is wrapped inside RedWoodProvider
which is from the redwoodjs
library. Reading through the source code, this provider uses ApolloProvider
underneath.
/**
* Create a GraphQL Client (Apollo) that points to the `apiProxyPath` that's
* specified in `redwood.toml`.
*/
export const createGraphQLClient = (config: GraphQLClientConfig) => {
return new ApolloClient({
uri: `${window.__REDWOOD__API_PROXY_PATH}/graphql`,
cache: new InMemoryCache(),
...config,
})
}
/**
* A GraphQL provider that instantiates a client automatically.
*/
export const GraphQLProvider: React.FC<GraphQLProviderProps> = ({
config = {},
...rest
}) => {
return <ApolloProvider client={createGraphQLClient(config)} {...rest} />
}
and the provider gets the config as props in RedWoodProvider
as below:
/* Modified a bit to shorten the code */
const RedwoodProvider: React.FC<RedwoodProviderProps> = ({
useAuth = window.__REDWOOD__USE_AUTH,
graphQLClientConfig,
children,
...rest
}) => {
return (
<GraphQLProvider config={graphQLClientConfig} {...rest}>
<FlashProvider>{children}</FlashProvider>
</GraphQLProvider>
)
}
Considering the above piece of source code, we can override the existing set up by passing the config in props of RedWoodProvider. The src/index.js
is modified accordingly:
ReactDOM.render(
<FatalErrorBoundary page={FatalErrorPage}>
<RedwoodProvider graphQLClientConfig={{
// URL of your Hasura backend
uri: 'https://learn-graphql.demo.hasura.app/v1/graphql'
}}>
<Routes />
</RedwoodProvider>
</FatalErrorBoundary>,
document.getElementById('redwood-app')
)
Note: You can pass any config supported by Apollo Client through the graphQLClientConfig
props.
Step 5: Generate a Cell
Cells are a declarative approach to data fetching and one of Redwood's signature modes of abstraction.
Cells are auto-generated files, that have scaffolding to fire a GraphQL query and display loading/error states or data based on the response of the query. It reduces the efforts of retyping the boilerplate code. You can create a cell using the following command:
yarn rw g cell SuperHeros
This command will generate a Cell inside the src/components folder along with scaffolded tests and storybooks. The file looks like this:
export const QUERY = gql`
query SuperHerosQuery {
superHeros {
id
}
}
`
export const Loading = () => <div>Loading...</div>
export const Empty = () => <div>Empty</div>
export const Failure = ({ error }) => <div>Error: {error.message}</div>
export const Success = ({ superHeros }) => {
return JSON.stringify(superHeros)
}
Here we will also have to change the query and the components based on our UI/UX requirements. Let’s modify the above file to consume our query:
export const QUERY = gql`
query getSuperHeros {
superhero_aggregate {
nodes {
name
team {
name
}
}
}
}
`
export const Loading = () => <div>Loading...</div>
export const Empty = () => <div>Empty</div>
export const Failure = ({ error }) => <div>Error: {error.message}</div>
export const Success = ({ superhero_aggregate }) => {
return (
<div>
{superhero_aggregate.nodes.map((hero) => (
<li>{hero.name} - {hero.team.name}</li>
))}
</div>
)
}
Now lets import and use it in our pages/SuperHeroPage/SuperHeroPage.js
file as below:
import SuperHerosCell from 'src/components/SuperHerosCell';
const SuperHeroPage = () => {
return (
<>
<h1>SuperHeroPage</h1>
<SuperHerosCell />
</>
)
}
export default SuperHeroPage
Execute the command yarn rw dev
to run the application. The app opens in http://localhost:8910/
by default. The output looks like this:
Tadaa! We have successfully created an app with RedwoodJS and Hasura.
Bonus:
RedWood JS is actively building a lot of tools and to take advantage of all the tools and support, we will also have to modify graphql.config.js
file.
Replace the contents of the file with the below code and you are ready to enjoy all the benefits RedwoodJS offers along with Hasura's superpowers!
module.exports = {
// URL of your Hasura backend
schema: `https://learn-graphql.demo.hasura.app/v1/graphql`,
}
A sample implementation of Hasura + Redwood can be found here. Happy coding
About the author
This blog post was written by Vilva Athiban P B, a JavaScript developer working for Omio as part of the Hasura Technical Writer Program.