Introduction ๐
Now that the authentication is handled (if you missed it, here is the previous episode), we are ready to prepare the connection to the protagonist of this hackathon: Hasura.
The one-liner on their website defines Hasura as:
From your databases to a unified GraphQL API in just one minute
I have used this product for many side projects now and I think it provides that and much more. Especially when working on startups or SaaS offerings, this can speedup your development time noticeably.
The GraphQL API allows you to make complex queries across joined tables in a very efficient manner. Hasura itself can be configured with your JWT provider to add a very granular layer of authorization to each query and mutation.
Actions & Remote Schemas make it easy to communicate with external systems and integrate them in a unified GraphQL API, making it seamless for any client that connects.
Setting up the project ๐ข
For this hackathon, I have decided to use Hasura's Cloud offering, so that my instance is fully managed and auto-scales.
Unfortunately it does not come with a pre-configured PostgreSQL database, so I went with an Heroku Postgres free instance. This instance should be more than enough to serve my requests during development and any users that want to try Dispensa after the hackathon.
Managing migrations & metadata ๐ง
Even though I am working directly on the Hasura Cloud instance, I want to keep track of any changes to the database schema and the metadata produced by changes in permissions etc.
For this reason I added hasura-cli
as a dev dependency to my project, and configured an hasura
directory to handle the output of the console. So now, even though Hasura is running on a managed instance, I can access its console on localhost and have it automatically track any changes. Commit
TypeSript code generation ๐ญ
Another massive advantage of using GraphQL is the availability of tools that generate TypeScript types starting from a GraphQL schema using introspection.
I chose to use GraphQL Code Generator which has served me well in the past, and started configuring it to connect to the Hasura instance. Commit
A couple of tricks that make the generated types even more useful:
- If you send the
X-Hasura-Role
header set touser
with the introspection request, you get back the schema of the database exactly as an user would see it, and not an administrator (who may have access to more fields or hidden tables) Code - If you add the
typed-document-node
plugin to your codegen config, it makes the code even simpler, since the data and variables types are automatically inferred from the query or mutation.
You can see the first generated types in this code.
Making requests through the application ๐ฑ
Now that we have defined strict types for all of our GraphQL operations, we need to execute them from within any components. We need a GraphQL client.
Even though I've never had problems with Apollo, this time I decided to go with urql. It integrates perfectly with the generated types and offers a very simple interface to make queries and mutations.
By creating a custom authentication Exchange
I was able to seamlessly use the authentication token generated previously to authenticate requests made to Hasura. Commit
The result โ
We have an Hasura instance up and running that provides a GraphQL API over our PostgreSQL database. The authorization for different fields is handled using the JWT token generated by Auth0.
The TypeScript types are automatically generated by introspecting the GraphQL schema as a user.
Now my React components can directly perform queries and mutations:
const [{ fetching, error, data }] = useQuery({ query: AnyDocument });
const [{ fetching, error, data}, mutate] = useMutation(AnyDocument);
Next steps โญ๏ธ
Now that everything is ready, we can start adding new tables and client-side code to make Dispensa useful for everyone!
Social
"Dispensa" is the Italian word for "Pantry" and my idea is to make an application to track what food is available in your home to make the experience of buying groceries a bit easier.
As always, you can find me on Twitter and GitHub. The code for this project can be found on its GitHub repository