# The $ object of a Total.js 5 handler

> Use the properties and methods of the controller received by a route handler.

Framework: total5
Product: Total.js 5 (total5@0.0.19)
Language: en
Content-SHA256: b04b25b10d7f00afcc531b3bee7c01f76fd782ecbc8281873a3128d66e3c4614
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

A route handler receives one object, written `$` in this site. It describes the request and it answers it. Answer **once**: after `$.json()`, `$.html()` or any other answer, the request is finished.

## Properties

| Property | Type | What it is |
|---|---|---|
| `$.url` | string | The path of the request, without the query string. |
| `$.method` | string | `GET`, `POST`... |
| `$.query` | object | The query string, parsed. |
| `$.params` | object | The `{name}` segments of the route. |
| `$.body` | object | The body, parsed by its content type (JSON, URL-encoded form, XML or multipart fields). |
| `$.files` | array | The uploaded files of a multipart request. |
| `$.headers` | object | The headers of the request, with lowercase names. |
| `$.ip` | string | The IP address; the first address of `x-forwarded-for` when the header exists. |
| `$.host` | string | The `host` header. |
| `$.referrer` | string | The `referer` header. |
| `$.protocol` | string | `http` or `https` (also when a proxy says so in `x-forwarded-proto`). |
| `$.ext` | string | The extension of the URL, without the dot (`$.extension` is the same). |
| `$.xhr` | boolean | `true` when the header `x-requested-with` is `XMLHttpRequest`. |
| `$.mobile` | boolean | `true` when the user agent looks like a mobile browser. |
| `$.robot` | boolean | `true` when the user agent looks like a crawler. |
| `$.ua` | string | A short name of the browser and system, such as `iPhone Safari` or `Windows Chrome`. |
| `$.user` | object | The user that `AUTH()` approved, or nothing. |
| `$.language` | string | The language that `LOCALIZE()` chose. |
| `$.datatype` | string | `json`, `urlencoded`, `multipart`, `xml`, `text` or `binary`: the type of the body of the request. |
| `$.response` | object | What will be sent: `status`, `headers` and `value`. Change `$.response.status` and `$.response.headers` before you answer. |
| `$.req`, `$.res` | objects | The Node.js request and response. |

## Methods that answer

| Method | What it does | Recipe |
|---|---|---|
| `$.json(value)` | Answers with JSON. | [responses](/en/total5/responses/) |
| `$.jsonstring(text)` | Answers with a text that is already JSON, without serializing it again. | [controller-completion-and-cache](/en/total5/controller-completion-and-cache/) |
| `$.html(text)` | Answers with HTML. | [responses](/en/total5/responses/) |
| `$.plain(text)` | Answers with plain text (`$.text` is the same). | [responses](/en/total5/responses/) |
| `$.xml(text)` | Answers with XML. | [responses](/en/total5/responses/) |
| `$.empty()` | Answers with status 204 and no body. | [responses](/en/total5/responses/) |
| `$.redirect(url, permanent)` | Redirects (302, or 301 when `permanent` is true). | [responses](/en/total5/responses/) |
| `$.binary(buffer, type, name)` | Answers with bytes and a content type. | [responses](/en/total5/responses/) |
| `$.file(path, name)` | Sends a file from disk. | [file-download](/en/total5/file-download/) |
| `$.stream(type, stream, name)` | Sends a readable stream. | [file-download](/en/total5/file-download/) |
| `$.filefs(storage, id)` | Sends a file of a `FILESTORAGE`. | [filestorage](/en/total5/filestorage/) |
| `$.image(options)` | Creates and sends an image on demand. | [images](/en/total5/images/) |
| `$.view(name, model)` | Renders a view with the layout and answers with it. | [views-and-layouts](/en/total5/views-and-layouts/) |
| `$.layout(name)` | Chooses another layout for the next `$.view()`. | [view-sections](/en/total5/view-sections/) |
| `$.proxy(url)` | Forwards the request to another URL and answers with its response. | [proxy](/en/total5/proxy/) |
| `$.respond(value)` | Answers in the format of `$.response.output` (`json` when it is not set). | [controller-completion-and-cache](/en/total5/controller-completion-and-cache/) |
| `$.invalid(value)` | Answers with an error: a text, a status code such as `404` or an `ErrorBuilder`. | [actions-crud](/en/total5/actions-crud/) |
| `$.fallback(code)` | Answers with the page of an error code, the custom one when `ROUTE('#404')` exists. | [error-pages](/en/total5/error-pages/) |
| `$.success(value)` | Answers `{ "success": true }`; `value` is added to it. | [responses](/en/total5/responses/) |
| `$.callback(err, value)` | With an error answers `$.invalid(err)`, otherwise `$.json(value)`, or `$.success()` when `value` is `undefined`. Without arguments it returns a function `(err, response)` that does the same. | [actions-crud](/en/total5/actions-crud/) |
| `$.successful(fn)` | Returns a function `(err, a, b, c)`: with an error it answers `$.invalid(err)`, otherwise it calls `fn(a, b, c)`. | [controller-completion-and-cache](/en/total5/controller-completion-and-cache/) |
| `$.done(arg)` | Returns a function `(err, response)`: with an error it answers `$.invalid(err)`, otherwise it answers with the success object. | [controller-completion-and-cache](/en/total5/controller-completion-and-cache/) |

