Aista – Magic Cloud – Generate a CRUD app in seconds

Categories
Hyperlambda

Hyperlambda HTTP Interceptors

Hyperlambda HTTP Interceptors allows you to inject code that is to be executed before or after some HTTP endpoint is executed.

Hyperlambda HTTP interceptors allows you to intercept some HTTP endpoint, and add logic that should be executed before or after your original endpoint. This opens up a lot of interesting use cases, such as for instance.

  • Logging invocations to your original endpoint
  • Attaching additional input data to your original endpoint
  • Return additional data from your endpoint required by the client
  • Changing the data specified by the client before invoking original endpoint
  • Changing authorisation requirements to your original endpoint
  • Add caching to your intercepted endpoint
  • Etc, etc, etc

This becomes almost the HTTP equivalent of AOP software development, which of course implies “Aspect Oriented Programming”, and is a more declarative way of creating software, due to allowing you to attach additional functionality, both before and after the invocation to your original endpoint.

Other use cases might be adding business logic to an HTTP endpoint you cannot add business logic to, such as for instance a GraphQL or PostgREST endpoints, such as those given to you by Hasura or Supabase. Logically this becomes the HTTP and Hyperlambda equivalent of OOP “polymorphism”, since it allows you to take some static thing, and modify how it behaves by “overriding” your original HTTP method. In the video below I am showing you how such interceptors works.

The idea is easily understood; Take some “whatever” HTTP endpoint. Create a new interceptor endpoint that invokes your original endpoint, and attach code to your interceptor endpoint allowing you to do things both before and after your intercepted endpoint is invoked. Then forward the arguments given to your interceptor to your intercepted endpoint, and optionally attach the Authorization header if any before invoking the intercepted endpoint.

Now the only thing you need to do to start using your interceptor, is to change the URL your client is using while invoking the original endpoint. The signature and logic should be the same, assuming your interceptor endpoint can accept any arguments.

You can find the code I am using in the above video below.

interceptor.post.hl

.arguments:*
.description:Intercepts our foo endpoint

// Endpoint we're intercepting.
.endpoint:"https://tiger-polterguy.gb.aista.com/magic/modules/faq/foo"

/*
 * Retrieving Authorization header to transmit to
 * intercepted endpoint.
 */
request.headers.get:Authorization

/*
 * Lambda object executed as an "intercepted lambda object"
 * before invocation to HTTP endpoint.
 */
.before
   log.info:BEFORE!!

/*
 * This is where you would parametrise your above [.before] object
 * with for instance arguments given by the client.
 */

// Evaluating [.before] lambda object.
eval:x:@.before

// Forwarding arguments given to endpoint to intercepted endpoint.
add:x:../*/http.post/*/payload
   get-nodes:x:@.arguments/*

/*
 * Checking if we've got an Authorization HTTP header,
 * at which point we forward it to the original HTTP endpoint.
 */
if
   not-null:x:@request.headers.get
   .lambda
      add:x:../*/http.post/*/headers
         .
            Authorization:x:@request.headers.get

// Invoking the intercepted HTTP endpoint.
http.post:x:@.endpoint
   headers
      Content-Type:application/json
   convert:true
   payload

// Sanity checking invocation to endpoint.
if
   not
      and
         mte:x:@http.post
            .:int:200
         lt:x:@http.post
            .:int:400
   .lambda
      log.error:Something went wrong as we invoked our intercepted HTTP endpoint
         endpoint:x:@.endpoint
         status:x:@http.post
         result:x:@http.post/*/content
      throw:Intercepted endpoint did not return success
         public:true
         status:502


/*
 * Lambda object to execute after invocation to
 * intercepted endpoint.
 */
.after
   log.info:AFTER!!

/*
 * This is where you would parametrise your above [.after] object
 * with for instance arguments given by the client.
 */

// Evaluating [.before] lambda object.
eval:x:@.after

// Return result to caller.
add:x:+
   get-nodes:x:@http.post/*/content/*
return

foo.post.hl

.arguments
   name:string
auth.ticket.verify:root
log.info:Foo endpoint was executed
strings.concat
   .:"Hello "
   get-value:x:@.arguments/*/name
unwrap:x:+/*
return
   result:x:@strings.concat