GETTING STARTED

MAIN CONCEPTS

API

Built-in extensions

Tuft comes with a few built-in extensions as named exports. When you import a built-in extension, you are importing a factory function that must be called to return the extension itself.

Prehandlers

createSearchParams()

Adds a searchParams property to the request object, set to an instance of URLSearchParams, which contains any key/value pairs present in the query string of the request URL.

const { createSearchParams } = require('tuft')

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

app.set('/', t => {
  console.log(t.request.searchParams)
})

// A request for the path '/?foo=bar' will set 'searchParams' to the following:
// URLSearchParams { 'foo' => 'bar' }

Extracts key/value pairs from the cookie header and makes them available as the cookie property in the request object.

const { createCookieParser } = require('tuft')

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

app.set('/foo', t => {
  console.log(t.request.cookies)
})

createBodyParser(type [, maxSize])

By default, Tuft does not include the request body in the request object, as doing so has a significant performance impact. Body parser is therefore provided as an optional prehandler extension that can be added only to the routes that require it. If a request includes a body that matches the provided type, then the parsed body data will be added to the request object as body, unless the request body size is greater than that of the provided maxSize.

const { createBodyParser } = require('tuft')

const app = tuft({
  prehandlers: [createBodyParser('json')]
})

app.set('/', t => {
  console.log(t.request.body)
})

The type argument can be any of the following:

'raw'

If the request content type is 'application/octet-stream', the body will be parsed as a Buffer object.

'text'

If the request content type is 'text/*', the body will be parsed as a string.

'json'

If the request content type is 'application/json', the body will be parsed as an object using JSON.parse().

'urlEncoded'

If the request content type is 'application/x-www-form-urlencoded', the body will be parsed as an object.

The optional maxSize argument sets the maximum body size that can be parsed. Request bodies of a greater size will be ignored. If not set, defaults to 1048576 bytes (1 MiB).

createSession([options])

Creates a session using the provided options. A session object will then be added to every request, and all data within that object is persisted between requests from the same client. Session data is stored on the server, and a cookie with a random session ID is set on the client.

const { createSession } = require('tuft')

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

app.set('/', t => {
  const { session } = t.request
  session.foo = 'bar'
  return { json: session } // {"foo":"bar"}
})

By default, server side storage is simply an instance of Map, and is therefore not intended for production environments. For a production environment, a custom store can be provided. See the options information below for a detailed explanation.

const { createSession } = require('tuft')
const myCustomStore = require('./custom-store')

const app = tuft({
  prehandlers: [createSession({
    store: myCustomStore,
  })]
})

app.set('/', t => {
  const { session } = t.request
  session.foo = 'bar'
  return { json: session } // {"foo":"bar"}
})

The property name for the session object can be customized by providing the name option.

const { createSession } = require('tuft')

const app = tuft({
  prehandlers: [createSession({
    name: 'user'
  })]
})

app.set('/', t => {
  const { user } = t.request
  user.id = '1234'
  return { text: `Your user ID is ${user.id}` } // Your user ID is 1234
})

The options argument is an object that includes any of the following:

name

The property name that will be added to the Tuft request object.

Defaults to 'session'.

cookieName

A string that will be used as the key when setting the cookie. If not provided, the cookie name will be set to the session name plus '_id'.

If no session or cookie name is provided, the cookie name will be set to 'session_id'.

cookieOptions

An object consisting of the same options accepted by the .setCookie() method of TuftContext.

encoding

The encoding used when generating the random session ID. Must be one of either 'base64' or 'hex'.

Defaults to 'base64'.

store

A custom store implementation, which overrides the default behavior of using a JavaScript Map as the store. The custom store must be an object with at least the following three methods:

  • .set(name, sessionObject)
  • Accepts a name and a session object, and stores the object indexed by that name. Returns undefined, or a promise that resolves to undefined.

  • .get(name)
  • Returns the session object (or a promise that resolves to the session object) indexed by the provided name.

  • .delete(name)
  • Removes the session object indexed by the provided name from the store. Returns undefined, or a promise that resolves to undefined.

Responders

createStreamResponder()

By default, Tuft only supports sending a single "chunk" of data as the response body, even if that chunk itself ends up being split into smaller chunks by the the underlying Node runtime. For situations where this is not ideal, the stream responder allows you to send multiple chunks (i.e. write to a stream) by including your logic in a callback function.

You can utilize this responder by adding a writeStream property to the response object and setting it to a callback function, which then accepts a write() function as its first and only argument.

write() can be called as many times as necessary to send chunks of data. Each invocation will write the passed chunk of data to the response stream. The response will end automatically when the callback function returns. It also optionally accepts the encoding type (a string) as the second argument.

const { createStreamResponder } = require('tuft')

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

app.set('/', () => {
  return {
    writeStream: write => {
      write('Hello, ')
      write('world!', 'UTF-8')  // Optionally set the encoding
    }
  }
})