Interceptors and exception handlers in Hyperlambda

This tutorial covers the following parts of Magic and Hyperlambda.

In this tutorial we will have a look at two features that allows you to write “Super DRY code”. DRY here refers to “Don’t Repeat Yourself”, and is an important design principle as you create software. These two features are referred to as “interceptors” and “exception handlers”. Below is an example of how you could tie these parts together. Make sure you create a new folder within your “modules” folder, name your folder “foo”, and put the following 3 files into that folder.

exceptions.hl

log.error:x:@.arguments/*/message
return
   message:Some error occurred
   status:int:555

interceptor.hl

log.info:Interceptor
data.connect:[generic|magic]
   .interceptor

bar.get.hl

log.info:Endpoint file

// Unccomment the next line to test exception handlers
// throw:An exception occurred

data.read
   table:users
   columns
      username
return-nodes:x:@data.read/*

If you invoke your endpoint now, you will see everything working, even though you’re not explicitly opening up a database connection in your above “bar.get.hl” file. The reasons is because the endpoint URL resolver will actually combine your “interceptor.hl” file with your “bar.get.hl” file, resulting in the following combined lambda object.

// Fetched from "interceptor.hl"
log.info:Interceptor
data.connect:[generic|magic]

   // Fetched from "bar.get.hl"
   log.info:Endpoint file
   data.read
      table:users
      columns
         username
   return-nodes:x:@data.read/*

This of course makes it easy for you to “outsource” commonalities in your folders to a single file, having everything occurring in one single file, to avoid repeating yourself. Notice, interceptors are recursively applied, implying if you have multiple interceptors upwards in your folder hierarchy, then all interceptors will be applied, creating a combined result, before your lambda object is executed. Exception handlers though are not recursively applied, and only the first exception handler upwards in your folder structure will be used. Interceptors are hence said to be extendable , while exception handlers are said to be overriding.

To understand the exception handler parts of our code, try to add the following Hyperlambda into your above “bar.get.hl” file somewhere.

throw:Throwing an exception ...

Notice how the status code and error message is “transformed” by our exception handler. This is because our exception handler is invoked with our original exception, and whatever it returns is what is returned to the client. By creating exception handlers such as above, you get to keep all your error logic in one place, and have common error logic for your modules, allowing you to for instance translate exception messsages, or create specific exception handlers for some of your folders, etc.