How i structure my Fastify application
Tags: node, fastify, javascript
Published: 2021-07-04 16:35:09

Fastify is obviously a great choice to start with a REST API application, it's very simple to go up and running, it's full of already made and tested plugins, and finally, is also (as the name says) fast.

However, I noticed, and also tried it on my skin, that there is a common problem of structuring the application folder to have a solution that can scale, but without tons of directories.

So, I decided to write an article to share the configuration that I use on my Fastify projects. The goal is to give the reader some starting point for his app, this is not the 100% correct solution for all the projects, but a solution which in my case was correct.

So, let's get started!

## First, app.js and server.js

The first thing that I do is split, the app initialization from the app entry point into two separate files, `app.js` and `server.js`, this became really helpful because you can have all your app routes and plugins initialized in a common **build** function in the app.js, and the app listening in the server.js.

This an example of app.js:

```javascript
require("dotenv").config();

const fastify = require("fastify");
const cookie = require("fastify-cookie");

const { debug } = require("./routes/debug");
const { auth } = require("./routes/auth");
const { me } = require("./routes/me");

const build = (opts = {}) => {
  const app = fastify(opts);

  app.register(cookie);

  app.register(debug);
  app.register(me, { prefix: "/v2/me" });
  app.register(auth, { prefix: "/v2/auth" });

  return app;
};

module.exports = { build };
```

An this an example of the server.js:

```javascript
const { build } = require("./app.js");

const app = build({ logger: true });

app.listen(process.env.PORT || 5000, "0.0.0.0", (err, address) => {
  if (err) {
    console.log(err);
    process.exit(1);
  }
});
```

As you can see, the app Is the returning object of the **build** function, so if I need it in another place (unit testing for example), I can simply import the build function.

## Second, application routes

For the logic of the routes, I prefer to split all of them into separate files with the discriminant of logic. Probably you have noticed in the example before these rows:

```javascript
app.register(debug);
app.register(me, { prefix: "/v2/me" });
app.register(auth, { prefix: "/v2/auth" });
```

The idea here is, my *app.js* is the main reference, in this file I can see all the "macro" routes, and have some first impact logic flow. All the logic of all the single routes though are specified in its file.

This improves a lot the application code quality and also permits discrete scalability. Also, you can wrap some middleware like the JWT validation in a specific route file in order to apply the common logic to all the subroutes of the file.

An example of the me.js routes file:

```javascript
const me = (fastify, _, done) => {
  fastify.addHook("onRequest", (request) => request.jwtVerify());

  fastify.get("/", getMe);
  fastify.put("/", putMeOpts, putMe);

  done();
};
```

## Third, lib and utils folders

There is always some quarrel between the purpose of the lib folder and that of the utils folder, now I tell you mine.

I use the utils folder principally for something very common, which I can use in every piece of code. You know, something like a **sum** functions, or some constants declaration, or maybe a hashing function, every piece of code which has a logic only for itself.

```javascript
// ./utils/hash.js

const bcrypt = require("bcryptjs");

const hash = (plainText) => bcrypt.hashSync(plainText, 10);

const verify = (plainText, hashText) => bcrypt.compareSync(plainText, hashText);

module.exports = { hash, verify };
```

The lib folder instead, it's the container for the app business logic, which is not "repeatable", something like the database factory, or the database queries.

```javascript
// ./lib/db.js

export async function deleteWebsite(seed) {
  return new Website()
    .where("seed", seed)
    .destroy();
}
``` 

## Fourth, static files

For the static files is very simple, I use the fastify-static plugin, and I store all the public data in a public folder. Please don't use silly names :)

## Fifth, unit testing

For the final point, all I need to do is to connect all the previous broken pieces and work with them, in my case, I usually do testing with Jest, but is quite the same with other frameworks.

Under every directory, I place a *__tests__* folder, and I name the files as the real application file, so `me.js => me.test.js`, and i recall at the build function on top of this article. Something like this:

```javascript
  it("does login", async () => {
    const app = await build();
    const response = await app.inject({
      method: "POST",
      url: "/v2/auth/login",
      payload: {
        email: "info@renatopozzi.me",
        password: "password",
      },
    });

    expect(response.statusCode).toBe(200);
    expect(JSON.parse(response.body)).toHaveProperty("access_token");
  });
```

Notice that I use the *inject* method from fastify, so I don't need to run a server in order to do some testing.

## Wrapping up

So today we saw something quite common in the "microframeworks" world, the app structure, I hope this article has brought you some inspiration for your next projects!

If you are interested in learning more, I have created an open-source project in fastify, you can look at the sources from [here](https://github.com/useaurora/api) if you are interested!

Hope to find you again soon!

While you're there, follow me on [Twitter](https://twitter.com/imarenny)!