## Other methods

| Method | What it does | Recipe |
|---|---|---|
| `$.cookie(name, value, expiration)` | Reads a cookie, or writes one when you pass a value. | [headers-and-cookies](/en/total5/headers-and-cookies/) |
| `$.csrf()` | Creates a CSRF token for this client. | [csrf-protection](/en/total5/csrf-protection/) |
| `$.hostname(path)` | The address of this server: protocol, host and the path you pass. | [restbuilder](/en/total5/restbuilder/) |
| `$.action(name, model)` | Runs an action with this request (user, query and params). | [calling-actions-from-code](/en/total5/calling-actions-from-code/) |
| `$.transform(name, value, callback)` | Runs a transform with this request. | [transforms](/en/total5/transforms/) |
| `$.authorize(callback)` | Runs `AUTH()` for this request and sets `$.user`; it returns a promise when there is no callback. | [controller-completion-and-cache](/en/total5/controller-completion-and-cache/) |
| `$.notmodified(date)` | Answers 304 and returns `true` when the request has the header `if-modified-since` with that date. | [controller-completion-and-cache](/en/total5/controller-completion-and-cache/) |
| `$.httpcache(date)` | Sets the cache headers and `last-modified` of the answer. | [controller-completion-and-cache](/en/total5/controller-completion-and-cache/) |
| `$.clear()` | Removes the temporary files of the upload. They are removed anyway when the request ends. | [file-upload](/en/total5/file-upload/) |
| `$.autoclear(false)` | Keeps the uploaded files after the request, so that you can use them later. | [upload-lifecycle-and-href](/en/total5/upload-lifecycle-and-href/) |
| `$.custom()` | Tells the framework that you answer through `$.res` yourself: it will not send anything. | [controller-completion-and-cache](/en/total5/controller-completion-and-cache/) |
| `$.href(key, value)` | Use `QUERIFY()` as in the linked recipe, the tested native query-link helper. | [upload-lifecycle-and-href](/en/total5/upload-lifecycle-and-href/) |
| `$.flush()`, `$.resume()`, `$.free()`, `$.cancel()` | Internal methods: do not call them. | - |

The example answers with the properties and calls the methods that need no setup.

```js controllers/api.js
exports.install = function() {
	ROUTE('GET /info/{a}/{b}/', info);
	ROUTE('POST /body/ @json', body);
	ROUTE('GET /answers/{kind}/', answers);
	ROUTE('GET /callback/{kind}/', callback);
};

function info($) {
	$.json({
		url: $.url,
		method: $.method,
		query: $.query,
		params: $.params,
		ext: $.ext,
		xhr: $.xhr,
		mobile: $.mobile,
		robot: $.robot,
		ua: $.ua,
		ip: $.ip,
		host: $.host,
		referrer: $.referrer,
		protocol: $.protocol,
		hostname: $.hostname('/x/'),
		datatype: $.datatype
	});
}

function body($) {
	$.json({ body: $.body, datatype: $.datatype });
}

function answers($) {
	switch ($.params.kind) {
		case 'json': return $.json({ a: 1 });
		case 'jsonstring': return $.jsonstring('{"a":1}');
		case 'html': return $.html('<b>x</b>');
		case 'plain': return $.plain('x');
		case 'xml': return $.xml('<a>1</a>');
		case 'empty': return $.empty();
		case 'redirect': return $.redirect('/x/', true);
		case 'binary': return $.binary(Buffer.from('abc'), 'application/octet-stream');
		case 'invalid': return $.invalid(409);
		case 'success': return $.success({ id: 7 });
		case 'status': $.response.status = 201; return $.json({ created: true });
		case 'header': $.response.headers['x-example'] = 'yes'; return $.json({});
	}
}

function callback($) {
	switch ($.params.kind) {
		case 'error': return $.callback('failed');
		case 'value': return $.callback(null, { v: 1 });
		case 'nothing': return $.callback(null);
		case 'function': return setImmediate($.callback(), null, { later: true });
		case 'successful': return setImmediate($.successful(function(a, b) { $.json({ a: a, b: b }); }), null, 'x', 'y');
	}
}
```
