Video Summary and Transcription
This video talk covers building web applications with Fastify, a web framework started in 2016. It guides you through installing Fastify using NPM and explains how to create a simple app that listens on port 3000. The talk emphasizes the importance of logging, showing how to enable it with 'logger: true' and use 'prettyPrint: true' for better readability. It also demonstrates how to split Fastify routes in separate files using Fastify auto-load, and how to handle authentication with Fastify JWT. The video covers unit testing with the tape utility and implementing data validation using Fluent Schema. Additionally, it touches on Fastify's lifecycle-based pattern for handling routes, its support for native Node ESM, and its performance benefits. You also learn about configuring a login system, generating JWT tokens, and testing protected routes. The speaker highlights the flexibility of Fastify and its modern JavaScript features like async/await.
1. Introduction to Fastify
I am Matteo Collina, here to talk about Fastify. Fastify is a web framework started in 2016. Install it with NPM. Easy to use. Let's build a simple app. Import Fastify. Use Node 14. Create app. Listen on port 3000. Server started. Route not found. No logs.
Everyone, I am Matteo Collina. And I'm here today to talk to you about Fastify. Please take a moment to follow me on Twitter, at Matteo Collina. I tweet about Node.js development and a bunch of other things. So yeah, maybe you can find it interesting.
Anyway, we are here to talk about Fastify. This is, you know, we are all remote, it's all distributed around the globe. So this talk, I'm going to try something that I normally don't try on stage. So maybe let's see how it goes. So first of all, Fastify is a web framework that myself and Thomas De La Vedo started back in 2016. And now it's coming up to be the major version 3, which is going to be released soon-ish.
Anyway, how do you install it? NPM install Fastify. And it's actually very easy to use. However, we are not going to talk a lot about it, but we are going to actually use it to actually build a very, very simple app. So first of all, we can just start by, you know, having our own server and we can import Fastify. Oh, by the way, folks, I am going to use a Node 14. Why? Because I want to use the new ESM features of of Node Core. So, you know, so that's that's what you're going to use. So we can do import Fastify from Fastify. Then I can create my app. And and then I can do app.listen on port 3000. Whoa. OK. So maybe this server. Oh, and VMUse 14. Hey, so this server has started. And then I can curl it and then, oh, well, route not found. Yeah, we didn't add any. So that makes total sense. However, we also if you look at it, it also didn't log anything.
2. Adding a Logger
We can add a logger by setting logger true. In development, set pretty print true for nicer output. The logger logs twice for each request, when it comes in and when it comes out.
So maybe we just want to add a little bit of a logger here. So which is probably useful. So we can do logger true and we can start it back. Oh, now it says server listening. It logs in new line. Delimited JSON, it use another library called Pinot to log. Still, we are getting some output out of it. However, if we are in development, what you can actually do is do pretty print true only in development. And if we do this, we will get a little bit more nicer output out of it. Note that it just logs twice for each request, logs when a request comes in and when a request comes out. Pretty nice and handy.
3. Splitting the App and Using Fastify Auto-load
We split the app into another file called app.js. We create a Fastify plugin and add routes. We can use a module called Fastify auto-load to load routes from a separate file. We create a routes folder and a hello.js file. We copy the block of code into hello.js and add the plugin. Done.
OK, so that's the basic of our app. We have started Fastify. So what we are up to now is what we want to do is we can actually split it up because, you know, we can't just code on one single server. So what we are going to do is we are going to do another file called app.js.
So what we do, we do as per default and then we create what we call a Fastify plugin. So and my app. So app and we can add our routes here. For example, get slash and then a sync and then return a low word. Hey, I'm a single quote person. So anyway, so that's it. We are in here. So if I restart this and then occur, whoa, still don't go. I need to actually load this. So what I can do, I can do app register. I can use import because we're doing ESM, right? So app.js and then here we go. Okay, now it's working. Again, we have moved this to one other file but this is still a little bit bespoke and a little bit more complicated.
So one of the things that we can do is we can actually use a module called, we can, instead of putting a routes in our file, in our single file, we can actually do something a little bit better. So first of all, I'm going to comment this up because we're going to use it later and I'm going to register one module which is actually very handy. Which is called Fastify auto-load. And I need to tell it what file, what we want to load, in fact. So I'm going to get an utility that I have prepared which is called dsm and it will actually give me a join method which I can just pass in the URL of this current file which is data1 file:// whatever and then I can concatenate it to routes. Note that if I want to do something different, you know, it would be a long, long list so I don't want to really do that. So I'm going to create a routes folder and then in the routes folder, I'm going to create a hello.js file. In my hello.js file, I'm going to copy this block here. Again, I still need my plugin here. So here we go. And then we can do this. And then I can close it up. Well, here we go.
4. Registering FastifyAutoLoad
We register FastifyAutoLoad to load all routes from a directory. If it crashes, it must be a function or a promise. I made a common mistake with the export default and routes. After importing the file, it works fine now.
So essentially what we are doing here, we are registering FastifyAutoLoad, which is then pointed to a directory, our routes, and then all of those routes will be loaded. So let's see, if all this still all work, it will crash. Of course, it crashes, must be a function or a promise. So what did I did wrong? Because that's typically very common that I do something wrong in here. So I have my export default here and routes. Wait, it is. So this file is here, server, import app.js, my app. I am importing my file. Here we go. And it is. Again, oh. Let's try this. Yay, okay. You wanted a function name. Okay, so, here we go, we have started this, and now we still all working fine. Okay.
5. Creating Additional Files and Writing Unit Tests
We can create abc-d.js and use Fastify Autoload to load it from the abc folder. To write a unit test, we use the tape utility, Fastify, and our app. We test the hello world function using a nothing function and DEEP equal. We create a Fastify server, register the App plugin, and call the server using server.inject. We check the response JSON for the hello world message. Finally, we close the server and run the test.
So what we can do now is we can, you know, create a little bit more stuff. So for example, you can create abc-d.js, for example. So in this file here, you see we have created a little bit of a directory structure. And then hello from D. Now if we go here and restart, you can actually see abc-d, oh abc, and then that's d.js. So as you can see, with using Fastify Autoload, we can actually, oh, just, Yay. By using Fastify Autoload, we can open up this file and down to, and load it up from the abc-d direct, from the abc folder.
Okay, so let's move one step forward. Now, what if I want to write a unit test, for example? Let's create a new test.js file. Now, I'm going to use a very simple, a very simple utility that, here we go. A very simple utility that it's actually very, very handy, which is called tape. I am a fan of very easy test tools. So I don't know, I am hopefully you are like that too but if you don't, you can use whatever you want. So I need tape, I need Fastify, and then I will need my app. So note that I'm actually not creating the server but I'm actually loading my apps in a separate way. So what I can do is for example, load the hello world. Well, I can test hello world. So I want to test my hello world function, so I'm using a nothing function here and then I'm using DEEP equal. Here we go. And then we can do create a server, which is my Fastify server and then we can do register. Guess what we are going to do. I'm going to pass App in here, which is our Fastify plugin. So I'm going to put that plugin in then what I need, what we can do now is we can await, we can call our server using our internal testing utility. So we can do await server.inject and slash, which is our route. And then we can do deep equal, res json and then specify the fact that we want hello world. Here we go. So, and then what we need to do, we need to remember to close our server. So we are doing this. Now we can run no test and, oh, where did I put this? Test. Oh, yeah.
6. Creating Protected Routes and Authentication
If you're using ESM, remember to pass an extension. Our test is passing and working fine. We added ABCD and tested ABC. Now we create a protected folder and an index.js file. We configure the authentication system by importing JWT and registering the plugin. We add a Decorator to authenticate our system using a try-catch block to verify the JWT token.
So if you're using ESM, we need to pass an extension, right? Remember that. Okay. So you see our test is passing. That should be deeply equivalent. So it's actually working fine. Now we can actually also add one more thing here and about ABCD as we wanted, test ABC. So what we can do, ABC, and then hello from D. And this should work the same. Okay.
So we have added a little bit of things. So now we want to create some block of frauds that are protected. So what I'm doing, I'm going to create a folder called protected and an index.js in here. And in this index.js, what we are doing to do is export default async function, admin, maybe whatever and then app, which is our Fastify app. What we are going to do now is in here, we want to add some folders, some endpoints. But before that, we need to configure our authentication system. In here, what we want, we want to add another import called JWT, for example, from Fastify.jwt. So now, what we're going to do, we are going to register this plugin and pass in secret. And I'm calling it change me. Hey, this needs to be changed. Now we are adding this bit. We're going to need to add a couple of other things, which are pretty, pretty, pretty handy. The first one is Decorator, because we want to add an Authenticator helper. So we call decorate and we call this authenticate, because this is how we're going to authenticate our system. So this is going to be another async function, which is rec and reply. These are Fastify objects. And then, what we're going to do, we're going to have a nice try catch block and do await rec dot JWT verify, which is going to verify our JWT token. And in case of an error, I just want to reply dot send that specific error. Okay, so that's actually very simple. Now we can change that if you want to in here, it's fine. So we have added this.
7. Implementing User Login and Authentication
To log in, create a user called login.js. Use 'app.post' to handle the login request. Authenticate the app and validate the username and password. Throw an error if the credentials are incorrect. Use JWT to generate a token. Implement data validation using Fluent schema. In the protected route, add a hook to automatically authenticate all routes.
Now, how are we going to log in? Well, in order to log in, I'm going to create a user called login.js here. Again, export default async function, login app, Hey, then app dot post because this is a post, and then I'm going to say, call login, and we're going to need a little bit of stuff in here. So I am leaving this placeholder. So we're going to direct reply, then we need to authenticate our app. So, ooh, sorry. Yay. So we get to authenticate our app. So what we're going to do in here is I'm going to create, to get a username and password from our body, and then I am going to do, here we go. If the username is Matteo and the password is not Paulina, we are going, poor man, authentication system, never do this in real life. So we need to throw new error, we need to throw an error. So I'm going to do an Authorized Error. Now we need this errors module. This is Import Errors from HTTP Errors. So pretty handy. And then in case we just need to get our token. So with JWT, you get a JWT token and you do app.jwt.sign and we put the username in and then return the token. Okay, so this is our system. Now we need one little bit more because we need to validate a little bit more our inputs. So Input S from Fluent schema, here we go. So what we're going to do in here now is we're going to open up the schema and do body s.object and then .prop and you'll pass in the username, then this is a string and this is required and then the same goes to password. Okay, so we do a little bit, a tad bit of data validation beforehand. So I de-mull this also, I also de-mull this too.
Now, what we need to do now is we need to have in our protected route, what I want, I want to have in our index here, I want to make sure that all the routes defined in this file and the file that this one imports and loads are automatically authenticated. So what I can do, I can do add hook and I'll call onRequest. So I'm adding it to the onRequest lifecycle hook. This is called every single time a request comes in independently on the function. And we are going to pass in app.authenticate, which is the method that we have just added. Now I can do, for example, app.get something as something and app.slash and just say, async rec reply. And just say, return is authenticated. And then do Here we go, okay? So that's it.
8. Testing and Adding Authentication
To test if everything is working, we need to send a POST request with a JSON body containing the username and password. The response will be a long token. We can then use this token as an authentication header for the protected routes. Additionally, we can add a test for the protected route by calling it after logging in with a POST request.
Now, we need to test, to test it's all this is working, which is, you know, demo-gots. Hey, demo-gots are not with me, as usual. Add is not, oh, where did I put that? Add. Nice. Here we go. So demo-gots are not with me. So if I do protected now, it says unauthorized error. Okay. So in order to log in, here we go. Hey, hey, I'm cheating. So I am sending in a POS request with a JSON as a body and my username and password. Now the answer to this is a bleep, long, long bit of a token. Okay, so what we are going to do is, take this token, which is actually pretty handy, and then pass it in as an authentication, to the authentication. So what we're going to do, we're going to say h-header, which is, authorization, it's authorization for, hey, okay, authorization. So it's, we are going to just change these up. So, I don't mess it up. I messed up enough during this talk, essentially. Here we go. And then protected. Hopefully, all of these would work. These are authenticated. Okay.
So now, this is actually pretty interesting, because what we can do is, we can also add a test for this code. So, in order to add a test for this route, what we can do is protected. So, here we go. So, what we can do, we can actually do something very similar to what we were doing before. And I'll wait. And call protected. Now, we need to call it as a login first. So, first we call login, but we need to call it as a POST.
9. Calling the Protected Route
We have a URL and the method needs to be POST. Specify the body with the username and password. Call the token and close it. Call JSON to get the token. Call the protected URL with the token. Check if it works. Authenticate and authorize.
So, we have this URL. And then the method needs to be POST. Here we go. That's it. And we need to specify a body. And we need to say that username, username, it's Matteo, and password is Alena. Here we go, which is pretty handy.
And then what I want is I want to do this. I want to call this token because that's our JWT token. Then I close this, call JSON. So I got my token. Now I can actually call, here we go. Yep. And I am going to go in here. And so URL. Here we go. Protected. And then I need to specify another. Note that it's actually pretty important to... Yep. And then we specify our token. Here we go. And then it's... Choo-choo.
Now let's see if all this work. Oh, this is authenticate. Just a second. Oh, authorization.
10. Finishing the Demo and Contact Information
Authorization bearer token. This is authenticated. Fastify can be used to build applications quickly using Fastify JWT, decorators, and life cycle methods. Fastify 3 releases, NodeV14, and native ESM support. Check out the application at the provided URL. Contact me for any questions.
Sorry. Authorization. Here we go. So this is actually working. Format is authorization bearer token. Bearer token. Interesting.
Okay. So just, just a second folks. And this is not working as it should be. Bearer token. So here we go. Sorry, I need to understand why this is not working. And this is the problem, you know, here we go.
Okay, so now this is, here we go, RESTBODY. Here we are. Yes, this is authenticated. So what we're going to do is call deep equal. This is authenticated. Here we go. Okay, so I just wanted to finish this demo, of this long demo saying that our Fastify server is, Fastify can be used to build application really quickly using a combination of several utilities, such as for example, Fastify JWT, the decorators and the life cycle methods of Fastify. Note that I'm currently using a few, all of this is using bleeding edge stuff. So the new Fastify 3 releases, NodeV14 and the new native ESM support. So this is not on Spyle, it's just running native ESM and it's actually looked pretty fresh to be seen. So I just wanted to point out that this is the URL where this system, this application is going to, this code is going to live. So if you can check it out and play with it if you want to. The website for Fastify is www.fastify.io. So you can look it up on NPM and also on Google. If you have any questions about Node.js, please reach out to me at Matteo Colina on Twitter or matteo.colina at nearfun.com and thank you all. Everyone.
11. Inspiration and Community Ownership
Fastify was inspired by the need for a new web framework for Node.js that combines good performance characteristics in production and a good developer experience. It aims to solve a certain class of problems and is built with community ownership and open contribution in mind. Fastify's tagline is 'when somebody reports a bug, would you like to send a PR to fix it?'
Hey, Matteo, how's it going? Really good, really good. It's been a blast. That was an amazing demonstration on the speed of Fastify. You know? Well, you know. Our attendees seem to agree because we have a number of questions flooding in. But I, obviously being a demonstration, I wanted you to ask to kind of fall back and focus on what inspired you at the very beginning, you and Thomas DeLiverdove back in 2016 to say, you know what, let's build this thing called Fastify. How did that come about? That's actually one of the great starting points. So at the beginning, I thought, well, I think there is space for a new web framework for Node.js because I was having some problems with the client, with both Express, Appie, Restify. They all had certain things that were not working well in production for some of the company I was working with. So I thought, well, maybe there is a space in the industry for something that is, combines having good performance characteristics in production and a good developer experience at the same time. And it needed to solve a certain class of problems that Fastify ended up solving. However, at the beginning, I thought, well, this writing and maintaining a new web framework is a massive endeavor, okay? It's really, really a lot of work. And I'm not going to do it unless I can find another human being to start doing this in the first, to start doing this with. And if I can convince somebody else that this is a good idea then we probably have a chance. If I cannot, because there's no way I can do, I could have done all of that thing alone. So essentially it was starting from the point of, this is something that is going to be owned by the community or the community will have a say on how all these things is built and how this thing is maintained. And so that's why it has very open contribution policy for example, from the very beginning and so on. And it's fully on open governance and a lot of those things. So, essentially it's really focused on getting a very good experience for the contributors as well as the users because the users are the contributors essentially. The typical tagline of Fastify is, well, when somebody reports a bug is would you like to send a PR to fix it? Because it's everybody should be maintaining it. The maintenance is private to through all users essentially.
12. Fastify's Unique Features
Fastify differs from other frameworks by fully supporting Async Await and the latest JavaScript features. It also provides excellent support for native node ESM in Fastify v3. Unlike other frameworks, Fastify follows a lifecycle-based pattern instead of a strict middleware pattern. This allows for more flexibility in handling routes and reduces the overhead by triggering only the necessary hooks.
Nice, nice. And then with there being a large number of frameworks within the JavaScript ecosystem. I was just curious to find out a little bit about what makes Fastify kind of standard its own and its own light as compared to the rest of them. Sorry, can you repeat? How does Fastify differ from the other... Okay, there are a few things, okay. So the first of all, it takes the several parts from most of the frameworks, okay. So it first of all, it fully supports Async Await compared to for example, Express 4. I know Express 5 is going to support Async Await but it's still alpha or something. And so first of all, it supports Async Await and all the latest things. We are also adding as what I've demoed, the new Fastify v3 add some very good support for ESM, for native node ESM that you can use with node 14 and 12.18, which is great. So we are really keen on adopting the latest and the greatest of the javascript spec. However, we do not follow a strict middleware pattern. We follow a lifecycle based pattern. Which means that there are hooks that are triggered at any point in the stages where the request comes in and at various part which you can inject code, but if you're not injecting code, these things are not triggered, which is really, really powerful because we can, one of the key things, one of the key problems for example when writing large express app is that you have a lot of middlewares where you do if this route do this, and then if not, call next, and then you pile them up one after the other. With fastify you can avoid all of that by having this kind of lifecycle and you can set those lifecycle methods only for a class of routes or only for some specific routes, which is one of the best way to lay down an app, an application, and that cause also the minimal overhead because those things are only triggered for the routes that require them essentially.
Mateo's IDE Preference
I am a huge fan of Vim and T-Max. Recently switched to the space Vim distribution. Slightly different from the Vim config I was using before.
Nice, and we do have a question from Michael Zielenski in the audience. He wanted to find out what IDE does Mateo use? So I am a huge fan of Vim and T-Max, I've been using Vim and T-Max for the last maybe 10 years, maybe 11, 12, something like that. On Vim, I recently switched to the space Vim distribution. I was trying it out and I've been trying it out for a few weeks now, and which is kind of interesting, to be honest. I like it. Slightly different from the Vim config that I was coming before. I wanted to try a little bit something a little bit more modern.
Matteo's Comfort Food and Closing Remarks
Matteo will be available in a Zoom room to answer all the questions. His comfort food is pizza, specifically Italian pizza. He emphasizes the difference between Italian pizza and other variations, especially those with pineapple. Matteo expresses gratitude for the opportunity to share his knowledge and looks forward to answering more technical questions. The discussion covered server-side JavaScript development, the JavaScript ecosystem, and pizza.
And just because we don't have that much time, which is very, very unfortunate, I wanted to let everybody who's tuning in know that Matteo is not going anywhere. He is going to be in a Zoom room, so all the questions that everybody is asking will be answered in the Zoom room as well. I wanted to kind of wind up before that by being, this is a pseudo-chef related discussion. I wanted to find out what your comfort food is.
Okay, my comfort food is pizza. And by the way, I am Italian. Okay, so I'm talking of Italian pizza. Pizza is kind of a religion here. So let's not confuse whatever you can eat outside of Italy to what you eat in Italy. And it's very important that I'm talking about Italian pizza. Now you can get really good Italian pizza in a lot of other places in the world. Most of the time though, you're just getting something that's, you know, just another type of dish that's called pizza. No, I'm not referring to that, okay. And also if it has pineapple on it, it is definitely not an Italian pizza. So, but if you get a really good Italian pizza, that's what I would call it. That's like my comfort food. It is also a carb bomb that is going to put, get straight into my belly. So whatever, so that's kind of, that's kind of it.
Definitely. Well, I'd like to at this point, obviously thank Matteo for his time this afternoon for sharing his knowledge in Fastify. Like, as I did mention, peeps, he is not going anywhere. It's just more, he will be in his Zoom room to answer all the questions that have been asked. So, and they are quite a number as you're talking about pizza, they kept, the list just kept on growing in terms of more technical stuff. So you will be around to answer those as well. And please do keep those questions coming. Matteo, it's been a pleasure speaking to you. I feel I have learned so much more about, you know, server-side JavaScript development, JavaScript ecosystem, and pizza. And I'm sure we will be speaking again. Sure. Bye-bye.
Farewell
Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye.
Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye.
Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye.
Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye. Bye-bye.
Comments