Skip to content

Commit

Permalink
Updated documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
delvedor committed Nov 13, 2017
1 parent 64b35b8 commit cfc5ccf
Show file tree
Hide file tree
Showing 3 changed files with 214 additions and 84 deletions.
208 changes: 149 additions & 59 deletions docs/Getting-Started.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
<h1 align="center">Fastify</h1>

## Getting Started
Hello! Thank you for checking out Fastify!
This document aims to be a gentle introduction to the framework and its features. You will find some easy explanation, examples and link to other parts of the documentation if you want to get deepen in some argument.
Let's start!

<a name="install"></a>
### Install
```
npm i fastify --save
```
<a name="first-server"></a>
### Your first server
Let's write a *Hello world* server!
Let's write our first server:
```js
// Require the framework and instantiate it
const fastify = require('fastify')()
Expand All @@ -24,30 +29,13 @@ fastify.listen(3000, function (err) {
})
```

Do you prefer to use `async/await`? Please review [Routes#async-await](https://github.com/fastify/fastify/blob/master/docs/Routes.md#async-await)!

<a name="schema"></a>
### Schema serialization
Fastify is designed for performance. To truly turbocharge our server, we can serialize responses according to the [JSON Schema](http://json-schema.org/) standard:
Do you prefer to use `async/await`? We got you covered.
*(we also suggest to use [make-promises-safe](https://github.com/mcollina/make-promises-safe) to avoid file descriptor and memory leaks)*
```js
const fastify = require('fastify')()

const opts = {
schema: {
response: {
200: {
type: 'object',
properties: {
hello: { type: 'string' }
}
}
}
}
}

// Declare a route with an output schema
fastify.get('/', opts, function (request, reply) {
reply.send({ hello: 'world' })
fastify.get('/', async (request, reply) => {
return { hello: 'world' }
})

fastify.listen(3000, function (err) {
Expand All @@ -56,61 +44,167 @@ fastify.listen(3000, function (err) {
})
```

*To learn more about using serialization and validation, see [Validation and Serialization](https://github.com/fastify/fastify/blob/master/docs/Validation-and-Serialization.md)!*
Awesome, that was easy.
Unfortunately, write a complex application requires definitely more code than what we wrote above. A classic problem when you are building a new application is how handle multiple files, asynchronous bootstrapping and the architecture of your code.
Fastify offers you out of the box an easy to use system that will help you handle all this problems and more.

<a name="register"></a>
### Register
As you can see, using Fastify is very easy and handy. Obviously, registering all of your routes in the same file is not a good idea, so Fastify offers a utility to solve this problem, `register`:
<a name="first-plugin"></a>
### Your first plugin
As in javascript everything is an object, in Fastify everything is a plugin.
Before digging into it, let's see how it works!
Let's declare our basic server, but instead of declare the route inside the entry point, we'll declare it in an external file (checkout the [route declaration](https://github.com/fastify/fastify/blob/master/docs/Routes.md) docs).
```js
/* server.js */

const fastify = require('fastify')()

fastify.register(require('./route'))
fastify.register(require('./our-first-route'))

const opts = {
hello: 'world',
something: true
fastify.listen(3000, function (err) {
if (err) throw err
console.log(`server listening on ${fastify.server.address().port}`)
})
```

```js
// our-first-route.js

async function routes (fastify, options) {
fastify.get('/', async (request, reply) => {
return { hello: 'world' }
})
}

fastify.register([
require('./another-route'),
require('./yet-another-route')
], opts, function (err) {
if (err) throw err
module.exports = routes
```
As you can see we used the `register` api, that you will use a lot when working with Fastify, since is the only way to register routes, plugins and so on.

At the beginning of this document we said that Fastify helps you on handling the asynchronous bootstrapping of your application. Why this is important?
Well, let's say you must connect to database to fetch some data, obviously you don't want that the server starts accept requests before the database connection has been established. How can you address this problem?
Usually you will work with some complex callback/promises system that will mix the framework api with other libraries and your code.
Fastify handles this internally for you, with the minimum effort!

Let's rewrite the above example with a database connection.
*(now we'll use a simple example, if you want a robust sulution you can use [`fastify-mongo`](https://github.com/fastify/fastify-mongodb) or checkout our [ecosystem](https://github.com/fastify/fastify/blob/master/docs/Ecosystem.md))*
```js
const fastify = require('fastify')()

fastify.register(require('./our-db-connector'), {
url: 'mongodb://mongo/db'
})
fastify.register(require('./our-first-route'))

fastify.listen(8000, function (err) {
fastify.listen(3000, function (err) {
if (err) throw err
console.log(`server listening on ${fastify.server.address().port}`)
})
```

```js
/* route.js */
// our-db-connector.js
const MongoClient = require('mongodb').MongoClient

module.exports = function (fastify, options, next) {
fastify.get('/', function (req, reply) {
reply.send({ hello: 'world' })
})
next()
async function db (fastify, options) {
const url = options.url
delete options.url

const db = await MongoClient.connect(url, options)
fastify.decorate('mongo', db)
}

module.exports = db
```

or with `async/await`:
```js
/* route.js */
// our-first-route.js

async function routes (fastify, options) {
const collection = fastify.mongo.collection('test')

module.exports = async function (fastify, options) {
fastify.get('/', function (req, reply) {
reply.send({ hello: 'world' })
fastify.get('/', async (request, reply) => {
return { hello: 'world' }
})

fastify.get('/search/:id', async (request, reply) => {
return await collection.findOne({ id: req.params.id })
})
}

module.exports = routes
```

Wow, that was fast!
Let's recap what we have done here, since we've introduced different things.
As you can see, we used `register` both for the database connector and the routes registration.
This is one of the best features of Fastify, it will load your plugins in the same order you declare them, and it will load the next plugin only once the current one has been loaded. In this way we can register the database connector in the first plugin and use it in the second.

We have used the `decorate` api. Let's take a moment to understand what is and how it works. A typic thing that you'll need is to use the same code/library in different parts of your application. A solution is to require the code/library that you need everywhere, it works, but is annoying because of code repeated and if needed, long refactors.
To solve this Fastify offers you a nice api, `decorate`, which add your code/library in the Fastify namespace, in way that you can use it everywhere.

If you want to get deepen on how plugins works, how can you develop plugins for Fastify or use all the apis that the framework offers to share your code around the application and how handle the complexity given by the asynchronous bootstrapping, checkout [the hitchhiker's guide to plugins](https://github.com/fastify/fastify/blob/master/docs/Plugins.md).

<a name="validate-data"></a>
### Validate your data
Data validation is extremely important and is a core concept of the framework.
To validate your incoming requests, Fastify uses [JSON Schema](http://json-schema.org/).
Let's see an example on how validate your routes:
```js
const opts = {
schema: {
body: {
type: 'object',
properties: {
someKey: { type: 'string' },
someOtherKey: { type: 'number' }
}
}
}
}

fastify.post('/', opts, async (request, reply) => {
return { hello: 'world' }
})
```
As you can see you can pass an options object to the route, which accepts a `schema` key, that will contain all the schemas for your route, `body`, `querystring`, `params` and `headers`.
Checkout [Validation and Serialization](https://github.com/fastify/fastify/blob/master/docs/Validation-and-Serialization.md) to know more.

<a name="serialize-data"></a>
### Serialize your data
Fastify comes with a first class support for JSON. It is extremely optimized to parse JSON body and to serialize JSON output.
To speed up your JSON serialization (yes, it is slow!) you must use the `response` key of the schema option. Following hot it works:
```js
const opts = {
schema: {
response: {
200: {
type: 'object',
properties: {
hello: { type: 'string' }
}
}
}
}
}

fastify.get('/', opts, async (request, reply) => {
return { hello: 'world' }
})
```
Just by using the above code you will speed up your serialization by 2x or even 3x than before, and you will be also protected from the leaking of sensitive data, since the Fastify will serialize just the data present in your response schema.
Checkout [Validation and Serialization](https://github.com/fastify/fastify/blob/master/docs/Validation-and-Serialization.md) to know more.

<a name="extend-server"></a>
### Extend your server
Fastify is built to be extremely extensible and it's very minimal, we believe that provide a fully featured framework is not needed, since it will probably give you more than what you need.
In other words, Fastify is not batteries included and if you need them, checkout our amazing [ecosystem](https://github.com/fastify/fastify/blob/master/docs/Ecosystem.md)!

<a name="test-server"></a>
### Test your server
We not offer a testing framework, but we do recommend a way to write your test that uses in a smart way the features and the architecture of Fastify.
Checkout the [testing](https://github.com/fastify/fastify/blob/master/docs/Testing.md) documentation!

<a name="cli"></a>
### Run from CLI
You can also run Fastify from the CLI thanks to [fastify-cli](https://github.com/fastify/fastify-cli). It's very easy! Simply add the following lines to your `package.json`:
### Run your server from CLI
You can also run Fastify from the CLI thanks to [fastify-cli](https://github.com/fastify/fastify-cli). It's very easy!
Simply add the following lines to your `package.json`:
```json
{
"scripts": {
Expand All @@ -124,11 +218,10 @@ And create your server file(s):
// server.js
'use strict'

module.exports = function (fastify, opts, next) {
fastify.get('/', (req, reply) => {
reply.send({ hello: 'world' })
module.exports = async function (fastify, opts) {
fastify.get('/', async (req, reply) => {
return { hello: 'world' }
})
next()
}
```

Expand All @@ -145,7 +238,4 @@ npm start

- Videos
- [Take your HTTP server to ludicrous speed](https://www.youtube.com/watch?v=5z46jJZNe8k) by [@mcollina](https://github.com/mcollina)

<a name="next"></a>
### Next
Do you want to learn more? Check out the documentation folder located [here](https://github.com/fastify/fastify/blob/master/docs/)!
- [What if I told you that HTTP can be fast](https://www.webexpo.net/prague2017/talk/what-if-i-told-you-that-http-can-be-fast/) by [@delvedor](https://github.com/delvedor)
23 changes: 21 additions & 2 deletions docs/Plugins-Guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ Your routes, your utilities and so on are all plugins. And to add a new plugin,
```js
fastify.register(
require('./my-plugin'),
{ options },
callback
{ options }
)
```
`register` creates for you a new Fastify context, this means that if you do any change to the Fastify instance, that change(s) will not be reflected into the context's ancestors. In other words, encapsulation!
Expand Down Expand Up @@ -271,6 +270,26 @@ module.exports = fp(dbPlugin)
```
You can also tell to `fastify-plugin` to check the installed version of Fastify, in case of you need a specific api.

<a name="handle-errors"></a>
## Handle errors
It can happen that one of your plugins could fail during the startup. Maybe you expect it and you have a custom logic that will be triggered in that case. How can you do this?
The `after` api is what you need. `after` simply register a callback that will be executed just after a register, and it can take up to three parameters.
The callback changes basing on the parameters your are giving:

1. If no parameter is given to the callback and there is an error, that error will be passed to the next error handler.
1. If one parameter is given to the callback, that parameter will be the error object.
1. If two parameters are given to the callback, the first will be the error object, the second will be the done callback.
1. If three parameters are given to the callback, the first will be the error object, the second will be the top level context unless you have specified both server and override, in that case the context will be what the override returns, and the third the done callback.

Let's see how use it:
```js
fastify
.register(require('./database-connector'))
.after(err => {
if (err) throw err
})
```

<a name="start"></a>
## Let's start!
Awesome, now you know everything you need to know about Fastify and its plugin system to start building your first plugin, and please if you do, tell us! We will add it to the [*ecosystem*](https://github.com/fastify/fastify#ecosystem) section of our documentation!
Expand Down

0 comments on commit cfc5ccf

Please sign in to comment.