Have you ever feel stuck because you want/need to set up a proper backend for your awesome web application, but you no longer have the time, the knowledge or the energy to dive into programming one?
If the answer is yes... this article might find you well.
Having dedicated +8 years in Frontend Development I had to confess there was a time I flirt with the Backend's world π± for 3 major reasons:
- I needed a Rest API for my clients and I didn't have the money to pay another developer
- More free time than now.
- Young and adventurous.
So I spent tons of hours learning how to do a decent backend app, thanks to Node.js it was easy to do it in the same JS I use every day, I learned how to do a proper rest API service, how to model data, querying databases with complex joins, even going to the NoSQL world that was a hot topic at the moment.
And don't get my wrong, those BE apps worked just fine and I learned a lot by doing them (Mostly help me be able to talk the same language as my BE's counterparts and understand each other). But, my expertise wasn't there, I'm a decently good FE developer and I know my skills and my limits, I wasn't enjoying doing migrations, setting up docker containers, and looking for hundreds of logs trying to find an error... was frustrating for me, it was just, not my league.
The Idea
So I started wondering, what if there is a service, that allows you to have your data tables on the cloud, easy to set up, easy to declare rest API endpoints, just click and BOOM, all ready π€?
A colleague whispered "Firebase" from the darkness. That's it! That's what I need right? A BaaS (a.k.a Backend as a Service) where I have a pretty little dashboard to add data and manage the database.
My life was solved, I was going to be able to focus just on the Frontend part of my own DIY Electronics Stock App π to organize all my crazy electronics and circuit components without worrying about the backend. But there was a catch.
The nature of my project and the backend logic I needed, wasn't a valid use case for a NoSQL database (To see the difference between both approaches, this is a very nice article). My data was structured, I wanted to join from products to projects, to stores, without doing some strange quirks on my client codebase.
So I started looking again.
Amazon Web Services
Another colleague whispered: "Go Serverless". I decided to try a little PoC using AWS Lambda Functions (just awesome Node.js functions) to retrieve data from their relational database service and deliver them trough their awesome API Gateway.
It was all all sunshine and rainbows until they email a juicy receipt... too much money for my crappy little serverless app.
GraphQL
But wait?... GraphQL is not a BaaS, it is not even a database technology, it's a query language, another way to get your data from a service rather a traditional REST API.
Yup, but I didn't know it until I did a small PoC with Apollo and GraphQL on my local, in the end, I was doing the same thing as before, just an overall better approach π€¦πΌββοΈ.
At that moment I had only 1 request, "Find a decent SQL BaaS and If I might be a little picky, that comes with GraphQL".
It was harder than I expected, search terms like "SQL Alternative to Firebase", "GraphQL BaaS" and even "Please God, send me an answer " didn't throw any good result, until...
Was 3 am when I saw in a tech forum a guy answering the same question I had, proposing to give a chance to something called Hasura, a Realtime GraphQL on Postgres Engine done by Rajoshi Ghosh & Tanmai Gopal.
Never heard of it before, doesn't ring any bell, but let's give it a try...
The answer
I was impressed, let me show you with a GIF how fast was to deploy an instance of Hasura in Heroku from here.
In the beginning, it kinda feels like a modern version of phpMyAdmin but cooler π, and the API was ready to go just calling https://my-awesome-diy-stuff.herokuapp.com/v1/graphql we just need to give it some data to return first.
So let's create a table called Products that will hold the Postgres Schema for my DIY electronics, you can do the following tutorial with your own tables, data, and schema, but I strongly suggest you follow the same data for the sake of learning how it works first.
product: {
id, name, url, media, qty, price;
}
Because data structures in Hasura follow Postgres schemas, for each column you can select the data type (int, float, numeric, bool, string, etc.) from supported PostgreSQL types available here.
For id, you can use any type of data you want, but I suggest you use UUID with the gen_random_uuid()function which generates a sequence of lower-case hexadecimal digits separated by hyphens, specifically a group of 8 digits followed by three groups of 4 digits followed by a group of 12 digits, for a total of 32 digits representing the 128 bits, I guaranty this will create a unique id for each of your products.
Also, it has a nice feature to add Frequently used columns
such as created_at
and updated_at
that updates automatically every time you edit your product. Make sure the primary key is id and click Add Table.
Queries and Mutations
Next thing, let's create some data, you have 2 options here:
- Insert rows manually on the
Data Tab
. - Or the fun way which involves using Graphql mutations on the
GraphiQL tab
.
Pretty obvious we are going to go for the second option, so let's click the tab and see what is there:
You can notice 2 things, first your GraphQL endpoint to use. for your API or just playing around with your Apollo client. The second one is the explorer along with GraphiQL UI. This is a pretty awesome tool to play around with graphql, test queries, and mutations and handle your data within the Hasura console.
It also autocompletes a lot of things, so even if your not an expert on graphql query syntax (like me at the beginning) this tool is a must-have.
If we want to create a few new products we will need to do a Mutation which exactly as it sounds, will modify the data on your database, in this case, Insert new data. In the Explorer sidebar at the very bottom, there is a selector that says Add new Query, just select Mutation and click the add button and. you will see something similar to this:
You can see at the right side that Hasura already creates you a wrapper for the mutation structure, let's give it a significant name and add what operation we will do inside, if you click the desire mutation on the left side (insert_products) you will see it opens an accordion with all the properties available (columns).
You will notice also that inside of the method insert_products we have a property call returning, this tells the mutation what properties should return after inserting a new row. For now, select them all and play the big button on top.
At the third column of the GraphiQL you will get the response of the operation in a JSON format, so if you get this is because everything went fine (if not, it will return you also the errors in a very self-explanatory way)
{
"data": {
"insert_products": {
"returning": [
{
"media": "https://res.cloudinary.com/alvarosaburido/image/upload/v1585500435/smidae/products/photon_particle_1_g4qywu.png",
"name": "Particle Photon",
"url": "https://docs.particle.io/photon",
"id": "31354e12-18e8-4d9a-b30f-1b51b82fd3b8",
"price": 19,
"qty": 1,
"updated_at": "2020-04-16T16:52:24.581014+00:00",
"created_at": "2020-04-16T16:52:24.581014+00:00"
}
]
}
}
}
Awesome, we have our very first product! So first baby-step done, now we can insert products in a better way. using Query Variables.
In our mutation, we will replace the object wrapper for a function that will receive the query variable as a parameter, is important to check what Type that query object should be, in our case is an array of products_insert_input
. Also notice that instead of passing the object in the function insert_products
we pass a reference of the query variable like this:
mutation InsertProductsMutation($products: [products_insert_input!]!) {
insert_products(objects: $products) {
returning {
media
name
url
id
price
qty
updated_at
url
created_at
}
}
}
The rest stays pretty much the same. Now, for it to work, you will need to pass a JSON object with the query variables holding your data, we will insert 2 new products inside of an array:
{
"products": [
{
"media": "https://store-cdn.arduino.cc/uni/catalog/product/cache/1/image/1040x660/604a3538c15e081937dbfbd20aa60aad/A/0/A000005_featured_2.jpg",
"name": "Arduino Nano",
"price": 20.0,
"qty": 5,
"url": "https://store.arduino.cc/arduino-nano"
},
{
"media": "https://www.zurich.ibm.com/images/news/waspmote.png",
"name": "Waspmote",
"price": 10000000,
"qty": 1,
"url": "https://www.cooking-hacks.com/documentation/tutorials/waspmote.html"
}
]
}
If you click the play button again, you will receive a confirmation of success, let's check the rows in the Data tab
to see that everything is going smoothly:
So now that we have data in place, let's use the same approach trough the GraphiQL explorer. Here is where GraphQL does it's magic, it's incredibly easy to do if you still not sure how does Graphql work or what are the benefits of it, you can check this amazing post by Frank Kilkelly GraphQL vs. REST, Explained Using Pizza.
Let's go to the GraphiQL Tab
once again and. in the bottom left, select in the dropdown Add query. In a similar way as the Mutations, now you will see on the panel left a query structure with some options, select all the properties you want to have in your query response and you will notice that a query object has been created in the right side, something similar to this:
query ProductsQuery {
products {
media
id
name
price
qty
updated_at
url
created_at
}
}
If you hit play you will get a JSON with all your products containing the properties you asked for, imagine now we are doing a query to fill a product selection dropdown input in your web application, you probably don't need anything else but the id and the name, so create a query like this:
query MyQuery {
products {
id
name
}
}
You will get:
{
"data": {
"products": [
{
"id": "31354e12-18e8-4d9a-b30f-1b51b82fd3b8",
"name": "Particle Photon"
},
{
"id": "6c2090a7-2d60-4e3a-86a3-33ae26330be7",
"name": "Arduino Nano"
},
{
"id": "a1b40581-5e5f-4030-9f50-aa6abb059fd0",
"name": "Waspmote"
}
]
}
}
Querying like a sir
Now that we totally nailed the 'Hello world' of queries, let's do something more advanced, using filters and sorting the elements that the query return.
Our boss now asked us to do a query that returns all products of less than 30 β¬ in alphabetical order, the query would look something like this:
query CheapProductsQuery {
products(order_by: {name: asc}, where: {price: {_lt: 30}}) {
id
name
price
}
}
If you pass an order_by
object with the property and the direction (ascendent or descendent) the query will return the products in alphabetical order. The other part is the where
object, containing the property you put the condition on and the operator, in this case we want to filter for all products with prices below 30 euros (not included) so se use _lt: 30
. For other operators, you can check here.
Click play and BAM! We got our sexy data:
{
"data": {
"products": [
{
"id": "6c2090a7-2d60-4e3a-86a3-33ae26330be7",
"name": "Arduino Nano",
"price": 20
},
{
"id": "31354e12-18e8-4d9a-b30f-1b51b82fd3b8",
"name": "Particle Photon",
"price": 19
}
]
}
}
Next Steps
That is pretty much it, as a little exercise to practice further, try to do the same query as before but using the Query variables approach as we did in the mutations π. Share your result the result or ask any doubt you have in the comments below.
In the next article, I will show you how to query your Hasura data from a Vue.js based client. Until next time.
Keep awesome!.
Top comments (0)