All Articles

4 min read • By Kyle Truong • Published 22 May 2020

A First Look at Using Hasura

Using graphql is supposed to make things easier, so why doesn’t it feel that way?

What drew me into graphql was the simplicity in the interfaces and the flexibility of field-level resolvers. By defining types for common data objects my frontend would be able to extract, with precision, what it needed. And later down the road I could request a different combination of objects without re-writing the backend because resolvers were a “set it and forget it” kind of thing. What ended up happening was I spent far more time writing these resolvers than I would have if I just resorted to writing REST APIs. Suddenly, every property of every object needed to be accounted for with types and resolvers. Relationships, or edges, required more complex logic and would often have to account for n + 1 query problems. This was a lot more work than dumping a generic blob of json per endpoint.

But graphql was still “better”. Although it took more work to setup it was more robust, for the exact reasons mentioned above. I didn’t want to go back to writing REST APIs but writing graphql-based backends this way wasn’t ideal either. And then I learned about Hasura from this thread:

https://news.ycombinator.com/item?id=22786853

Hasura sits between your server and database and acts as a magical service compiling your graphql requests into SQL statements. The act of simply connecting Hasura to your database will automatically spin up graphql types and resolvers to query and mutate every table in your database. It also conveniently maps the relationships between your tables into appropriate graphql relationships/edges. Through the admin interface you can create and edit tables, rows, data, relationships, permissions, and more. And if you still want more customization it allows you to abstract the graphql resolver portion away into your own service you can invoke by dispatching an action, like redux actions or some other event-like system.

It’s crazy good. It makes me wonder how they can accomplish so much and give it away for free (how awesome open-sourced software is never gets old). It’s crazier how people aren’t using this. I never want to write another API, REST or GraphQL based, by hand again.

Table relationships are essentially abstracted to object relationships and array relationships. Object relations are one-to-one. One table links to another by way of foreign key. Array relations also map by foreign keys but are used to represent a one-to-many relationship. Both of these can be mixed and matched between tables to represent a many-to-many relationship. All of these relationships can be created and modified in the UI. All of these relationships are traversable by graphql. You can query and mutate data at the level of SQL through both a graphql interface and a web UI interface.

Hasure web UI example

export const promotionsFetchEpic = (
  action$: ActionsObservable<PayloadAction>,
  state$: StateObservable<StoreState>,
): Observable<PayloadAction> =>
  action$.pipe(
    filter((action) => action.type === appDataFetchSuccess.toString()),
    asyncRequest(
      promotionsFetchStart.toString(),
      promotionsFetchSuccess.toString(),
      promotionsFetchError.toString(),
      (action: PayloadAction) => {
        const shopOrgin = selectShopOrigin(state$.value);

        return hasuraGraphqlRequest(
          `
          query PromotionsFetch {
            promotion(where: {shop_origin: {_eq: "${shopOrgin}"}}) {
                promotion_id
                promotion_type

                countdown_promotion {
                  countdown_timer_message
                  countdown_timer_message_font_size
                  ...
                }

                text_promotion {
                  custom_message
                  ...
                }

                promotion_products {
                  product_id
                  promotion_id
                  product {
                    ...
                  }
                }
              }
            }
        `,
          {},
          selectJwt(state$.value),
        );
      },
    ),
  );

I still find it unbelievable, how Hasura makes it both so incredibly easy to use while giving such granular control over your SQL database.