UNPKG

13.7 kBMarkdownView Raw
1<h1 align="center">Fastify</h1>
2
3## Routes
4You have two ways to declare a route with Fastify, the shorthand method and the full declaration. Let's start with the second one:
5<a name="full-declaration"></a>
6### Full declaration
7```js
8fastify.route(options)
9```
10* `method`: currently it supports `'DELETE'`, `'GET'`, `'HEAD'`, `'PATCH'`, `'POST'`, `'PUT'` and `'OPTIONS'`. It could also be an array of methods.
11
12* `url`: the path of the url to match this route (alias: `path`).
13* `schema`: an object containing the schemas for the request and response.
14They need to be in
15 [JSON Schema](http://json-schema.org/) format, check [here](https://github.com/fastify/fastify/blob/master/docs/Validation-and-Serialization.md) for more info.
16
17 * `body`: validates the body of the request if it is a POST or a
18 PUT.
19 * `querystring`: validates the querystring. This can be a complete JSON
20 Schema object, with the property `type` of `object` and `properties` object of parameters, or
21 simply the values of what would be contained in the `properties` object as shown below.
22 * `params`: validates the params.
23 * `response`: filter and generate a schema for the response, setting a
24 schema allows us to have 10-20% more throughput.
25* `attachValidation`: attach `validationError` to request, if there is a schema validation error, instead of sending the error to the error handler.
26* `onRequest(request, reply, done)`: a [function](https://github.com/fastify/fastify/blob/master/docs/Hooks.md#route-hooks) as soon that a request is received, it could also be an array of functions.
27* `preValidation(request, reply, done)`: a [function](https://github.com/fastify/fastify/blob/master/docs/Hooks.md#route-hooks) called after the shared `preValidation` hooks, useful if you need to perform authentication at route level for example, it could also be an array of functions.
28* `preHandler(request, reply, done)`: a [function](https://github.com/fastify/fastify/blob/master/docs/Hooks.md#route-hooks) called just before the request handler, it could also be an array of functions.
29* `preSerialization(request, reply, payload, done)`: a [function](https://github.com/fastify/fastify/blob/master/docs/Hooks.md#route-hooks) called just before the serialization, it could also be an array of functions.
30* `handler(request, reply)`: the function that will handle this request.
31* `schemaCompiler(schema)`: the function that build the schema for the validations. See [here](https://github.com/fastify/fastify/blob/master/docs/Validation-and-Serialization.md#schema-compiler)
32* `bodyLimit`: prevents the default JSON body parser from parsing request bodies larger than this number of bytes. Must be an integer. You may also set this option globally when first creating the Fastify instance with `fastify(options)`. Defaults to `1048576` (1 MiB).
33* `logLevel`: set log level for this route. See below.
34* `config`: object used to store custom configuration.
35* `version`: a [semver](http://semver.org/) compatible string that defined the version of the endpoint. [Example](https://github.com/fastify/fastify/blob/master/docs/Routes.md#version).
36* `prefixTrailingSlash`: string used to determine how to handle passing `/` as a route with a prefix.
37 * `both` (default): Will register both `/prefix` and `/prefix/`.
38 * `slash`: Will register only `/prefix/`.
39 * `no-slash`: Will register only `/prefix`.
40
41 `request` is defined in [Request](https://github.com/fastify/fastify/blob/master/docs/Request.md).
42
43 `reply` is defined in [Reply](https://github.com/fastify/fastify/blob/master/docs/Reply.md).
44
45
46Example:
47```js
48fastify.route({
49 method: 'GET',
50 url: '/',
51 schema: {
52 querystring: {
53 name: { type: 'string' },
54 excitement: { type: 'integer' }
55 },
56 response: {
57 200: {
58 type: 'object',
59 properties: {
60 hello: { type: 'string' }
61 }
62 }
63 }
64 },
65 handler: function (request, reply) {
66 reply.send({ hello: 'world' })
67 }
68})
69```
70
71<a name="shorthand-declaration"></a>
72### Shorthand declaration
73The above route declaration is more *Hapi*-like, but if you prefer an *Express/Restify* approach, we support it as well:<br>
74`fastify.get(path, [options], handler)`<br>
75`fastify.head(path, [options], handler)`<br>
76`fastify.post(path, [options], handler)`<br>
77`fastify.put(path, [options], handler)`<br>
78`fastify.delete(path, [options], handler)`<br>
79`fastify.options(path, [options], handler)`<br>
80`fastify.patch(path, [options], handler)`
81
82Example:
83```js
84const opts = {
85 schema: {
86 response: {
87 200: {
88 type: 'object',
89 properties: {
90 hello: { type: 'string' }
91 }
92 }
93 }
94 }
95}
96fastify.get('/', opts, (request, reply) => {
97 reply.send({ hello: 'world' })
98})
99```
100
101`fastify.all(path, [options], handler)` will add the same handler to all the supported methods.
102
103The handler may also be supplied via the `options` object:
104```js
105const opts = {
106 schema: {
107 response: {
108 200: {
109 type: 'object',
110 properties: {
111 hello: { type: 'string' }
112 }
113 }
114 }
115 },
116 handler (request, reply) {
117 reply.send({ hello: 'world' })
118 }
119}
120fastify.get('/', opts)
121```
122
123> Note: if the handler is specified in both the `options` and as the third parameter to the shortcut method then throws duplicate `handler` error.
124
125<a name="url-building"></a>
126### Url building
127Fastify supports both static and dynamic urls.<br>
128To register a **parametric** path, use the *colon* before the parameter name. For **wildcard** use the *star*.
129*Remember that static routes are always checked before parametric and wildcard.*
130
131```js
132// parametric
133fastify.get('/example/:userId', (request, reply) => {}))
134fastify.get('/example/:userId/:secretToken', (request, reply) => {}))
135
136// wildcard
137fastify.get('/example/*', (request, reply) => {}))
138```
139
140Regular expression routes are supported as well, but pay attention, RegExp are very expensive in term of performance!
141```js
142// parametric with regexp
143fastify.get('/example/:file(^\\d+).png', (request, reply) => {}))
144```
145
146It's possible to define more than one parameter within the same couple of slash ("/"). Such as:
147```js
148fastify.get('/example/near/:lat-:lng/radius/:r', (request, reply) => {}))
149```
150*Remember in this case to use the dash ("-") as parameters separator.*
151
152Finally it's possible to have multiple parameters with RegExp.
153```js
154fastify.get('/example/at/:hour(^\\d{2})h:minute(^\\d{2})m', (request, reply) => {}))
155```
156In this case as parameter separator it's possible to use whatever character is not matched by the regular expression.
157
158Having a route with multiple parameters may affect negatively the performance, so prefer single parameter approach whenever possible, especially on routes which are on the hot path of your application.
159If you are interested in how we handle the routing, checkout [find-my-way](https://github.com/delvedor/find-my-way).
160
161<a name="async-await"></a>
162### Async Await
163Are you an `async/await` user? We have you covered!
164```js
165fastify.get('/', options, async function (request, reply) {
166 var data = await getData()
167 var processed = await processData(data)
168 return processed
169})
170```
171**Warning:** You can't return `undefined`. For more details read [promise-resolution](#promise-resolution).
172
173As you can see we are not calling `reply.send` to send back the data to the user. You just need to return the body and you are done!
174
175If you need it you can also send back the data to the user with `reply.send`.
176```js
177fastify.get('/', options, async function (request, reply) {
178 var data = await getData()
179 var processed = await processData(data)
180 reply.send(processed)
181})
182```
183**Warning:**
184* If you use `return` and `reply.send` at the same time, the first one that happens takes precedence, the second value will be discarded, a *warn* log will also be emitted because you tried to send a response twice.
185* You can't return `undefined`. For more details read [promise-resolution](#promise-resolution).
186
187<a name="promise-resolution"></a>
188### Promise resolution
189
190If your handler is an `async` function or returns a promise, you should be aware of a special behaviour which is necessary to support the callback and promise control-flow. If the handler's promise is resolved with `undefined`, it will be ignored causing the request to hang and an *error* log to be emitted.
191
1921. If you want to use `async/await` or promises but respond a value with `reply.send`:
193 - **Don't** `return` any value.
194 - **Don't** forget to call `reply.send`.
1952. If you want to use `async/await` or promises:
196 - **Don't** use `reply.send`.
197 - **Don't** return `undefined`.
198
199In this way, we can support both `callback-style` and `async-await`, with the minimum trade-off. In spite of so much freedom we highly recommend to go with only one style because error handling should be handled in a consistent way within your application.
200
201**Notice**: Every async function returns a promise by itself.
202
203<a name="route-prefixing"></a>
204### Route Prefixing
205Sometimes you need to maintain two or more different versions of the same api, a classic approach is to prefix all the routes with the api version number, `/v1/user` for example.
206Fastify offers you a fast and smart way to create different version of the same api without changing all the route names by hand, *route prefixing*. Let's see how it works:
207
208```js
209// server.js
210const fastify = require('fastify')()
211
212fastify.register(require('./routes/v1/users'), { prefix: '/v1' })
213fastify.register(require('./routes/v2/users'), { prefix: '/v2' })
214
215fastify.listen(3000)
216```
217```js
218// routes/v1/users.js
219module.exports = function (fastify, opts, next) {
220 fastify.get('/user', handler_v1)
221 next()
222}
223```
224```js
225// routes/v2/users.js
226module.exports = function (fastify, opts, next) {
227 fastify.get('/user', handler_v2)
228 next()
229}
230```
231Fastify will not complain because you are using the same name for two different routes, because at compilation time it will handle the prefix automatically *(this also means that the performance will not be affected at all!)*.
232
233Now your clients will have access to the following routes:
234- `/v1/user`
235- `/v2/user`
236
237You can do this as many times as you want, it works also for nested `register` and routes parameter are supported as well.
238Be aware that if you use [`fastify-plugin`](https://github.com/fastify/fastify-plugin) this option won't work.
239
240#### Handling of / route inside prefixed plugins
241
242The `/` route has a different behavior depending if the prefix ends with
243`/` or not. As an example, if we consider a prefix `/something/`,
244adding a `/` route will only match `/something/`. If we consider a
245prefix `/something`, adding a `/` route will match both `/something` 
246and `/something/`.
247
248See the `prefixTrailingSlash` route option above to change this behaviour.
249
250<a name="custom-log-level"></a>
251### Custom Log Level
252It could happen that you need different log levels in your routes, with Fastify achieve this is very straightforward.<br/>
253You just need to pass the option `logLevel` to the plugin option or the route option with the [value](https://github.com/pinojs/pino/blob/master/docs/API.md#discussion-3) that you need.
254
255Be aware that if you set the `logLevel` at plugin level, also the [`setNotFoundHandler`](https://github.com/fastify/fastify/blob/master/docs/Server.md#setnotfoundhandler) and [`setErrorHandler`](https://github.com/fastify/fastify/blob/master/docs/Server.md#seterrorhandler) will be affected.
256
257```js
258// server.js
259const fastify = require('fastify')({ logger: true })
260
261fastify.register(require('./routes/user'), { logLevel: 'warn' })
262fastify.register(require('./routes/events'), { logLevel: 'debug' })
263
264fastify.listen(3000)
265```
266Or you can directly pass it to a route:
267```js
268fastify.get('/', { logLevel: 'warn' }, (request, reply) => {
269 reply.send({ hello: 'world' })
270})
271```
272*Remember that the custom log level is applied only to the routes, and not to the global Fastify Logger, accessible with `fastify.log`*
273
274
275<a name="routes-config"></a>
276### Config
277Registering a new handler, you can pass a configuration object to it and retrieve it in the handler.
278
279```js
280// server.js
281const fastify = require('fastify')()
282
283function handler (req, reply) {
284 reply.send(reply.context.config.output)
285}
286
287fastify.get('/en', { config: { output: 'hello world!' } }, handler)
288fastify.get('/it', { config: { output: 'ciao mondo!' } }, handler)
289
290fastify.listen(3000)
291```
292
293<a name="version"></a>
294### Version
295#### Default
296If needed you can provide a version option, which will allow you to declare multiple versions of the same route. The versioning should follow the [semver](http://semver.org/) specification.<br/>
297Fastify will automatically detect the `Accept-Version` header and route the request accordingly (advanced ranges and pre-releases currently are not supported).<br/>
298*Be aware that using this feature will cause a degradation of the overall performances of the router.*
299```js
300fastify.route({
301 method: 'GET',
302 url: '/',
303 version: '1.2.0',
304 handler: function (request, reply) {
305 reply.send({ hello: 'world' })
306 }
307})
308
309fastify.inject({
310 method: 'GET',
311 url: '/',
312 headers: {
313 'Accept-Version': '1.x' // it could also be '1.2.0' or '1.2.x'
314 }
315}, (err, res) => {
316 // { hello: 'world' }
317})
318```
319If you declare multiple versions with the same major or minor, Fastify will always choose the highest compatible with the `Accept-Version` header value.<br/>
320If the request will not have the `Accept-Version` header, a 404 error will be returned.
321#### Custom
322It's possible to define a custom versioning logic. This can be done through the [`versioning`](https://github.com/fastify/fastify/blob/master/docs/Server.md#versioning) configuration, when creating a fastify server instance.