Add business logic to Supabase or Hasura
Tags: graphql, beginners, tutorial, webdev
Published: 2022-10-05 18:37:24

HTTP gateways are incredibly interesting. For instance, you can easily create a [Hyperlambda](https://aista.com/hyperlambda/) HTTP gateway that adds business logic to Supabase or Hasura, to intercept the original endpoint, and inject business logic before or after the invocation to your originally wrapped GraphQL or PostgREST endpoint. This has use cases such as for instance.

* Add business logic to GraphQL endpoints, such as those exposed by [Hasura](https://hasura.io/)
* Add business logic to PostgREST endpoints, such as those exposed by [Supabase](https://supabase.com/)
* Add HTTP caching to optimise your original HTTP endpoint
* Apply authorisation to endpoints originally not having authorisation
* Log error invocations
* Etc, etc, etc

With for instance Hasura, the preferred method of implementing business logic is one of the following according to their FAQ.

* Event Triggers
* REST APIs
* GraphQL APIs
* Stored procedures or functions in your database

Ignoring event triggers and stored procedures, plus functions, due to that these methods arguably are the very definition of bad architecture resulting in the “big ball of mud” – This leaves us with GraphQL APIs and REST APIs. Since the purpose of Hasura is to simplify things for you, the GraphQL API and REST APIs gives you little or nothing. However, there exists a 5th method that is not documented at Hasura’s website; **HTTP gateways**!

This allows you to intercept the original HTTP endpoint, forward the payload to _“whatever”_, and inject your own business logic either before or after invoking the Hasura GraphQL endpoint, or Supabase PostgREST endpoint. Some use cases for this might be for instance.

* Validate data before allowing the GraphQL endpoint to be invoked
* Send emails as some GraphQL endpoint or PostgREST endpoint is invoked
* Apply logging if the GraphQL or PostgREST endpoint invocation fails
* Apply either server side cache, or HTTP cache for your endpoints, to optimise execution of slow queries
* Etc, etc, etc

The by far easiest way to achieve such a thing, is to create your HTTP gateway using Hyperlambda. In the following video I am demonstrating the idea. Notice, you can find the code I am creating in the video at the bottom of this article.

{% embed https://www.youtube.com/watch?v=P9jgVwN_HX4 %}

This allows you to easily add business logic to Supabase or Hasura, through interceptors, resulting in that you can now easily _“inject”_ business logic, both before and after invoking your original endpoint. No need for Supabase’s _“edge functions”_, learn TypeScript, or NodeJS. No need to add stored procedures to your database to put business logic into it. No need for slow HTTP REST endpoints invoked by your Hasura GraphQL implementation as _“extension methods”_, etc, etc, etc. And, this allows you to **validate data** before passing it into either Supabase as PostgREST arguments, or Hasura as a GraphQL payload.

As an additional bonus, this allows you to _“transform”_ the weird (at best) HTTP POST requirements Hasura forces you to apply due to GraphQL typically forces you to implement your read invocations as POST invocations. So you can turn your GET GraphQL endpoints into `GET` endpoints, resulting in better semantics for your GraphQL endpoints, better obeying by the HTTP standard.

## Frontend CRUD generator wrapping your Hasura or Supabase project

In addition, if you create a strongly typed Hyperlambda endpoint, you’re also able to generate meta data on your GraphQL endpoints, creating CRUD endpoints, that you can all of a sudden generate an Angular frontend for using [Aista](https://aista.com/). To understand what I’m talking about, realise the following is easily achievable for you using Aista for both your Hasura and your PostgREST servers, due to Hyperlambda’s ability to use meta data to generate Angular frontends.

![Automatically generate frontends for Supabase and Hasura](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x9sh725ir0af9jznriim.jpeg)

I will go into depths of the last point in later articles, but realise that as long as you can correctly “type declare” your Hyperlambda endpoints, Aista can automatically generate a CRUD frontend for you. You can try one such frontend [here](https://sakila.aista.com/). So all of a sudden, you can now generate frontends 100% automatically for your Supabase and Hasura projects.

Of course, at this point the natural question becomes as follows; If you’re using Hyperlambda and Aista as an HTTP gateway, and you’re creating strongly typed HTTP APIs, wrapping your existing Hasura and Supabase projects, and you’re applying all your business logic in Hyperlambda – Why not switch entirely to the automatically generated CRUD API that Magic generates? To understand the latter, please read up more about how Aista [automatically generates CRUD APIs for you](https://aista.com/crud-api-generator/), wrapping your existing or a new database.

However, sometimes when you’re stuck in _“legacy land”_, extreme measures needs to be applied to slowly change over time. And for a period, the above Hyperlambda HTTP Gateway solution might just be exactly what you need, to slowly transfer from legacy GraphQL code or legacy PostgREST code, to a modern and scalable stack such as Hyperlambda.

## Code

Below you can find the code I use in the above YouTube video.

**gateway-original-1.post.hl**

```
.arguments
   name:string
auth.ticket.verify:root
strings.concat
   .:"Hello "
   get-value:x:@.arguments/*/name
unwrap:x:+/*
return
   result:x:@strings.concat
```

**gateway-original-2.post.hl**

```
.arguments
   name:string
strings.concat
   .:"Holla there "
   get-value:x:@.arguments/*/name
unwrap:x:+/*
return
   result:x:@strings.concat
```

**gateway-simple.post.hl**

```
.arguments:*

// Add all arguments into [http.post] invocation!
add:x:./*/http.post/*/payload
   get-nodes:x:@.arguments/*
validators.string:x:@.arguments/*/name
   min:5
   max:10

// Invoking original endpoint we are now wrapping.
http.post:"https://tiger-polterguy.gb.aista.com/magic/modules/faq/gateway-original-2"
   convert:true
   payload

if
   and
      mte:x:@http.post
         .:int:200
      lt:x:@http.post
         .:int:300
   .lambda

      // Example of how to send an email using Hyperlambda.
      .mail.smtp.send
         message
            to
               Thomas Hansen:thomas@gaiasoul.com
            from
               Testing Gmail:testing.anarchy@gmail.com
            subject:This is subject
            entity:text/plain
               content:This is body
else
   lambda2hyper:x:@http.post
   log.error:x:-


// Returning result of original endpoint invocation to client.
add:x:+
   get-nodes:x:@http.post/*/content/*
return
```

**gateway.post.hl**

```
.arguments:*

// Validating length of name argument
validators.string:x:@.arguments/*/name
   min:5
   max:10
request.headers.get:Authorization

// Add all arguments into [http.post] invocation!
add:x:./*/http.post/*/payload
   get-nodes:x:@.arguments/*

// Invoking original endpoint we are now wrapping.
http.post:"https://tiger-polterguy.gb.aista.com/magic/modules/faq/gateway-original-1"
   convert:true
   headers
      Authorization:x:@request.headers.get
      Content-Type:application/json
   payload

// Sanity checking the result of our invocation.
if
   and
      mte:x:@http.post
         .:int:200
      lt:x:@http.post
         .:int:300
   .lambda

      // Returning result of original endpoint invocation to client.
      add:x:+
         get-nodes:x:@http.post/*/content/*
      return
else

   // Logging an error!
   lambda2hyper:x:@http.post
   log.error:x:-
   throw:Something went wrong as you invoked your HTTP endpoint
      status:500
      public:true
```

Thank you for reading, I hope it was helpful to you :)