CoolFace
Apppublic

strong-tie/inbound-calls

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
Getting-Started.md617 linesDownload Raw Back to Guides
1<h1 align="center">Fastify</h1>2 3## Getting Started4 5Hello! Thank you for checking out Fastify!6 7This document aims to be a gentle introduction to the framework and its8features. It is an elementary preface with examples and links to other parts of9the documentation.10 11Let's start!12 13### Install14<a id="install"></a>15 16Install with npm:17```sh18npm i fastify19```20 21Install with yarn:22```sh23yarn add fastify24```25 26### Your first server27<a id="first-server"></a>28 29Let's write our first server:30```js31// Require the framework and instantiate it32 33// ESM34import Fastify from 'fastify'35 36const fastify = Fastify({37  logger: true38})39// CommonJs40const fastify = require('fastify')({41  logger: true42})43 44// Declare a route45fastify.get('/', function (request, reply) {46  reply.send({ hello: 'world' })47})48 49// Run the server!50fastify.listen({ port: 3000 }, function (err, address) {51  if (err) {52    fastify.log.error(err)53    process.exit(1)54  }55  // Server is now listening on ${address}56})57```58 59> If you are using ECMAScript Modules (ESM) in your project, be sure to60> include "type": "module" in your package.json.61>```js62>{63>  "type": "module"64>}65>```66 67Do you prefer to use `async/await`? Fastify supports it out-of-the-box.68 69```js70// ESM71import Fastify from 'fastify'72 73const fastify = Fastify({74  logger: true75})76// CommonJs77const fastify = require('fastify')({78  logger: true79})80 81fastify.get('/', async (request, reply) => {82  return { hello: 'world' }83})84 85/**86 * Run the server!87 */88const start = async () => {89  try {90    await fastify.listen({ port: 3000 })91  } catch (err) {92    fastify.log.error(err)93    process.exit(1)94  }95}96start()97```98 99Awesome, that was easy.100 101Unfortunately, writing a complex application requires significantly more code102than this example. A classic problem when you are building a new application is103how to handle multiple files, asynchronous bootstrapping, and the architecture104of your code.105 106Fastify offers an easy platform that helps to solve all of the problems outlined107above, and more!108 109> ## Note110> The above examples, and subsequent examples in this document, default to111> listening *only* on the localhost `127.0.0.1` interface. To listen on all112> available IPv4 interfaces the example should be modified to listen on113> `0.0.0.0` like so:114>115> ```js116> fastify.listen({ port: 3000, host: '0.0.0.0' }, function (err, address) {117>   if (err) {118>     fastify.log.error(err)119>     process.exit(1)120>   }121>   fastify.log.info(`server listening on ${address}`)122> })123> ```124>125> Similarly, specify `::1` to accept only local connections via IPv6. Or specify126> `::` to accept connections on all IPv6 addresses, and, if the operating system127> supports it, also on all IPv4 addresses.128>129> When deploying to a Docker (or another type of) container using `0.0.0.0` or130> `::` would be the easiest method for exposing the application.131 132### Your first plugin133<a id="first-plugin"></a>134 135As with JavaScript, where everything is an object, with Fastify everything is a136plugin.137 138Before digging into it, let's see how it works!139 140Let's declare our basic server, but instead of declaring the route inside the141entry point, we'll declare it in an external file (check out the [route142declaration](../Reference/Routes.md) docs).143```js144// ESM145import Fastify from 'fastify'146import firstRoute from './our-first-route.js'147/**148 * @type {import('fastify').FastifyInstance} Instance of Fastify149 */150const fastify = Fastify({151  logger: true152})153 154fastify.register(firstRoute)155 156fastify.listen({ port: 3000 }, function (err, address) {157  if (err) {158    fastify.log.error(err)159    process.exit(1)160  }161  // Server is now listening on ${address}162})163```164 165```js166// CommonJs167/**168 * @type {import('fastify').FastifyInstance} Instance of Fastify169 */170const fastify = require('fastify')({171  logger: true172})173 174fastify.register(require('./our-first-route'))175 176fastify.listen({ port: 3000 }, function (err, address) {177  if (err) {178    fastify.log.error(err)179    process.exit(1)180  }181  // Server is now listening on ${address}182})183```184 185 186```js187// our-first-route.js188 189/**190 * Encapsulates the routes191 * @param {FastifyInstance} fastify  Encapsulated Fastify Instance192 * @param {Object} options plugin options, refer to https://fastify.dev/docs/latest/Reference/Plugins/#plugin-options193 */194async function routes (fastify, options) {195  fastify.get('/', async (request, reply) => {196    return { hello: 'world' }197  })198}199 200//ESM201export default routes;202 203// CommonJs204module.exports = routes205```206In this example, we used the `register` API, which is the core of the Fastify207framework. It is the only way to add routes, plugins, et cetera.208 209At the beginning of this guide, we noted that Fastify provides a foundation that210assists with asynchronous bootstrapping of your application. Why is this211important?212 213Consider the scenario where a database connection is needed to handle data214storage. The database connection needs to be available before the server is215accepting connections. How do we address this problem?216 217A typical solution is to use a complex callback, or promises - a system that218will mix the framework API with other libraries and the application code.219 220Fastify handles this internally, with minimum effort!221 222Let's rewrite the above example with a database connection.223 224 225First, install `fastify-plugin` and `@fastify/mongodb`:226 227```sh228npm i fastify-plugin @fastify/mongodb229```230 231**server.js**232```js233// ESM234import Fastify from 'fastify'235import dbConnector from './our-db-connector.js'236import firstRoute from './our-first-route.js'237 238/**239 * @type {import('fastify').FastifyInstance} Instance of Fastify240 */241const fastify = Fastify({242  logger: true243})244fastify.register(dbConnector)245fastify.register(firstRoute)246 247fastify.listen({ port: 3000 }, function (err, address) {248  if (err) {249    fastify.log.error(err)250    process.exit(1)251  }252  // Server is now listening on ${address}253})254```255 256```js257// CommonJs258/**259 * @type {import('fastify').FastifyInstance} Instance of Fastify260 */261const fastify = require('fastify')({262  logger: true263})264 265fastify.register(require('./our-db-connector'))266fastify.register(require('./our-first-route'))267 268fastify.listen({ port: 3000 }, function (err, address) {269  if (err) {270    fastify.log.error(err)271    process.exit(1)272  }273  // Server is now listening on ${address}274})275 276```277 278**our-db-connector.js**279```js280// ESM281import fastifyPlugin from 'fastify-plugin'282import fastifyMongo from '@fastify/mongodb'283 284/**285 * @param {FastifyInstance} fastify286 * @param {Object} options287 */288async function dbConnector (fastify, options) {289  fastify.register(fastifyMongo, {290    url: 'mongodb://localhost:27017/test_database'291  })292}293 294// Wrapping a plugin function with fastify-plugin exposes the decorators295// and hooks, declared inside the plugin to the parent scope.296export default fastifyPlugin(dbConnector)297 298```299 300```js301// CommonJs302/**303 * @type {import('fastify-plugin').FastifyPlugin}304 */305const fastifyPlugin = require('fastify-plugin')306 307 308/**309 * Connects to a MongoDB database310 * @param {FastifyInstance} fastify Encapsulated Fastify Instance311 * @param {Object} options plugin options, refer to https://fastify.dev/docs/latest/Reference/Plugins/#plugin-options312 */313async function dbConnector (fastify, options) {314  fastify.register(require('@fastify/mongodb'), {315    url: 'mongodb://localhost:27017/test_database'316  })317}318 319// Wrapping a plugin function with fastify-plugin exposes the decorators320// and hooks, declared inside the plugin to the parent scope.321module.exports = fastifyPlugin(dbConnector)322 323```324 325**our-first-route.js**326```js327/**328 * A plugin that provide encapsulated routes329 * @param {FastifyInstance} fastify encapsulated fastify instance330 * @param {Object} options plugin options, refer to https://fastify.dev/docs/latest/Reference/Plugins/#plugin-options331 */332async function routes (fastify, options) {333  const collection = fastify.mongo.db.collection('test_collection')334 335  fastify.get('/', async (request, reply) => {336    return { hello: 'world' }337  })338 339  fastify.get('/animals', async (request, reply) => {340    const result = await collection.find().toArray()341    if (result.length === 0) {342      throw new Error('No documents found')343    }344    return result345  })346 347  fastify.get('/animals/:animal', async (request, reply) => {348    const result = await collection.findOne({ animal: request.params.animal })349    if (!result) {350      throw new Error('Invalid value')351    }352    return result353  })354 355  const animalBodyJsonSchema = {356    type: 'object',357    required: ['animal'],358    properties: {359      animal: { type: 'string' },360    },361  }362 363  const schema = {364    body: animalBodyJsonSchema,365  }366 367  fastify.post('/animals', { schema }, async (request, reply) => {368    // we can use the `request.body` object to get the data sent by the client369    const result = await collection.insertOne({ animal: request.body.animal })370    return result371  })372}373 374module.exports = routes375```376 377Wow, that was fast!378 379Let's recap what we have done here since we've introduced some new concepts.380 381As you can see, we used `register` for both the database connector and the382registration of the routes.383 384This is one of the best features of Fastify, it will load your plugins in the385same order you declare them, and it will load the next plugin only once the386current one has been loaded. In this way, we can register the database connector387in the first plugin and use it in the second *(read388[here](../Reference/Plugins.md#handle-the-scope) to understand how to handle the389scope of a plugin)*.390 391Plugin loading starts when you call `fastify.listen()`, `fastify.inject()` or392`fastify.ready()`393 394The MongoDB plugin uses the `decorate` API to add custom objects to the Fastify395instance, making them available for use everywhere. Use of this API is396encouraged to facilitate easy code reuse and to decrease code or logic397duplication.398 399To dig deeper into how Fastify plugins work, how to develop new plugins, and for400details on how to use the whole Fastify API to deal with the complexity of401asynchronously bootstrapping an application, read [the hitchhiker's guide to402plugins](./Plugins-Guide.md).403 404### Loading order of your plugins405<a id="plugin-loading-order"></a>406 407To guarantee consistent and predictable behavior of your application, we highly408recommend to always load your code as shown below:409```410└── plugins (from the Fastify ecosystem)411└── your plugins (your custom plugins)412└── decorators413└── hooks414└── your services415```416In this way, you will always have access to all of the properties declared in417the current scope.418 419As discussed previously, Fastify offers a solid encapsulation model, to help you420build your application as single and independent services. If you want to421register a plugin only for a subset of routes, you just have to replicate the422above structure.423```424└── plugins (from the Fastify ecosystem)425└── your plugins (your custom plugins)426└── decorators427└── hooks428└── your services429    │430    └──  service A431    │     └── plugins (from the Fastify ecosystem)432    │     └── your plugins (your custom plugins)433    │     └── decorators434    │     └── hooks435    │     └── your services436    │437    └──  service B438          └── plugins (from the Fastify ecosystem)439          └── your plugins (your custom plugins)440          └── decorators441          └── hooks442          └── your services443```444 445### Validate your data446<a id="validate-data"></a>447 448Data validation is extremely important and a core concept of the framework.449 450To validate incoming requests, Fastify uses [JSON451Schema](https://json-schema.org/).452 453Let's look at an example demonstrating validation for routes:454```js455/**456 * @type {import('fastify').RouteShorthandOptions}457 * @const458 */459const opts = {460  schema: {461    body: {462      type: 'object',463      properties: {464        someKey: { type: 'string' },465        someOtherKey: { type: 'number' }466      }467    }468  }469}470 471fastify.post('/', opts, async (request, reply) => {472  return { hello: 'world' }473})474```475This example shows how to pass an options object to the route, which accepts a476`schema` key that contains all of the schemas for route, `body`, `querystring`,477`params`, and `headers`.478 479Read [Validation and480Serialization](../Reference/Validation-and-Serialization.md) to learn more.481 482### Serialize your data483<a id="serialize-data"></a>484 485Fastify has first-class support for JSON. It is extremely optimized to parse486JSON bodies and serialize JSON output.487 488To speed up JSON serialization (yes, it is slow!) use the `response` key of the489schema option as shown in the following example:490```js491/**492 * @type {import('fastify').RouteShorthandOptions}493 * @const494 */495const opts = {496  schema: {497    response: {498      200: {499        type: 'object',500        properties: {501          hello: { type: 'string' }502        }503      }504    }505  }506}507 508fastify.get('/', opts, async (request, reply) => {509  return { hello: 'world' }510})511```512By specifying a schema as shown, you can speed up serialization by a factor of5132-3. This also helps to protect against leakage of potentially sensitive data,514since Fastify will serialize only the data present in the response schema. Read515[Validation and Serialization](../Reference/Validation-and-Serialization.md) to516learn more.517 518### Parsing request payloads519<a id="request-payload"></a>520 521Fastify parses `'application/json'` and `'text/plain'` request payloads522natively, with the result accessible from the [Fastify523request](../Reference/Request.md) object at `request.body`.524 525The following example returns the parsed body of a request back to the client:526 527```js528/**529 * @type {import('fastify').RouteShorthandOptions}530 */531const opts = {}532fastify.post('/', opts, async (request, reply) => {533  return request.body534})535```536 537Read [Content-Type Parser](../Reference/ContentTypeParser.md) to learn more538about Fastify's default parsing functionality and how to support other content539types.540 541### Extend your server542<a id="extend-server"></a>543 544Fastify is built to be extremely extensible and minimal, we believe that a545bare-bones framework is all that is necessary to make great applications546possible.547 548In other words, Fastify is not a "batteries included" framework, and relies on549an amazing [ecosystem](./Ecosystem.md)!550 551### Test your server552<a id="test-server"></a>553 554Fastify does not offer a testing framework, but we do recommend a way to write555your tests that use the features and architecture of Fastify.556 557Read the [testing](./Testing.md) documentation to learn more!558 559### Run your server from CLI560<a id="cli"></a>561 562Fastify also has CLI integration thanks to563[fastify-cli](https://github.com/fastify/fastify-cli).564 565First, install `fastify-cli`:566 567```sh568npm i fastify-cli569```570 571You can also install it globally with `-g`.572 573Then, add the following lines to `package.json`:574```json575{576  "scripts": {577    "start": "fastify start server.js"578  }579}580```581 582And create your server file(s):583```js584// server.js585'use strict'586 587module.exports = async function (fastify, opts) {588  fastify.get('/', async (request, reply) => {589    return { hello: 'world' }590  })591}592```593 594Then run your server with:595```bash596npm start597```598 599### Slides and Videos600<a id="slides"></a>601 602- Slides603  - [Take your HTTP server to ludicrous604    speed](https://mcollina.github.io/take-your-http-server-to-ludicrous-speed)605    by [@mcollina](https://github.com/mcollina)606  - [What if I told you that HTTP can be607    fast](https://delvedor.github.io/What-if-I-told-you-that-HTTP-can-be-fast)608    by [@delvedor](https://github.com/delvedor)609 610- Videos611  - [Take your HTTP server to ludicrous612    speed](https://www.youtube.com/watch?v=5z46jJZNe8k) by613    [@mcollina](https://github.com/mcollina)614  - [What if I told you that HTTP can be615    fast](https://www.webexpo.net/prague2017/talk/what-if-i-told-you-that-http-can-be-fast/)616    by [@delvedor](https://github.com/delvedor)617