GETTING STARTED

MAIN CONCEPTS

API

Extensions

Tuft extensions are split between two types: prehandlers and responders.

Prehandlers

A prehandler is a function akin to a middleware function in frameworks such as Express or Koa. A route can have an array of zero or more prehandler functions which are executed serially, in insertion order, before the response handler is called. A TuftContext object is passed as the first and only argument to each prehandler. This enables you to share logic between multiple routes by writing your own prehandler functions, or you can import prehandlers from external libraries that were written by yourself or other developers.

function myPrehandler(t) {
  // my custom middleware logic
}

To add a prehandler to your route map, add it to an array and set that array as the value of the prehandlers property in your options object when you create your application object.

const app = tuft({
  prehandlers: [myPrehandler]
})

// 'myPrehandler' will be executed before all routes added to 'app'

If a prehandler returns a response object, a response will be sent based on the properties in that object, and all successive prehandlers (and the main response handler itself) will be bypassed. In the following example, prehandler1() and prehandler2() will be executed, but prehandler3() and handler() will not.

function prehandler1() {
  // custom middleware logic
}

function prehandler2() {
  return { status: 400 }
}

function prehandler3() {
  // custom middleware logic
}

function handler() {
  return { status: 200 }
}

const app = tuft({
  prehandlers: [
    prehandler1,
    prehandler2,
    prehandler3
  ]
})

app.set('/', handler) // This route will return a 400 status code

While mofifying the passed TuftContext object is supported, overriding pre-existing properties is not.

function myPrehandler(t) {
  // 'time' is not a pre-existing property, so this is fine
  t.request.time = Date.now()

  // Don't do this, as 'secure' is a pre-existing property
  t.request.secure = true
}

Tuft comes packaged with the following built-in prehandlers that you can import:

Responders

A responder is a function that accepts a response object and then optionally responds to the client based on its included data. It does this by utilizing the passed Node server response object.

function myResponder(tuftResponseObject, response) {
  const { foo } = tuftResponseObject

  if (foo !== undefined) {
    response.statusCode = 200
    response.write(foo)
    response.end()
  }

  ...
}

To make use of a responder, add it to your route map by setting the responders option to an array and including the responder in that array. It will then be executed before Tuft's built-in response handling takes place.

const app = tuft({
  responders: [
    myResponder
  ]
})

// 'myResponder' will be executed before Tuft's built-in responders

Tuft comes packaged with one built-in responder that you can import:

How responders work

A responder receives two parameters:

  • the Tuft response object
  • the Node server response

If the responder chooses not to respond to the client, it should return the passed Tuft response object. This signals to the underlying framework that the response has not been sent. Otherwise, it should utilize the passed Node response stream to handle the response.

function myResponder(tuftResponseObject, response) {
  const { foo } = tuftResponseObject

  if (foo !== undefined) {
    // The responder has decided to handle the response based
    // on the presence of the property 'foo'
    response.statusCode = 200
    response.write(foo)
    response.end()
  }

  else {
    // The responder has decided not to handle the response,
    // so the Tuft response object is returned
    return tuftResponseObject
  }
}

If there are multiple responders on a particular route, they will be executed in order until one of them fails to return the response object.