API Documentation
Application
The app
object is the whole tinyhttp application with all the middleware, handlers and settings.
import { App } from '@tinyhttp/app'
const app = new App()
app.get('/', (req, res) => {
res.send('hello world')
})
app.listen(3000)
The app object has methods for
- Routing HTTP requests; see for example,
app.METHOD
. - Configuring middleware; see
app.route
. - Rendering HTML views; see
app.render
. - Registering a template engine; see
app.engine
.
The tinyhttp application object can be referred from the request object and the response object as req.app
, and res.app
, respectively.
Constructor
noMatchHandler(req, res)
Handler if none of the routes match. Should return 404 Not found.
import { App, Request, Response } from '@tinyhttp/app'
const app = new App({
noMatchHandler: (req: Request, res: Response) => void res.status(404).end('Not found :(')
})
app
.get('/', (req, res) => {
res.send('hello world')
})
.listen(3000)
onError(err, req, res)
A middleware to catch server errors. Error can be anything. Should return 500 Internal Server Error.
import { App, Request, Response } from '@tinyhttp/app'
const app = new App({
onError: (err, req, res) => {
res.status(500).send({
message: err.message
})
}
})
app.get('/', (req, res) => void res.send('hello world')).listen(3000)
applyExtensions
A handler-like function that adds request and response extensions to handlers.
By default, the extendMiddleware
function is used, which contains all tinyhttp's req
/ res
extensions.
import { App, extendMiddleware } from '@tinyhttp/app'
const app = new App({
applyExtensions: (req, res, next) => {
extendMiddleware(req, res, next)
res.someExt = someExt(req, res, next)
}
})
When an empty function is passed, all extensions from extendMiddleware
aren't included anymore:
import { App } from '@tinyhttp/app'
import { send } from '@tinyhttp/send'
const app = new App({
applyExtensions: (req, res, next) => {
// now tinyhttp only has a `res.send` extension
res.send = send(req, res)
}
})
You can also disable all of the extensions by passing an empty function:
import { App } from '@tinyhttp/app'
const app = new App({
applyExtensions: (req, res, next) => { next() }
})
settings
tinyhttp application has a list of settings to toggle various application parts. All of them are opted out by default to achieve the best performance (less extensions, better performance).
import { App } from '@tinyhttp/app'
const app = new App({
settings: {
networkExtensions: true
}
})
app.use((req, res) => void res.send(`Hostname: ${req.hostname}`)).listen(3000)
Here's a list of all of the settings:
networkExtensions
- networkreq
extensionssubdomainOffset
- subdomain offset forreq.subdomains
bindAppToReqRes
- bind currentApp
toreq.app
andres.app
xPoweredBy
- setX-Powered-By: "tinyhttp"
headerenableReqRoute
- enablereq.route
propertyviews
- views directory where templates are locatedview
- custom View object to handle template engine rendering logicview cache
- toggle caching of viewsview engine
- the default engine extension (e.g.eta
)
networkExtensions
Enabled a list of Request object extensions related to network.
subdomainOffset
Subdomain offset for req.subdomains
. Defaults to 2
.
bindAppToReqRes
Bind the app as a reference to the actual app to req.app
and res.app
. Disabled by default.
enableReqRoute
Enables req.route
property. Disabled by default.
Properties
app.locals
The app.locals
object has properties that are local variables within the application.
console.dir(app.locals.title)
// => 'My App'
console.dir(app.locals.email)
// => 'me@myapp.com'
Once set, the value of app.locals properties persist throughout the life of the application, in contrast with res.locals properties that are valid only for the lifetime of the request.
You can access local variables in templates rendered within the application. This is useful for providing helper functions to templates, as well as application-level data.
app.locals.title = 'My App'
app.locals.strftime = require('strftime')
app.locals.email = 'me@myapp.com'
app.parent
app.parent
points to a parent App
object, e.g. the app that was mounted to.
const app = new App()
const subapp = new App()
app.use(subapp)
console.log(app.parent)
/*
<ref *1> App {
middleware: [],
mountpath: '/',
apps: {
'/': App {
middleware: [],
mountpath: '/',
apps: {},
parent: [Circular *1]
}
}
}
*/
Events
Coming soon...
Methods
app.METHOD
Routes an HTTP request, where METHOD is the HTTP method of the request, such as GET, PUT, POST, and so on, in lowercase. Thus, the actual methods are app.get(), app.post(), app.put(), and so on.
Routing methods
app.all
This method is like the standard app.METHOD()
methods, except it matches all HTTP verbs.
The following callback is executed for requests to /secret
whether using GET, POST, PUT, DELETE, or any other HTTP request method:
app.all('/secret', (req, res, next) => {
console.log('Accessing the secret section ...')
next() // pass control to the next handler
})
The app.all()
method is useful for mapping “global” logic for specific path prefixes or arbitrary matches. For example, if you put the following at the top of all other route definitions, it requires that all routes from that point on require authentication, and automatically load a user. Keep in mind that these callbacks do not have to act as end-points: loadUser can perform a task, then call next()
to continue matching subsequent routes.
app.all('*', requireAuthentication, loadUser)
app.get
Routes HTTP GET requests to the specified path with the specified handler functions.
app.get('/', (req, res) => {
res.send(`${req.method || 'GET'} request to homepage`)
})
app.post
Routes HTTP POST requests to the specified path with the specified handler functions.
app.post('/', (req, res) => {
res.send(`${req.method || 'POST'} request to homepage`)
})
app.put
Routes HTTP PUT requests to the specified path with the specified handler functions.
app.put('/', (req, res) => {
res.send(`${req.method || 'PUT'} request to homepage`)
})
app.delete
Routes HTTP DELETE requests to the specified path with the specified handler functions.
app.delete('/', (req, res) => {
res.send(`${req.method || 'DELETE'} request to homepage`)
})
app.use
Mounts the specified middleware function or functions at the specified path: the middleware function is executed when the base of the requested path matches path.
A route will match any path that follows its path immediately with a /
. For example: app.use('/apple', ...)
will match /apple
, /apple/images
, /apple/images/news
, and so on.
Since path defaults to /,
middleware mounted without a path will be executed for every request to the app.
For example, this middleware function will be executed for every request to the app:
app.use((req, res, next) => {
console.log('Time: %d', Date.now())
next()
})
Middleware functions are executed sequentially, therefore the order of middleware inclusion is important.
// this middleware will not allow the request to go beyond it
app.use((req, res, next) => void res.send('Hello World'))
// requests will never reach this route
app.get('/', (req, res) => res.send('Welcome'))
app.engine
Register a template engine. Works with any Express template engines that contain a renderFile
function.
import { App } from '@tinyhttp/app'
import { renderFile } from 'eta'
const app = new App()
app.engine('eta', renderFile) // map app.engines['eta'] to `renderFile`
app.render
Render a file with the engine that was set previously via app.engine
. To render and respond with the result, use res.render
import { App } from '@tinyhttp/app'
import { renderFile } from 'eta'
const app = new App()
app.engine('eta', renderFile)
app.render(
'index',
{ name: 'Eta' },
{
/* some options */
},
(err, html) => {
if (err) throw err
doSomethingWithHTML(html)
}
)
tinyhttp doesn't support app.render
overloading yet. Because of that, some engines (Pug, for example) may require additional wrapping.
import { App } from '@tinyhttp/app'
import pug from 'pug'
const app = new App()
const renderPug = (path, _, options, cb) => pug.renderFile(path, options, cb)
app.engine('pug', renderPug)
app.use((_, res) => void res.render('index.pug'))
app.listen(3000, () => console.log(`Listening on http://localhost:3000`))
app.path
Returns the mountpath of the app.
const app = new App()
const blog = new App()
const blogAdmin = new App()
app.use('/blog', blog)
blog.use('/admin', blogAdmin)
console.dir(app.path()) // ''
console.dir(blog.path()) // '/blog'
console.dir(blogAdmin.path()) // '/blog/admin'
app.route
Returns an instance of a single route, which you can then use to handle HTTP verbs with optional middleware. Use app.route()
to avoid duplicate route names.
new App()
.route('/events')
.all((req, res, next) => {
// runs for all HTTP verbs first
// think of it as route specific middleware!
})
.get((req, res, next) => res.json({ hello: 'world' }))
.post((req, res, next) => {
// maybe add a new event...
})
app.enable
Sets the Boolean
setting name to true
, where name is one of the properties from the app settings.
app.enable('networkExtensions')
app.disable
Sets the Boolean
setting name to false
, where name is one of the properties from the app settings.
app.disable('networkExtensions')
app.set
Sets the setting name to value, where is one of the properties from the app settings.
app.set('subdomainOffset', 2)
app.handler
Extends req
/ res
objects, pushes 404 and 500 handlers, dispatches middleware and matches paths.
In some cases where you don't need to start a server but pass the req
/ res
handler instead.
For example you want to start an HTTP/2 server instead of HTTP one:
import { App } from '@tinyhttp/app'
import type { Request, Response } from '@tinyhttp/app'
import fs from 'fs'
import { createSecureServer } from 'http2'
const app = new App()
const options = {
key: fs.readFileSync('localhost-privkey.pem'),
cert: fs.readFileSync('localhost-cert.pem')
}
app.get('/', (req, res) => void res.send(`Hello from HTTP ${req.httpVersion} server!`))
createSecureServer(options, async (req: Request, res: Response) => {
await app.handler(req, res)
}).listen(3000)
It's also common to pass the handler in serverless functions (e.g. Vercel), like this:
const { App } = require('@tinyhttp/app')
app.use((req, res) => res.send(`You're on ${req.url}`))
module.exports = async (req, res) => await app.handler(req, res)
app.listen
Starts an HTTP server and listens on a specified port and host.
import { App } from '@tinyhttp/app'
const app = new App()
app.use((_, res) => res.send('Hello World')).listen(3000, () => console.log(`Started on :3000`))
Request
The req
object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on.
app.get('/user/:id', (req, res) => void res.send(`user ${req.params.id}`))
The req object is an enhanced version of Node.js built-in IncomingMessage object.
Properties
req.hostname
Contains the hostname derived from either Host
or X-Forwarded-Host
HTTP header.
// Host: "example.com:3000"
console.dir(req.hostname)
// => 'example.com'
req.query
This property is an object containing a property for each query string parameter in the route.
// GET /search?q=tobi+ferret
console.dir(req.query.q)
// => "tobi ferret"
// GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse
console.dir(req.query.order)
// => "desc"
console.dir(req.query.shoe.color)
// => "blue"
console.dir(req.query.shoe.type)
// => "converse"
// GET /shoes?color[]=blue&color[]=black&color[]=red
console.dir(req.query.color)
// => [blue, black, red]
req.route
This property can be enabled via
enableReqRoute
setting
Contains the currently-matched route, a string. For example:
app.get('/user/:id?', function userIdHandler(req, res) {
console.log(req.route)
res.send('GET')
})
Example output would be something like this:
{
path: '/user/:id?',
method: 'GET',
handler: [Function: userIdHandler],
type: 'route'
}
req.params
This property is an object containing properties mapped to the named route “parameters”. For example, if you have the route /user/:name
, then the “name” property is available as req.params.name
. This object defaults to {}
.
// GET /user/v1rtl
app.get('/user/:name', (req, res) => {
res.end(`Hello ${req.params.name}!`)
})
// => v1rtl
req.protocol
Contains the request protocol string: either http or (for TLS requests) https. This property will use the value of the X-Forwarded-Proto
header field if present. This header can be set by the client or by the proxy.
console.dir(req.protocol)
req.secure
A Boolean property that is true if a TLS connection is established. Equivalent to the following:
req.protocol === 'https'
req.xhr
A Boolean property that is true if the request’s X-Requested-With
header field is “XMLHttpRequest”, indicating that the request was issued by a client library such as fetch
.
console.dir(req.xhr)
// => true
req.fresh
When the response is still “fresh” in the client’s cache true is returned, otherwise false is returned to indicate that the client cache is now stale and the full response should be sent.
When a client sends the Cache-Control: no-cache
request header to indicate an end-to-end reload request, this module will return false to make handling these requests transparent.
Further details for how cache validation works can be found in the HTTP/1.1 Caching Specification.
console.dir(req.fresh)
// => true
req.stale
Indicates whether the request is “stale,” and is the opposite of req.fresh
. For more information, see req.fresh
.
console.dir(req.stale)
// => true
req.ip
Contains the remote IP address of the request.
console.log(req.ip)
// => '127.0.0.1'
req.ips
Contains an array of remote IP addresses of the request.
console.log(req.ips)
// => [127.0.0.1']
req.subdomains
This property can be enabled via
networkExtensions
setting
Contains an array of subdomains. Subdomain offset can be set via subdomainOffset
console.log(req.hostname)
// dev.node0.example.com
console.log(req.subdomains)
// ['node0', 'dev']
req.app
This property can be enabled via
bindAppToReqRes
setting
Points to a reference of the currently used app.
app.use((req, res) => void res.json(req.app.settings))
req.path
Contains the path part of the request URL.
// example.com/users?sort=desc
console.dir(req.path)
// => '/users'
Methods
req.accepts
Checks if the specified content types are acceptable, based on the request’s Accept
HTTP header field. The method returns the best match, or if none of the specified content types is acceptable, returns false
(in which case, the application should respond with 406 "Not Acceptable"
).
The type value may be a single MIME type string (such as "application/json"
), an extension name such as "json"
, a comma-delimited list, or an array. For a list or array, the method returns the best match (if any).
// Accept: text/html
req.accepts('html')
// => "html"
// Accept: text/*, application/json
req.accepts('html')
// => "html"
req.accepts('text/html')
// => "text/html"
req.accepts(['json', 'text'])
// => "json"
req.accepts('application/json')
// => "application/json"
// Accept: text/*, application/json
req.accepts('image/png')
req.accepts('png')
// => false
// Accept: text/*;q=.5, application/json
req.accepts(['html', 'json'])
// => "json"
For more information, or if you have issues or concerns, see accepts.
req.acceptsEncodings
Returns the first accepted encoding of the specified encodings, based on the request’s Accept-Encoding
HTTP header field. If none of the specified encodings is accepted, returns false
.
req.acceptsCharsets
Returns the first accepted charset of the specified character sets, based on the request’s Accept-Charset
HTTP header field. If none of the specified charsets is accepted, returns .false
req.get
Returns the specified HTTP request header field (case-insensitive match).
req.get('Content-Type')
// => "text/plain"
req.get('content-type')
// => "text/plain"
req.get('Something')
// => undefined
req.range
Parse Range
header.
app.use((req, res) => {
const ranges = req.range(1000)
if (range.type === 'bytes') {
// the ranges
range.forEach((r) => {
// do something with r.start and r.end
})
})
Response
The res
object represents the HTTP response that a tinyhttp app sends when it gets an HTTP request.
Properties
res.app
This property can be enabled via
bindAppToReqRes
setting
Points to a reference of the currently used app.
app.use((req, res) => {
res.json(res.app.settings)
})
Methods
res.append
Appends the specified value
to the HTTP response header
field. If the header is not already set, it creates the header with the specified value. The value parameter can be a string or an array.
calling
res.set()
afterres.append()
will reset the previously-set header value.
res.append('Link', ['<http://localhost/>', '<http://localhost:3000/>'])
res.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly')
res.append('Warning', '199 Miscellaneous warning')
res.cookie
Sets cookie name
to value
. The value
parameter may be a string or object converted to JSON.
The options
parameter is an object that can have the following properties.
Property | Type | Description |
---|---|---|
domain |
string |
Domain name for the cookie. Defaults to the domain name of the app. |
encode |
Function |
A synchronous function used for cookie value encoding. Defaults to encodeURIComponent . |
expires |
Date |
Expiry date of the cookie in GMT. If not specified or set to 0, creates a session cookie. |
httpOnly |
boolean |
Flags the cookie to be accessible only by the web server. |
maxAge |
number |
Convenient option for setting the expiry time relative to the current time in milliseconds. |
path |
string |
Path for the cookie. Defaults to “/”. |
secure |
boolean |
Marks the cookie to be used with HTTPS only. |
signed |
boolean |
Indicates if the cookie should be signed. |
sameSite |
boolean | string |
Value of the “SameSite” Set-Cookie attribute. More info. |
All
res.cookie()
does is set the HTTP Set-Cookie header with the options provided. Any option not specified defaults to the value stated in RFC 6265.
res.cookie('name', 'tobi', {
domain: '.example.com',
path: '/admin',
secure: true
})
// Enable "httpOnly" and "expires" parameters
res.cookie('rememberme', '1', {
expires: new Date(Date.now() + 900000),
httpOnly: true
})
res.clearCookie
Clears the cookie specified by name
. For details about the options
object, see res.cookie()
.
Web browsers and other compliant clients will only clear the cookie if the given options is identical to those given to
res.cookie()
, excluding expires and maxAge.
res.cookie('name', 'tobi', { path: '/admin' })
res.clearCookie('name', { path: '/admin' })
res.end
Ends the response process. The method comes from response.end() of http.ServerResponse..
Can be used to send raw data or end the response without any data at all. If you need to respond with data with proper content type headers set and so on, instead use methods such as res.send()
and res.json()
.
res.end()
res.status(404).end()
res.json
Sends a JSON response. This method sends a response (with the correct Content-Type
header) that is the parameter converted to a JSON string using JSON.stringify()
.
The body can be any kind of JSON, including object, array, string
, boolean
, number
, or null
.
res.json(null)
res.json({ user: 'tobi' })
res.status(500).json({ error: 'message' })
res.send
Sends the HTTP response.
The body can be a Buffer
object, a string, an object, or an array.
res.send(Buffer.from('whoop'))
res.send({ some: 'json' })
res.send('<p>some html</p>')
res.status(404).send('Sorry, we cannot find that!')
res.status(500).send({ error: 'something blew up' })
This method performs many useful tasks for simple non-streaming responses: For example, it automatically set the proper Content-Length
header value and provides automatic HEAD and HTTP cache freshness support.
When the parameter is a Buffer
object, the method sets the Content-Type
response header field to "application/octet-stream"
, unless previously defined as shown below:
res.set('Content-Type', 'text/html')
res.send(Buffer.from('<p>some html</p>'))
When the parameter is a string, the method sets the Content-Type
to "text/html"
:
res.send('<p>some html</p>')
When the parameter is an Array or Object, Express responds with the JSON representation (same as res.json
):
res.send({ user: 'tobi' })
res.send([1, 2, 3])
res.status
Sets the HTTP status for the response. It is a chainable alias of Node’s response.statusCode
.
res.status(403).end()
res.status(400).send('Bad Request')
res.sendStatus
Sets the response HTTP status code to statusCode and send its string representation as the response body.
res.sendStatus(200) // equivalent to res.status(200).send('OK')
res.sendStatus(403) // equivalent to res.status(403).send('Forbidden')
res.sendStatus(404) // equivalent to res.status(404).send('Not Found')
res.sendStatus(500) // equivalent to res.status(500).send('Internal Server Error')
If an unsupported status code is specified, the HTTP status is still set to statusCode and the string version of the code is sent as the response body.
res.sendStatus(9999) // equivalent to res.status(9999).send('9999')
res.sendFile
Sends a file by piping a stream to response. It also checks for extension to set a proper Content-Type
header field.
Path argument must be absolute. To use a relative path, specify the
root
option first.
res.sendFile('song.mp3', { root: process.cwd() }, (err) => console.log(err))
res.set
Sets the response’s HTTP header field
to value
. To set multiple fields at once, pass an object as the parameter.
res.set('Content-Type', 'text/plain')
res.set({
'Content-Type': 'text/plain',
'Content-Length': '123',
ETag: '12345'
})
Alias to res.header
.
res.links
Joins the links
provided as properties of the parameter to populate the response’s Link
HTTP header field.
For example, the following call:
res.links({
next: 'http://api.example.com/users?page=2',
last: 'http://api.example.com/users?page=5'
})
Yields the following results:
Link: <http://api.example.com/users?page=2>; rel="next",
<http://api.example.com/users?page=5>; rel="last"
res.location
Sets the response Location HTTP header to the specified path parameter.
res.location('/foo/bar')
res.location('http://example.com')
res.location('back')
A path
value of "back"
has a special meaning, it refers to the URL specified in the Referer
header of the request. If the Referer header was not specified, it refers to "/"
.
After encoding the URL, if not encoded already, tinyhttp passes the specified URL to the browser in the
Location
header, without any validation. Browsers take the responsibility of deriving the intended URL from the current URL or the referring URL, and the URL specified in the Location header; and redirect the user accordingly.
res.render
Render a template using a pre-defined engine and respond with the result.
import { App } from '@tinyhttp/app'
import ejs from 'ejs'
const app = new App()
app.engine('ejs', ejs.renderFile)
app.use((_, res) => void res.render('index.ejs', { name: 'EJS' }))
app.listen(3000, () => console.log(`Listening on http://localhost:3000`))
res.vary
Adds the field to the Vary response header, if it is not there already.
res.vary('User-Agent').render('docs')
res.format
Sends a conditional response based on the value in Accept
header. For example, if Accept
contains html
, the HTML option will be sent.
res.format({
html: (req, res) => void res.send('<h1>Hello World for HTML</h1>')
text: (req, res) => void res.send('Hello World for text')
})
and depending on the Accept
header, it will send different responses:
curl -H "Accept: text/html" localhost:3000
# <h1>Hello World for HTML</h1>
curl localhost:3000
# Hello World for text
res.redirect
Redirect to a URL by sending a 302 (or any other) status code and Location
header with the specified URL.
res.redirect('/another-page')
// custom status
res.redirect('/some-other-page', 300)
res.type
Sets the Content-Type
HTTP header to the MIME type as determined by mime.lookup() for the specified type. If type contains the /
character, then it sets the Content-Type
to type.
res.type('.html')
// => 'text/html'
res.type('html')
// => 'text/html'
res.type('json')
// => 'application/json'
res.type('application/json')
// => 'application/json'
res.type('png')
// => 'image/png'
res.jsonp
Send JSON response with JSONP callback support. res.jsonp
isn't used that often so it's located in a separate package - @tinyhttp/jsonp
Here's how to enable it:
import { jsonp } from '@tinyhttp/jsonp'
app.use((req, res, next) => {
res.jsonp = jsonp(req, res, app)
next()
})
app.get('/', (req, res) => {
res.jsonp({ some: 'jsonp' })
})