Fastify is an HTTP framework for Node.js that focuses on providing a good developer experience without compromising on performance metrics. What makes Fastify special are not its technical details, but its community which is wide open for contributions of any kind. Part of the secret sauce is Fastify plugin architecture that enabled developers to write more than a hundred plugins. This hands-on workshop is structured around a series of exercises that covers from basics "hello world", to how to structure a project, perform database access and authentication.
Fastify Workshop
Transcription
So today we're going to talk about the fastify, this is the fastify workshop. So we are going to learn the basics of this framework and maybe go a little bit further along on more advanced topics. Have you used this framework before, folks? If you do, you can write in the chat, you can do, you can respond, you can interrupt, plus one. I don't know how to pronounce your name. So anyway, thank you. Yeah, a few people have used the framework before. So, yeah, no. OK, somebody has not. Nice. Cool. OK, the people that have used the framework before, you're probably familiar with the concept. So if you've used the framework before, please, this is more or less the first few exercises are more basic. So help your fellow learners. So why fastify? So a few bits and bobs. So I created this framework long time ago. By the way, hi, I'm Matteo Collina. I created fastify down in 2016. So this is a workshop with the creator of the thing. If you want to take some time to open Twitter, go Twitter slash Matteo Collina, hit the go here, look Matteo up. And then it follow. It's a nice button here. Please do. Thank you very much. You can also follow fastify itself. It's actually a nice framework to follow. Anyway, I work for a company called Nierfirm. We are a professional services company based in Ireland. By the way, we are hiring. So in case you're looking for a job, that's where we can look us up. This is the company Nierfirm. Again, you're probably familiar with it. If you follow me, if not, it's loading. Here we go. This is Nierfirm. So if you want, we are we are over here. And check us out. Anyway, let's keep going. Well, somebody has arrived. So why fastify? fastify is a web framework to build APIs and really nice servers on. It's fast. It says in the name, it's fast. How fast? Well, we'll see. But the other bits is that it's very secure and also it provides some, it has a very good developer experience. One of the nicest parts about fastify is that it is a very nice community. fastify was actually born before the community, fastify community was actually born before fastify actually even existed. I started fastify when I convinced Thomas de la Veda, the other creator of this library, to join me in this journey. So. Happy days. And while we recently gained a lot of adoption, how much adoption? Well, you can actually look it up by yourself, but in the in the last years, the number of downloads have been slowly growing. So I suspect there is some Sunday ban being filled up and and it's going it has steadily, but surely grown. Nice usage in January, beginning of January, end of January, December. It is always the case. So every day. So core features, first of all, is highly performant. fastify adds almost no overhead compared to no core. It's very extensible. fastify, it has plugins, hooks, decorators and other things. And it has a lot of it's it's naturally support JSON schema. So. It's not mandatory, but you should be using it. It also provides logging by default. And we were recently checking another. It uses Pino under the cover. So I wrote that same 2016, early 2016, and it's a great logger. So check it out. It's developer friendly and it has a good support for Typekit, even though it's actually improving. Who is using it? A lot of companies, so including some big names or small names, whatever. Enough people are using this. This is probably increased from the last time we did the numbers. So there are not much. So we have 46 core plugins and 162 community plugins. You can see the list. There is a lot of things happening here. Nice. One of the things is the fastify community, as I said, is very welcoming. In fact, we have a Contribute flag, a Contribute tab on our website. And you can see those are all issues that are free for people to do. Very interesting enough, we have even some in Chinese. So I don't know what even this is written. Hopefully, this makes sense to somebody that speaks Chinese. I don't know if any of you does, but if you do, please help on the Chinese document. OK, so there's a lot of things that are possible. Benchmarks wise, fastify has been built to be as fast as possible. So it's you can check the benchmarks, but the result is that fastify is, for all intents and purposes, as fast as Node Core would be for a certain task. Good, bad, I don't know. That's what it is. So you can check it out. Let's start with the workshop. OK, you can execute these commands. I'm going to pass this command down here. Know that you need to use, I recommend to use Node 8. And sorry, not Node 16 and npm 8. So please make sure that you have those two things. How do you do? Node-v will tell you which version of Node you have. And npm-v will tell you what version of npm you have. You want to have Node 16 and it should come by default with npm 8. We, at the end of the workshop, we might use Docker, but if you don't have Docker installed, don't worry. And the repository is public, so you can just go around and check it out. OK, you can file as fast as the instruction here. I'm going to pass it, oh, to pass the file. To pass the link also in the Discord group. Here it is. OK, oh, the Blender Bot alerts. Who the hell does not have the Blender Bot alerts? Workshop structure, the workshop, it has multiple modules. So, you know, you can build, like if you start building this application, we build a small app together. If you start building this application, you will build on top of the previous one. And we will, at each step, you will add more features to this and you will have the solution in the next folder. OK? And, yeah, there are bonus features and hints. So, first of all, how do we start? Well, there is a step 01 hello world, and you can check, you should check out the readme and run npm start. OK? So what's written in there? Just to give you a hint, near form, the fastify workshop. fastify workshop and you can go SSC and hello world and server. Well, and sorry, and readme. And just run npm start. OK? That's the comment. So if everything works, this comment should run and not error anybody. Let me know, I'm giving you, I don't know, three minutes. Actually, yeah, three minutes to do it. So let's see, I'm going to take the time here on my clock, on my watch. Feel free to interrupt me anytime, by the way. Hello, hey, folks, how is the workshop going? Were you able to run the command? Hello, any answer? Due to streaming, I believe my computer is really slow, so the packages are still getting installed. OK, let's wait for that. Let's try to save some bandwidth. Work for me. Hey, OK. So how are everybody? So Petr Diksten is asking what is the, what is the Starland command for fastify? So what you need to do, let's go back to here. It's this. What you need to do is these two lines. OK, OK, so let's go and let me walk you through your first fastify program. OK, you have already built it. We've wrote it for you, essentially. So the program is actually very simple, which is create fastify. OK, and add a route and then listen. OK, so let me show you something that might be interesting. So you go into server. You're doing things this way. What you could also do is this. So can you increase the font size? There is a way to just show the code speed, not the presentation. Yeah, OK. OK, so what you can do is you could also write things in this way. So basically relying on top level of weight and not having a function. However, I would recommend to do the function because we'll keep it working on it later on. So you might just want to do, you know, I'm fond of top level of weight. So just in case you have any doubts. OK, let me go back to the slides. OK, so next step. fastify allows the user to extend its functionality with plugins. So plugins are a key fundamental construct of fastify. You can actually read up into this link with the document. I'm passing it in the chat, in the chat and the Discord channel. In fastify, everything is a plugin. So you can do fastify.register and your plugin name. And you are basically creating a new context, which is private. So what I'm asking you to do is to split server.js into two files. One, it's a server.js file that contains only the server startup logic. And one index.js file that contains the code to instantiate fastify and register plugins. Then you need to create a new file inside routes, routes slash users, and export it as a fastify plugin. I don't want to jump too quickly. So keep working on your folder and let's, I leave this up. Let me know if you have any questions. OK, you know, this is more like baptism of fire type of situation. OK, so let me start doing these exercises a little bit myself. So, um, where is it? OK, so we left you when we were at this step here with this kind of exercise, with this thing. This is step one. OK, so what you can do, uh, is you can do, uh, you can do, uh, uh, yeah, what you can do. Let's repeat it loud, Raphael. In case you have any questions, please share in the chat or open your mic. OK, make sure. OK, so we, the first thing is to split this into two files. So how do we do that? Well, we open index.js file. And in the index.js file, we can copy this partially. OK, and we can just adjust to function build. Oh, OK, and then export default build in this, in this one, I would do, it build from index.js, then I will just do. OK, does it make sense? Hopefully so. You guys are very silent. Definitely, definitely making much sense. OK, so please interact a little bit, otherwise I'm talking to the wall. OK, so now you can do node server. Oh, did wrong. Can read properties of undefined. What did? Oh, yeah, of course, because this is an async function. So I need to await it. Amazing. OK, so now this is starting. And it's printing a lower. OK, so now we have separated this. So how do we create a plugin? So in order to create a plugin, what you can do is we have work here. What we can do is create a folder routes and then users. And here we have this file and then export default app users and we can just do return users. It's nice. GitHub copilot is nice to create fixture data. OK, so we have created two users and this is async. Now, how do you register this? Well, we go back into we go into our index file and then we you can actually do. Well, I think I'll call this app. And then I would do app dot register and you can even use dynamic import if you want to. Routes users.js and node server. And we do curl. Oh, it did not start. It seems about OK, though. OK, let's try again. Hmm, where did I did something wrong? Yeah, it's not loading something. Hmm. As you can see, my facts. Ah, yeah, this is a sink. Yes, thank you. Thank you. Now, it's still it's a word is working and it's users is working too. Cool. OK, so this is an example of how you do this. It's let me share my screen. How are you doing? Have you been following along? Are you stuck? Are you able to nice? OK, are you able to work on this? OK, so. Yeah, so plug is essentially any in any module, right? It is not opinionated. It is just an regular function that needs to be exported and we can register it. Yeah, yes, it is just regular function. Yes, it's not. There's nothing. There is something special about it in the sense that the way it's loaded. So something that is useful and I'm going to show you this is. OK, you see this line. Long line. OK, so what you can do again, let me share again my code. It's. If you like to, if you like code completion and you probably do. OK, what you want to do is you can actually. What you can do, this is not needed. Actually, this can be just an empty object. What you can do, you can define its type. At the top, even if it's javascript, because then you could do, you see that it has all the methods already filled up. So you have auto complete on the thing. Not that I'm using VI with typescript and auto complete, right? Anyway, so this is the this is a trick that you can use to get the auto complete done and. Already in in fastify. OK, so if when using plugins. Now, something for the future, like these is buried down at the end. If you want to open an issue in the meanwhile, this is buried down at the end of in the middle of the game typescript reference. OK, so maybe we might want to move it to the end. Maybe we might want to move it to the getting started. Yeah, actually, there's a question about it because. Some some ports works, but when you encapsulate with declare more like here, like essentially, I would just put it here for some. OK, yeah, OK, so. It might be useful just to add it so that anyway. Cool, OK, so. Sorry, here it was. Let me show you like it's let me. And I forget that I don't have both screens showed. So there is if you look at the docs file, you see that it is we have is your first plugin. And we can actually add it here. Sure, sure thing. Anyway, cool, so this is the first the second exercise, OK? How many of you were able to do it? Hopefully, all of you, I don't know, a few of them, a few of you are not telling me how you're progressing, so hopefully you will be doing this very well. Logging so next step that we're going to cover in this in today's workshop is logging fastify shifts by default with a logger called Pino. What is Pino? If you haven't heard about Pino, check it out immediately. You know, it's a really fast logger, so it has a nice logo. There's a pine tree. Happy days. And you can just use it this way, but it's naturally embedded in fastify. And fastify is a logger option that you can use to enable logging and configure it. So you can open up your logging documents, logging docs, and you can just turn on logger. OK, you can also configure pretty print to log stuff. What is pretty print? Pretty print is, you know, for something nice for humans, not just for people. Pino by default logs in JSON so that you can easily process the things. OK, give you three minutes like folks turn on the logger to turn on the logs. OK, so that's pretty much it for today's workshop. If you have any questions, please feel free to ask them in the comments below. And if you have any questions, please feel free to ask them in the comments below. And if you have any questions, please feel free to ask them in the comments below. Thank you for watching. Working. OK, great. Oh, God. OK. Have you turned on pretty print? How does it change with pretty print? Yes. OK. So you can turn on pretty print with the logger. You can log from the fastify instance. You can also log from the route itself. And you will get something like that. But with colors, I hope you like colors. Do you? With pretty prints, you will get a lot of chatty values. So you will see multiple lines. You will see that you are incoming requests with this payload, which has a request ID. Then the same request will say all the logs for that request. And then when it's completed, it will tell you how much time it took to respond to that request and the request ID for it. OK, so pretty good. Yes. Let's move to the step four, serialization. That is one of the most important parts in the fastify. It will really enable you to increase your performance, your servers. Also, because fastify uses a schema-based approach under the hood that is AJV. It's a library that compiles your request and your response to be able to answer fast and serialize it pretty fast as well. And also, it validates your input by just passing just a couple of lines of code. So I will pass here in the chat here and also in the discord, a reference for the validation and serialization that is pretty important. It will enable you to validate your code and validate your response. And it will enable you to reach the 100% of performance using fastify. So my code will please go to the next one. So let's do a quick exercise. Let's validate the response of the users. The users wrote using a schema created with the fluent JSON schema. You can use other schemas, for instance, how many folks have used Joy for validation. I don't know if you heard about it, but it's also a pretty cool library. So that's it. I think that I will share my screen at this time. So you need to stop, Matthew? Yeah. Okay. Great. One second. So let's move to the serialization. Okay. TypeBlocks is a good one as well. I mean, I have used TypeBlocks for almost my project, so it's good to know as well. So let's go to our source code. We have added the pretty print here, and it's important to wrote. But right now we should go to the root and declare a schema for that. What is the schema? We need to understand what the answer we should provide to the users, and it will enable to answer fast and also compile it. And the first thing that you do is likely the installing of fluent JSON schema, but with the npm CI command, it will be installed by the pool. So go to your work here file and to your users folder, and then let's declare the schema. It's already declared, but I will just explain it a bit. fastify uses some receives as a second parameter of each wrote a couple of options, and one of them is the schema. Through the schema, you can combine some responses and some requests that you want to receive. For instance, in this route, we are returning the username, and the type of the username is a string and also is an array of objects, right? No questions so far, I assume. And going further, we shall define that this is our response. So we create a response object, and inside of this response object, we define that for this route, when everything works fine, we will return an HTTP 200. 200 is the default response of fastify when you don't specify anyone, okay? So if you return, for instance, just an empty array, it will be an empty array with the 200 of response code. You can also test it using CUR, okay? So for instance, if you go to the step four, and do a CUR with the variables to the localhost 300 users, it will return you an HTTP status code that is 200, is the full of a good response, okay? So yes, when we answered 200 status code, we want to define how the response is formed, how the response is, I don't know the exact word, but how is the response schema, okay? So right now, we are assuming that the response will contain an array, and its items will be an object with a property called username, and its type will be a string, and also it will be required. So it was defined. In case if you change the username, for instance, to one that is not a string anymore, and you try to run your code again, those server, and then you do a CUR, it is working, okay? Okay, not as expected, let me see. For instance, if you, okay, yes, it's this one. If you change the return, for instance, here we are returning an array, but you want to return just rello word, but your schema was defined as an array of objects. Okay, it is not what is supposed to do, I guess. One second here. The schema was defined, it was asynchronous. Okay, I think that it will be an idea, Matteo? So you are? I'm just trying to answer a different answer on the schema. It's a, you're not schema. I think it's not, let me just check the example. It's 200. Okay, I think that is this one. You're missing the required, you need to specify required in the items. No, I have to read. Let me check. So node CD, the step 04 serialization. Okay. Okay, this works. Then let me try duplicating this. Okay, yeah, that's it. I have found that the schema is defined as the property. No, the difference is that if you pass in a string, it will bypass the schema. If you are returning a string, okay, you are, if you look at the core dash V, you will see the content type says text, and therefore the validation will not kick in. Yes, yes, I forgot this, we have discussed it. But just for example, here we have the name, we have specified that the username, the username is required, is a property required for a handser. So for instance, if I change the property to test, it will return me a non-200 code, internal server error. So it also specify to, it also prevents you to answer bad things, you know, to expose much more than expected. So the question for Jacob is why not use typescript for type definitions? You can, but there are a lot of folks which doesn't like the typescript approach, because it bundles, it do a lot of things. That's why it's fully supported by typescript, by the way. Okay, but also it's important to mention that this is completely different than a typescript type definition. Okay, here we are defining thing in runtime. For instance, if you are using typescript and define a type here, my amazing response in typescript, it will not work. Okay, because it's type. I would do it differently. As a result of the function, I would there define a typescript appropriate types of definition, and I would get at edit time or compile time or edit error instead of getting them at runtime. They differ. There is a fundamental difference between those two things. Okay, so the first of all, if you specify it in this way, yeah, the rendering of the JSON is faster. So we can use instead of just simply editing it, you will get it immediately. Okay, so then the other problem is the other advantage. One advantage is speed. This is actually significantly faster than just returning the JSON. The second one, which is to some extent even more important, is that you probably don't know what you're returning, really. typescript is not getting it. So typescript is all removed at compile time, right? At compile time, yeah. So essentially, you just don't know, okay? Because something else might be, in this case, it's simple, but the data might come from another library, okay? For instance, if you have a response like this and you return and you have a property that is any and you define anything here and you return a, it will work in typescript, you know, and it's not expected to work. Yeah, but you should not use any. Yeah, you should not use any, but sometimes you cannot trust the source of your data. For instance, it comes from the api, okay? The api can answer anything, okay? Okay, but then you step to the problem, it comes from api, but then from the schema, you also don't know it. You also don't know, but you compile it and you, instead of returning 200 stats code, you return a 400 stats code. Because it's validated during the runtime. In typescript, you can only have the guarantee when you are writing the code during the compile time, but not in runtime. But as far as I can see it, if I would write it in typescript, the development is a lot easier for me because I don't have to play around with some kind of other program to generate things where points, function calls might be missing or whatever, and I'm directly getting the error inside. Yeah, but they are doing two different things. Yes, I understand there are two different things. This one is at runtime, and the other one is at compile time helping me writing the correct code. There's nothing that bars you to do both. Yeah, except for a bit more work, but... Well, we will fix that in the next release of fastify. It will enable you to do both. So that will simplify a lot of things. So anyway, there's a question of, is there a difference between using Fluent Json Schema versus just a regular Json Schema object? No. Okay, so Fluent Json Schema is just us not wanting to do... The point is with Fluent Json Schema, you get auto-completion. It's very simple to write Json Schema with it. If you use something else, if you use Json, normal Json Schema, I typically forget some stuff and get it wrong all the time. Okay. Yes, and this is very good information. The type box can provide you everything that you want if you want to work with schemas and typescript. It works very good. So, well, I think that the serialization was explained. If you have any questions, please share. Let's move forward. Yeah, I have one. Yeah, sorry, the workplace at the moment. So that's why I have my camera turned off. But anyway, so I have a question about what is the recommended, like, fastify-ish way of handling validation errors, right? So as far as I remember, Matteo is not a big fan of using instance off to check something, right? But if you need to check that specific type of error is exactly like validation one, right? So as far as I remember again, in fastify docs, it says that you should check that validation field is like present. Well, this is with less cover validation during validation. So we have a validation example out. Yes, here. Okay, so just two steps down the line. Okay, okay, right. Okay, so that's it. The solution, pretty simple, as we have seen. So we have tried also to make the response wrongly. It will return 500. That's called internal server error, pretty good. And the step five is let's go to the testing. testing is pretty important. And then fastify make it very flexible through the dot inject function that is, thanks to like my request. So let's make a test for your index.js module. Try to use node tab and use fastify inject for that. Okay, so let's move forward. Let's write a unit test for the index.js module or index.js is modularized. So you can, we are returning the fastify with the road. So let's create the index.test.js. But firstly, you should make sure that you have installed a node tab. Okay, so you install it, create a folder. You can also, after installing tab, you create a new script that test your code. Okay, so going to the test file, we need to import tab. We need also to import our beauty server. Okay, it is in the index.js, great. And also tab provide this utility that you create suite of tests. So let's test the get users. And we can do it asynchronous or not, but asynchronous will be more easy. So let's test that we should return users correctly. Correctly, okay. In this function, in this callback, we will assert it. Okay, so let's create the fastify instance, calling our build server. And then also our server is created. We just call the fastify inject that will make the request to users just simpler, you know? You don't need to do a fastify listen or fastify ready. Doing the fastify inject, it will automatically request the fastify route. Okay, so pretty good. And then we should make sure that the answer, the stats code of the answer in the exercise says that we should check if the answer is 200. So the answer should be 200, good. Let's test this one, npm test. Okay, we have a facet. But also we should test that we expect, we return the expect array of users, okay? So let's do the same. Await, we can do it to a JSON response is equal await arrest on JSON that will bring you the body of the request, of the response, actually. And then you don't need it. You just check if the JSON response is the same as username equal. Let me check what is our answer is Alice and Bob, right? So Alice and Bob. If we run the test again. Okay, we have our route tested, okay? Pretty simple, no? Now, you might wonder why the code coverage is all reported to zero. If you look at the code coverage report is all 0%, okay? Yes. It's because we are using ESM. ESM and code coverage do not play well together these days. So that's life right now. If you want a solution to that, okay? One solution is to disable top internal code coverage and instead use something called C8. I'm going to share my screen. So what I've done is you're in step two testing. So in step five, test, whatever. What I've done get diff. What I've done here, I've just added this thing, dependencies C8, and you can run it with C8 up. And when you run it, it will automatically, so the npm test will not, but if you do npm, run half will give you the right results. Well, it's not. The first one is the one of tap, and the second one is the one of C8, so then you do tap or C, and you can just do no coverage. Just rely on C8 to do your thing. And it's actually working fine, okay? What is the difference between the C8 implementation versus the tap native one? Tap uses an old library called Istanbul, and while C8 uses, it's a new code coverage tool provided by V8 itself. Two different options, and one is the old school one, Istanbul, and Istanbul does not play well with ESM, unfortunately. That's life. Note that I think you can, now, it has improved the situation, so I think you can do this now. Yeah, it's working, okay? So you can actually just do the one-liner import if you want to. There is a very good question. Why not tap instead of something like Jest? Okay, now you have asked the right question. So this is one of the things that you should not be using tests to test your node systems. That's a TLDR. Why? There are a few long bugs about it, okay? A few long discussions about it. It's a lot of conversations, but the end result is that with Jest, Jest overwrites all the node globals, so you instant soft checks would not work. That's the first one. And then it also tweaks stuff on the handles that are created by the system, so perfectly valid code will start to error in Jest. Perfectly valid code for node will just error in Jest. And we need to do, as maintainers, we need to do certain shenanigans to make sure that Jest still works, okay? While it doesn't in some cases, which is very weird, okay? Or very, very weird, unfortunately, okay? I will pass you one of the major links to Jest. It's a node problem of the library, okay? I am just always finding time to find the right links, so. Here we go. And Facebook Jest. I think this is the issue. Yay, 2549. If you want to know, this is partially the reason. This is going to hunt you in any possible turn whenever you don't expect it. So here we go. I'm passing it here. Okay, so this is essentially, there are a few workarounds to that problem, but to be honest, it's not worth it. There are other problems about it, and you see this still is a bug. It's considered a bug, okay? And it has a few hundred comments and about it from all over the place, okay? And you see, look at this. Timers, it's just, you know. Anyway, just from my point of view, if you're using OJS, you're actually looking for problems if you're using testing Jest. Jest works greatly for working on the front end, by the way. I'm just, I am pretty happy about it on the front end side of things, okay? Oh, yes, so somebody is saying, I miss what you do to get your test to do the stuff. So you did C8 tap. So instead of tap, you just do C8 tap. And then, however, then you need to, you can do this, but then you also need to add in your tappers C file. Oh, yeah, you need to have a tappers C file. And in this tappers C file, you need to specify the no coverage true. Or alternatively, in here, you need to put no coverage. So tell tap not to use its own coverage stuff and just use C8 for coverage. That's it. So this is nice, okay? I'm going to cover the next step, which is validation. So we are down to validation now. So let me open up the next screen share, okay? Here we go. Share, share, okay. validation, tap, sorry, AJV. So what we use, we use, in fastify, we use AJV. There's a long documentation about validation in our doc. It's a long reference list. It explains a lot of things. AJV is one of the best validators for JSON schema. So it's what I would recommend people to use for validation. You want to ask why JSON schema? Well, it's a standard, okay? That's it. Other alternatives might be good enough, but it's way better to have a standard and to be compatible, for example, with Swagger and make sure things work automatically. So the exercise is to create, this is a document. You can check out the documentation to solve the exercise. I would recommend you to create, I will ask you to create a new file, a new plugin in the route slash login.js in which you create a route, which is a post. And in that post, you can specify a schema for the body of that post, that is a JSON object containing two fields. One is username and the other one is password. Both add strings. Cool. Give you five minutes for this. We'll see where we are at in five. Okay, let's walk you a little bit through the solution and the exercise, okay? Or does anybody needs more time? Okay, so let me share my screen. I need to change my share here. Okay, so I'm still in the previous folder, so you should be able to follow along. So the question is to create a new file called login.js. So I'm opening it up, my editor doing login.js and then I am here and I need my previous step. Why it's not moving forward? Okay, so I need actually this from my previous one that I added another plugin. Okay, nope. Where did I put it? Work here. Okay, so I'm copying in my nice sentence. Raffaele, if you have some moments, can you maybe open an issue on the Repopo, on the workshop to add the types everywhere? Yeah, I have mentioned that you in your past issue, take a look at that later. Yeah, okay, perfect. So we are here, I'm logging. So I'm passing this here so I can export default. Okay, I tend to prefer saying this app. So we want to create a post, so we do app.post. Well, it's not working. Yeah, it did work. Okay, now this goes to Mongo. We don't really want to go to Mongo, okay? Okay, but what we want is we want to accept a schema. So let's say return something. Now, what we want to create, we want to import S from Blended Schema. And then we can create our schema here. And for the schema, we need to specify our body. And it has a username and password. Now, it's really handy, I don't know, like using copilot for doing live coding seems like magic most of the time, okay? So if you see lots of smarts, autocomplete is copilot doing this thing, okay? So now, this requires a username and a password. And then we want to validate it. Now, I'm going to cheat a little bit and then going to copy some of the code. So we have our response. Oh, well, it's just the username and password. Copilot is a game changer. It is. So we are not actually validating anything here. We're just returning the username. And the password. Now, we can also say the response. And we want to say it's the username and the password. So cool. Let's see if I can run this. No server. It's starting, okay? So I can do curl x-post dash h. We need to specify the content type. Application JSON, that's what we are sending. And the body, which is dash d. And we are saying like username. Oh, I need to use double quotes. Username. And it's full. And password is bar. Very strong username and password combo. Local host. Oh, bad JSON input. Where did I put my JSON input from? Oh, yeah, I did not put the last quote. Cool. Okay, and the slash is not found. True. So we want the login. And it's not finding the login. Why? Oh, yeah, because I have not added it here. So what I need to do is add login here. So node server. And now it's working to some extent. It's already picking it up. Nice. So instead, but the returns are empty. Why the return are empty? We'll see that in a moment. So and let's go to three. Let's close this up. It's too many stuff, too many things. So browse, login. So it's an object. Let's see. Well, returning. Let me let me cheat for a second. Ah, yeah, true. That's why I did it wrong. You see it from time to time. The autocompletion is too smart. By the way, that syntax is actually pretty good. But the actual syntax is this one. That's why. And here we go. Okay. Now it's working. Okay, great. Perfect. Okay. Now what we can try also if we can try to validate if our stuff is correct. So I can curl and let's try to specify a different. Let's call it pass. You'll see that we get an error. And the answer says, well, body should have required property password. You will get a much more detailed error in there in your output. Okay. Okay. Um, let me start this year and let me start sharing again the slides. So here we go. It is slides. So this was the exercise. This is the solution. As you can see, we have implemented our schema. Okay. Right credential, wrong credentials. So let's move to one important part of every api. I would say that every api will need to have an authenticator if it exposes publicly. So let's move to the fast five JWT. That is a, JWT is a method of authentication widely used across the globe. So fast five provides a plugin called fast five JWT. Uh, that uses internally JSON web token. And in the next, uh, in the next exercise, we will, um, change the index.js so that it registered the fast five JWT plugin using a hard coded string as a secret. Um, and, and you can create, uh, return a code for that. Return a JSON web token for that. Um, I will present to you my, the solution and then we can write the task together. Okay. So let me just share my entire desktop. So right here we have our, our last example. And then we have the, the logging that we just returning the username and password. Okay. But now we should check that for instance, um, if the username is totally different from the password, you know, uh, so we, we should throw an error. Uh, we should tell, tell to the, to the requester that it is not allowed. Okay. So a horse, uh, will now try that. But firstly, firstly, we should import the error. Okay. So in part a horse from HTTP errors, that is, uh, that is a nice library. Okay. It is provide, it provides the, the response schema to you pretty good. Okay. Just it. So let's, let's try. So if we go to the node index, not server actually, and then we try to do, uh, cool, um, the favorite member correctly, uh, passing the best, uh, username. Let me open better here is their name as half L and my password is half file as well to local host 3,000 looking. Okay. We should also specify the heater, um, show them type. If I remember just to specify that it is a Jason. Okay. Okay. Let me see if that works. Um, am I missing something? Should work. Great. Um, but here we are just returning the username and password when a success happens. Okay. But when it, when I perform a login, I should return my token. Okay. I token of the authentication. So let's use the first by JWT for that beside JWT singing. And then you can specify any object that will be decoded to the, uh, encoded to the, to the token. So let's pass the username for instance. Okay. So if you run it again, uh, I think that they should import the yes. Is this, I should register firstly, my, my app. Okay. So import, um, fast five, JWT and to register this, this, this plugin, you should provide a secret. Uh, my secret will be this, okay. I can, I can put anything here. Okay. So now we are getting that the username is required mostly because I might send something wrongly. Let me see here. Um, one second. It should work. Okay. Yeah, yeah, yeah. It is, it is not working because our last, latest, uh, response body is that the username and password. Now we should change it to, to receive, to accept the token as a required this thing. Okay. So I hope that it works great. It's, it is working fine. So now when we do a request, let me clear for you guys. And then I have a JWT token as a head, as an answer. So for instance, if you go to the dwt.io and paste this code, it will, it will bring you the, the, the, the coded data that is the username. If you, if you want to, to add other property here, you can, okay. For instance, if I add hello, it will bring me hello word here. And then I perform a new login. I will get a new token. I've got the new token. And if I decode this token, I will get the hello word. Okay. How good so far? Any question? Okay. Everything clear. So let's, let's add a test now for, for this route. Okay. So let's, or latest code was trying, was testing when, when a valid post is tested. And also we showed, also we showed now test when we send credentials, good credentials. What means good credentials is when a password is the same as, as the username. Okay. So let's remove everything here. Let's rename it to test token with the correctly credentials. Okay. So let's create our server. Build server. Okay. And let's do a request. Qonst res equals await festify inject. And we showed a performer request. We will, we will do the request to the login route. Using the post method and your, and our buddy will be the username as half L and the password, password as half L as well. It means that it is a good, good request. It should work. Right. So we showed check if the responses that's code is 200. And also we showed, make sure that the JSON the response of their server. Json response token, right. Is the same as, well, here we have a problem. How we can fake the answer, the response from the token. So the festify JWT provide a mock method that you, you can return. I stub for instance. When you, when you are creating a, when you are creating a server, when you are creating a test for your server, you show you, you are registering the routes that you need to test in this file. We are testing the login route. Okay. And here we are importing the login route that basically create the post route. But also we are making use inside of our login route. We are making use of JWT plugin. So here we show, register the JWT token, but we still have the same problem that the JWT provides a dynamic token. How we can assert that this token, the token is correctly. We can use the sign on stub. Sign on is a test helper. It will help you to create mocks for your request. Okay. So you have the sign on from import sign on. And then here you can decorate the JWT by yourself. Okay. The JWT method, because in the login route, you are using the Festify JWT sign in. So here we show the mock it. We create the sign in method and it will be a stub from sign on. Okay. And here, the only thing that we know that we show do is Festify JWT sign in returns. Let me see if I remember it correctly. Return, yes, returns the token that they want. Okay. It is the kind of standard for plugins in Festify system to mix property and methods to request object. There is a lot of plugins in the Festify system. There is no standard plugin. I mean, you can for JWT request, we have the Festify JWT that is officially maintained by the Festify team. Most of the plugins are maintained by the Festify community. But the core ones like the JWT, the MySQL, the PostgreSQL is maintained by the Festify team, core team. Okay. So here let's return the example token. And then we can just check that example token will work. Okay. So it should work, I guess. Let me see. Let me run the test. So npm run test. It was failed. Let me see why it should be equal. Okay. It is not before the route that we have created. Okay. TAP also provide a good way to test a single route that you can just specify TAP, test, logging test, JS. Post logging with an invalid post payload. Okay. Let me shit a bit. Removing the user. That's it. Yes, it's the other one. So it's working fine. Okay. So we have created our test. We have mocked the answer. And then you can keep going. By the way, the test, all the tests is available in the step seven, but don't shit. Okay. You should just look at it when the step is done. Otherwise, we will not get any insights from it. Okay. Let's keep going. Any questions so far? The solution, pretty clear. Okay. So let's do the second exercise of the step seven. That is change the routes login to the out check. And when the check fails, we show the return up for 100. One authorizes it. Okay. The first example here we did together. Okay. The second one is up to you. We just shared the solution for the test. It's pretty simple. We will just need to pass a wrong password and it will basically enter inside the zip and it will throw an error. And then you can just make sure that the status code is 401. Okay. Um, this is just it's pretty simple. We have seen the most complex stuff in the when you are using sign on to mock stuffs and so on. It is pretty useful. And I think that we can keep going. Otherwise, if you have any questions, share, please share. We will move to the to the next talk about config. I think that there is no questions, right? Okay. Let's move then. Config. So this is one of my favorite topics. It's config. And one of the things that most people can get wrong in how they structure their code and applications using fastify, but not just fastify, kind of almost everything. So one of the big one of the recommendation can be to use environment variables to configure your app. What you don't want really is to have your JWT secrets encoded in the source code of your application. Very recently, I was I found it plenty of time. This type of secrets embedded in the code. Also, you don't want your aws keys pasted in your code base. Okay. There's a lot of things where you don't want to put those stuff. So usually you don't want to genetically you don't want to commit config config values straight into a repo. And you might want to manage them using environment variables and injecting them into the system, into your app, into your process at at runtime. Right. When you deploy it, you could potentially also fetch them, for example, from some sort of secret storage, for example, vault or aws key storage, I think, or aws secrets. Anyway, we have a few module in the fastify community for that to check out. So but today we're going to talk about storing your configuration in environment variables. So what I the modules that we're going to use, there's always a module, right? You have learned this in this workshop. Every single at every single turn, there's a new module that you can use. Okay. Every single step of this workshop, there's a new module that's getting introduced. There's a module for that. It's called M schema. I really like the M schema module because you can M schema. And it's actually pretty nice. What you do in a schema, you specify a JSON schema for your environment variables. You are saying, for example, that you want a port and stuff. Okay. And then you actually create your M schema. Okay. And you have your conflict. Note that it also automatically supports .env by default. And .env is actually awesome because you can just put your in locally when you are developing, just create a .env file and it will automatically pick up your environment variables from there. It's pretty handy. I really like this. Note that you can also use, like with AJV, you can actually automatically cast things automatically. So it's pretty handy. Also, fluent schema is supported and all those things that you might want to use. Also, typescript, like a lot of stuff. What I'm asking you is to create a new config.js file that use EnSkiva to load a JWT underscore secret environment variable using the .env, like looking at the .env for development, essentially development purposes. And it's very useful. It's very useful for you to use it. It's very useful for you to use it. Like looking at the .env for development, essentially development purposes. And it validates its value. And then you want to, in your server.js, you want to import your config.js file and provide the output to the parsed environment stuff, and sorry, the parser config to the build server function inside. In the .js, then use that configuration provider to actually currently instantiate the JWT package. Okay. Is it clear? Yeah, okay. Yeah, and variable is always a headache. Yeah, I know it's always a headache first, folks. I know. So that's why we are covering this here. And also the important part of the important part, the important here, is that we are separating the starting of your application. So and passing off the configuration from the actual build server implementation. Okay. So we are done. A mistake that a lot of teams do is to have a config file. And from every place on your code base, you load up that config file. And you just take stuff from there. Or randomly in the middle of a request, of a request or processing a request, you are accessing the process.m to check an environment variable configuration. Okay. That's not cool. So instead, try using this pattern where you're passing, you're actually having your config flowing down from the top to the value step. I know it's a little bit more verbose, but it actually helps in compartmentalize and encapsulate and scale your code. Yes. So the question is, to use it in other files, is it better to pass it via property? Yeah, my main recommendation is to always do something like that. Okay. So from the top file, you import your config. And then you pass it to your fastify instance to boot it up. Why is this better? Because when you're testing your application, you can actually test it with multiple versions, with multiple setup and multiple configuration values without having to rely on mocking to set up your configuration. Which is way better overall. So you can just avoid the mock and just pass it down. It's also more clear because it's clear where things come from. It's always responsible for a value. So yeah, that's the way I would implement this. And here you just do your configs and your stuff. Okay. Does it make sense, folks? Great. Do you want to do this? I'll do this. And then you do the next one. I can do nine and 10, Rafael. And then what do you want to do? Nine and 10. I can do the 11 and 12. You can do 11 and 12. Okay, perfect. Yeah. Okay. Amazing. Okay. Let me start with nine. Okay. So let's start with talking a little bit about decorators. Okay. What are decorators? So in the previous tab, you use a JWT token. And with this JWT token, you can use to access protected routes. In this tab, what you're doing is to protect a route that can only be accessed by an authenticated user. Okay. How are we doing that? Well, first of all, we need to create a decorator. Okay. fastify extensibility model is providing it. It is provided by plugins. Everything is a plugin, fastify. And the decorators are essentially functions or objects that are functional properties in general that are added to your request, response, or your main server. Those are typically populated inside hooks. What are hooks? Well, hooks are... We'll talk about hooks in the step 10. So for now, we focus on the decorator. Okay. So what you're going to create is create a new plugin slash authentication. Wait a second. Is a new plugin slash authentication JS plugin that essentially it's the one that includes the fastify JWT module. Okay. It's not you move the register of the JWT module inside this new plugin. It also creates a new authenticated decorator to the Fastified instance, which essentially validates the token and respond with an error if it is invalid. Actually, let me just show you. It's probably become more clear when we are going to do the next step. Okay. So this is the example of what you need to do. Okay. So basically create a plugins authenticate file and you just move the fastify register on inside using the option. Okay. And using creating a decorate function here. Are you... Have you ever encountered this? Are you familiar with this type of declaration? Okay. I don't know if the people that have used fastify or not. You might just want to copy that file to use the next to the next one. I don't know if you are... If you want to, you totally can. It's something that is worthwhile doing from my point of view. Okay. So if you want, totally go ahead. Okay. You can go ahead and copy it. Know that we need to use the skip override. Okay. Why? Because with skip override, otherwise you won't be able to expose the plugins. Okay. So you'd want to be able to expose the decorators. All the plugins are right now filtered. Sorry, are completely encapsulated. So when you are creating a plugin, you won't be able to use the decorator outside of the function. Okay. You still need to register it and import it. In the next step, folks, we are going to use the decorator that you just have created to create the protected route. Now, this image is probably not rendering great, Raphael. So you might want to change something here on our code. Okay. Anyway, what happens is that fastify is not based on a middleware path. You probably are familiar with the concept of middleware in Express, right? Middleware enables you to add a lot of functionality. fastify instead offers, basically you have your incoming request, then you do routing, then you do, we create a logger. Okay. Then it starts passing through a few hooks. So the first one is an onRequest hook. And onRequest is actually pretty, it's the first hook that you're going to encounter. Note that the routing happens at the very beginning. So in fastify, whenever you're, so there's no dynamic route. Whenever a route is decided, that's the route. Okay. No other route is going to be called. Then you do the instance logger. Okay. We get the logger. Then we create the hook, we show the onRequest hook. Then the pre-passing hook, pre-passing is different from onRequest because it can be used to modify the body if you want to. Then there is a parsing, so it's a content type parsing. So if there is a body, this is where the body is parsed. Then there is a pre-validation hook, which you should almost never use this because you have not validated your input yet. But it's useful in certain cases. Then there is a validation hook. Then there is where the validation happened, you know, the AJV. Then a pre-handler and then the handler. This is where you write and this pre-handler is used before. Then you do, you issue a reply. Okay. And before the reply, there is a pre-serialization hook. And then serialization happened. And then there is the onSend hook before sending. Then we have the response is sent and then we have a response, onResponse hook. And after the response is sent to the end user. This is different from Express where everything is just a mid-error and you just add mid-errors on top of mid-errors on top of mid-errors on top of mid-errors. Okay. Using this is what also gives you a lot more throughput than Express. So it's a fundamental part of fastify. So it is the exercise, okay? So you get your, you have your decorator from the previous, your previous function. Okay. And you want to require authentication using the onRequest fastify hook. Using the fastify.authenticate decorator. Now the authenticate decorator, it was defined like this. So it's an asynchronous function that take a request and a reply. And you just call request JWT verify on it. So in here, what you would do is you need to look at the onRequest hook and essentially require authentication for, for your, for your stuff. Okay. Note that you can pass the hooks. Can we pass globally with fastify.ado? But also you can, you can also specify it as options in, to your routes. So you can actually specify only one route. I want to execute our hook only for one specific route. This is very important for fastify, for how fastify works. So you don't need to execute this long chain of mid-errors all the time, but you only execute what you need at every step. Hopefully it's great. Can you clarify what's better to, why it's better to register off the decorator by using onRequest hook, not the pre-validation one? Just because we will be able to skip few unnecessary hooks until they are, until if Delph fails. Yes, for me it makes sense to, to register in the pre-validation. Yeah. Let me just check if the request buddy is already parsed in the, in the pre-validation. The request body is not, so I would, so the out is better to, on the onRequest, because onRequest happens immediately. So we are not waiting for the body. Okay. So they basically, you, instead of waiting for it's, let's imagine you're sending a five meg, a five megabyte file. If you're an authenticated user, you're sending, and you're sending it on a five megabyte file, you might be able to cause denial of service attack. If you are parsing, if you're parsing the file, if you're receiving the full file and then parsing it. If you move it on pre-validation or pre-handler, pre-handler, what you're doing is you're actually having the full file parsed before you actually do your thing. This is problematic because the moment you are doing that, you are causing all sorts of problems. You're actually exposing yourself to do unneeded work in case the workshop is, in case the, the file is, in case the payload is very big. So that's why I prefer to say it's better to put it on our request. However, you might want to receive the authentication tokens for whatever reason, because the JWT, you pass it as a, as a better token inside the others, the others. But let's say that you're passing your JWT or your, whatever means of authorization inside the body. Then of course you need to put, to do that work before parsing. Okay. Oh, sorry. Before, before, after you've done all the parsing and before the rounds. Does it make sense? Yeah. Okay. So let's go and talk a little bit about the implementation of this. Okay. The implementation, it's somewhat simple in the sense of that you just take your decorator that you had defined before, and you just pass it as a whole request together with your slash user. And then in your ender, you just return your user. Yes, the hook supports array. The question was that, yeah. So basically you can just, yeah, an array of function. Yes, you can specify it is an array of functions. So also one single function or an array of functions. So whatever you want, you tell you need. If you want to combine those kind of hooks in a, in an interesting way, like for example, say, oh, I want to support one strategy versus another strategy. Um, you can also look at this module, this fastify auth module. fastify auth enables you to say, uh, to specify multiple one to use in or as an or syntax. Okay. So that, you know, first validate if there is a GWT and then verify there is a username and password. And, uh, it, uh, it will do its job, essentially. So it essentially, it will try them all up until it find ones that actually, it's actually good. Uh, there are other authentication strategies. One is, uh, uh, uh, fastify passport. A lot of people like passport. So, um, here you go. Um, here you go. So there is another question about, uh, is it safe to use it? Prevalidation for case transformation. Oh, uh, so, uh, uh, okay. Is it safe to use prevalidation hook for something like case transformation? Like when we have schemas defined for fields in camel case, but input is underscore grand type versus grant underscore type versus grand type put as a camel case. I would not do that. Like I would not do any data manipulations before, uh, having validated what it's in there. There is one case where you can do that is for instance, when you, uh, I have used that the Google, uh, cloud Pub-Sub and Google cloud Pub-Sub send the data to you, uh, encoded and you show decoded, uh, before parsing. So in that situation, you can do it because, uh, in the prevalidation, because you have a check at the, if it is safe to the code and then you decode and then you validate after it, you know, but in case of, uh, just, just changing the, the, the fields for camel case, uh, you, I also would not do it just for, you know. Yeah, I would, you know, list all the things that I want to list in my additional schema and, uh, just support them. Okay. It's, uh, uh, part of the problem is, uh, there is actually one thing that we do when receiving adjacent that's actually very handy. It's the prototype poisoning protection. Okay. No, it's not indexing it. Happy days. Prototype poisoning. Okay. Okay. You can read it up. Okay. It explained it all. It's an old article, whatever. Very important. So let's, uh, let's go forward in, in, uh, uh, in step 10. Let's try step 10 and let's see how it works. Okay. So we are in, let's go and see how it's all of this work. So let me share my screen. And so we go into step 10, step 10 hooks. Okay. So first of all, we do run node server. Then what we need, we need to first of all, log in. You probably remember how you would log in. So it's the, uh, you need to, to send the curl syntax. So you have your girl and then you specify your body. And then you specify, you send it to login. Okay. And we also want dash feed to know the exact response. It is our JWT token. So this is the important one, the token. Okay. Then what you will do if in order to test this, you would need to, uh, curl. Uh, your HTTP slash slash local last 3000 user passing a better token. So authorization there, and then you take the value above. Okay. You passed it and you close. Okay. And then you see that it returns the token. Now, if I put a wrong token here, you see that I'm getting an unauthorized message. Works beautifully. Okay. It's, uh, very simple and it's a very effective way to add authorization to your app. Now, something that you can do is, for example, if you want to, let's say you want to protect the multiple routes. Okay. Like right now we have the, your user here. It's, uh, uh, it's one route. Okay. But you have the on request. What you can do is you can fastify ad hook, uh, on request. Okay. And then here, fastify, authenticate instead. Okay. And then let's say that you specify another route. You can say, put it here. Note that the hook will keep working for all, um, the hook will keep working for all routes defined in the same plugin. So it's actually pretty neat. So we can have like two routes. So let's run this code. And we can, the first one is still working. And then if we are moving to user two, which is our second round and also second route. So you can see that you can actually, uh, create a series of defines a series of route with a common authentication defined. And, uh, you know, if we can try, if we try another strategy, like another stuff, like the logging route, the logging routes still work as expected. So it's not protected by authentication. So the hard hook is encapsulated. We call it, we define it as encapsulated within the, the plugin then define. When is the stuff going to happen when they're not encapsulated? Well, in order to have something not encapsulated, we need to specify either using the skip override or using the fastified plugin utility to define them. In that way, the hooks will always be executed. So let's talk about fastify outload. fastify outload, uh, bootstrap, uh, entire folder. This is pretty cool. Actually, uh, it loads all the plugins found in a directory and automatically configures the route matching the folder structure, which means that if you auto load the route routes, it will automatically for every file that you add to this route, it will be automatically bootstrapped. It means that if you create the route users.js and you create the route orders.js, it will be automatically loaded into the fastified structure, even if you don't add anything in the index.js. Okay. It's important to mention that, uh, before any work, uh, once we have created tests for everything, we can do it. We can do this refactor easily. Okay. So don't worry about breaking our application because we are moving forward, but adding tests for everything. Okay. But so let's move to the fastifier to load. So for instance, if you register a folder users, okay, slash users, it will automatically add you, uh, edit your prefixed path. It means that let me try if I can draw here. Okay. You have the route users. Okay. I think that this is user. Okay. And then you add a new file to it. The file one dot. JS. When you load the application using fast file to load automatically. If you register a route here using fast by. Okay. I can't write, but if I get it, we'll add the one as prefixed route. Okay. So let's go to, to a better example. Um, here in your best example, we had the routes. Oh, let me increase the font size. We have the folder house. Okay. And inside the house, we have the login.js. We have the users.js. Inside the user folder, we have index.js that we registered the route is less user, but using fast file to load, we don't need the specified user. We can just remove it. We can just remove it because of the fast file to load. You understand that this file is inside the user hold the user folder. So it should be prefixed by user. It should be perfected by user. So if you, if you add the route one here, it will, when the fast file load, it will be in the end, but user one. So if you register the route two, it will be user two. Okay. You don't need to change anything, just adding a file. Okay. So this is pretty good, right? Um, this, uh, enable a lot of good stuff to do, to be honest. Let me go back. Uh, so also if you take a look in your, in your application, we are registering the routes here. Uh, a new route for plugins is, uh, actually a new plugin. We register here. A new route for users is here and looking at the users, uh, the users in general. If we need to register a new route, we should do it. Okay. Uh, for instance, uh, foo, foo.js, but once you have registered, fast file out to load, you don't need to, to, to register it, uh, manually. It will be generated automatically. Okay. So let's, let's go back to the step 11, uh, as an exercise. Okay. Um, let's do it together. Then we move forward. Okay. Let's remove all the, all the manual route registration, remove it. And also the plugin that instead of, instead of removing, let's comment it. Okay. Okay. You can specify the register, uh, and the, the, the festify out to load. Let's file to load is also, uh, a plugin officially supported by, by, by that's fine. Okay. So which parameters does it receive? Um, actually it is pretty simple. You register the out to load route and then you specify for which, which directory it showed loads automatically. The first, first one showed to be the plugins. So let's specify that. Oh, we are import meta URL because we are using ESM. Okay. And then we merge with plugins. Uh, basically these join just will return the full path to the, to the plugins folder. Okay. The full path, for instance, home, a file and so on. Okay. Um, the second one is we showed register automatically or routes. So let's just move plugins to routes. Just it, we don't need to do anything more. Just one thing, actually. Um, when you, when you start the festify server, for instance, in the server.js, you can also print the routes to register it. So if you do a console log, testify, print routes. And let's go to the step 10 hooks. Um, and do server. Let me see if it work. Okay. Not working. Let me see why, um, it's the build server. Yes. Oh, we showed the standard, the options, I guess. Let me see if it works. Okay. One second server.js. Let's see the server.js here is the same. And then we can test it using that index file. It should be the same as we have registered. No problem so far. Uh, okay. Let's, let's try to do it here. We have the route using user. Okay. Just to, to fix that. Step 11, server. Okay. It's working and let's register just, or let's just print the routes registered. Okay. Console.log, testify, print routes. Great. It is printing for hops. Okay. Let's, uh, and it is important to mention that here we are registering just two, two, two folders. And we are not registering manually any, any route. So for instance, if I create a new route, for instance, here can add a zoom. The zoom will return the same thing, but here will be hello, and here will be word. Zoom was called and zoom was called. Okay. Note that I haven't registered this file any, in any place. I just created the file. Okay. And then the zoom route is automatically registered. Pretty cool, no? So, uh, it will enable you to, to do a lot of fancy things, a lot of good stuff, you know, but there is an issue yet. What is the issue? If you check the, the, the structure, you'll see that we have a route call it, uh, user call it, uh, user slash user. But in fact, what we want is to have just user. But as I, as I mentioned it before, when you create a folder, it will add a prefix. So here you don't need to specify user. You just, you just, uh, need to have the slash. So when you move, when you change it, you have the correct routes. You have the users and you have the use user and the zoom. So it's working perfectly fine. And well, uh, I really enjoyed this, this, this tool, to be honest. So the only thing that you need is this couple of lines of code. Oh, actually this few lines of code. Okay. So, uh, here we did, and then let's go to the step 12. Okay. It's one step, uh, to, to, to be on, uh, but before you're going to do it, I would like to, to, to hear your thoughts about the last two and, um, and also what you think about this is what, what is your feedback about it? Uh, did you understand or you have any question? Everything is good so far. Good so far. Okay. Very clear. Thanks. That's one good. Yeah. Okay. Let's go to the step 12. Um, it's more, uh, it's more, it's one of the most difficult, I would say, because you need to deal with database, but it's more real. Okay. You probably will do it in your, your applications. Okay. So fast five post-processing is also official plugin for fast five, but before any work, you should make sure that any PM run db up and db migrate, uh, where is executed. So, uh, try it in our machine. If you are following the steps, it will, uh, uh, it will create a Docker container. If you don't have a Docker, I'm not sure if you'll be able to run it. Okay. Um, so in this step, we are going to use a database connection to validate our authentication. The first step, the first step we will do together, but the last one, I will let, I will give you, uh, some minutes to finish, um, hope to, to check it out. Okay. So have you run the db up and db migrate? It is working. Okay. Thanks, Jacob. Um, so let's do the exercise together. Let's change the config.js to support the PG connection string variable is that environment variable that is widely used, uh, to connect to your database. Okay. So this is the, the, the configuration I will send you right here. Okay. So let's change your config.js. We have our config.js here and we are expecting to, to have one more property. And this property will be the connection PG connection string that will be required as well. Okay. Just it is pretty simple. And we showed register or, uh, fast five push degrees to, to accept that, that connection. So, uh, but also we show define the PG connection string in your aim file. Um, let's paste the, let me see, okay, our connection is here and then we have the our connection is here. And then we showed make use of this, this environment variable. Let's go to our index file and then before registering the plugins, before registering the routes, uh, uh, you, you can register the, the fast five plugin. Okay. So let's import the five plugin, uh, fast five push degrees. Sorry. Let's five push degrees from best five push degrees. And then you have it and it, it requires, uh, option that is the connection string. So the connection string is basically what we have in the config file. Uh, but actually it is from the environment variables. So it will be PG connection string because the options here, let me see. Yes. Yes. Inside the config is the same. Great. Yeah, we are importing the configuration here and we are passing to the server. And then we are able to use ops, uh, options PG connection string. The first part pretty good. Our good is, um, very easy, but the next slide, well, also we have registered or that's five push degrees plugin. We are able to make requests using the near form SQL. So your objective is to verify is the, if the username providing the request, buddy exists in the database. If not, you show the return of 401 stats code. Okay. Uh, a tip here is use fast five dot PG dot carry to select the data from the user's database. Okay. The solution is pretty simple. Um, just import the near form SQL and perform a request. So here we have the check, the simple off check. Okay. But we showed check if it exists in the database. So we can use fast five PG carry, uh, using this SQL that it will prove, uh, the near form SQL will prevent you to, to, to, uh, SQL injection, you know, it is common. So let's select the ID username from users table from users table. Where the username is equal the username passive. It will be a promising and it will return, uh, rose. Okay. So, uh, it will return some object that contains gross. That is the response of the database. Okay. So inside the rose, we want to have to, to get the first client, the first user, actually, uh, and check if this user exists. Okay. If this user doesn't exist, you should throw the same error as an authorizer. And then we are good. This is the solution that we just factor a bit. Okay. This is, um, the enough thing. Let me test it with the step 12. No server. And then if I perform a login, but cure car with the password, okay. The username and password have, uh, password authentication to fail to the. Let me see here. Okay. I think that I have. Okay. Okay. Great. It is working. It is returning 401. Let me do the request again. There's a turning 401 because my user doesn't exist in the database. Let me get an user that exists. Let me see here, uh, in the test. I don't remember exactly the user that exists in the database is the Alice. Okay. So let's check, change the request to use Alice and the password is the same. Alice. And then you have the token. Okay. It is authenticated because you have checked in the database. So it's working. Okay. So the solution is pretty simple. And then let's move to them to more one, uh, exercising the step 12. That is, uh, move the existing routes users.js to routes users index.js to make use of the first five outlook. Second step. Change the response schema that so that it requires an array of objects with property username, uh, of type string and ID. Okay. Uh, right now we are just returning username and password. So now you should return username and ID. Okay. And the third part is, uh, modify the handler to, to load all the users from the database instead of, uh, instead of, uh, static users. Okay. Basically you showed, um, the same request that you did here. You showed do in the, in the users, but instead of do a wire, you should only remove it. It should give you the ID and the username properly. So the solution is pretty simple. Uh, you did basically you showed just, uh, yeah, we will, I think that we will provide the slides as well. Okay. Actually this repository is public. So you can run it locally without an issue. Um, the solution you showed change the response schema because in the, in the first version you are returning the password and now you showed return the ID and the type is integer. Okay. And the users, when you have moved to the route users index.js, uh, you showed instead of returning the static users, you can do the carry to the database just as I mentioned before, and then you return to the application. This is simple. Okay. Let's move to the step. The last step, the typescript version. Okay. Let's create an, uh, and specify application using typescript. Um, let's go to the step nine that in, that you did, okay, the step, the step nine, the repository and use the declaration measuring to writing a custom noted case show, uh, the, the created to the first five, uh, you can use type box as, as was mentioned before here. Okay. Let's do it together. So let me close this, the steps go to the step, uh, nine, actually I can go to the step, uh, uh, 30 because 30, because we, I shouldn't show to you that just the important part of the typescript. Okay. Firstly, you are creating, um, uh, the, the creation of the, the first five is the same as the, in the javascript. The difference that is that you can return the specified types that the specified instance, for instance, you have the server.js, uh, that is the same as the finite, you just have some, some types, types definition, and then you the same as the finite, you just have some, some types, types definition. Okay. And, uh, the most important part as was mentioned, as I guess, in the step five, I guess, we, we showed the fine, the route schema, uh, how we can do that with type box, uh, that type box provide a couple of, uh, uh, notes to you. Um, and couple of tools to, to, to identify, to generate your change on the schema. Okay. Uh, we were using the fluent JSON schema, but it doesn't provide those, uh, provide us, uh, the, the type, the type sheet, the typescript type. Okay. So for instance, we are receiving the username and password in the, in the looking route. Okay. So the type box provide, uh, uh, some types like the fluent schema to define your type and you can use it in the schema. But the most important part is that you can also define a type from your JSON schema. Okay. This is the, the syntax to, to generate the JSON schema, and then you can use the, these, this type inside the specified request. So it means that for instance, if I do, I have, I have, um, uh, I, I tell to the type box that I have username and password, right? And if I do here, uh, request dot buddy dot it, it complete automatically. I can use the username and password. It automatically completed. Okay. And, um, this is very good actually, because you can define the request. You can define the response schema here and it also validated in runtime is validated in compile time. And also it to enable, enable you to achieve the more performance in that's fine. If you don't provide a response schema, um, you basically you lose, uh, 20% of the, of the throughput in the best way. Uh, you can achieve much more with the response schema because also you have compiled a schema for the response. You are be able to answer way more fast. Okay. We had a lot of benchmarks in best five. You can check the GitHub best five benchmarks. Okay. You can check all the benchmarks with a lot of others, uh, other frameworks like express or happy or Koa JS. We still is that we are still there. The faith test. Yes. And well, this is the one part of the typescript, uh, approach. Okay. Any questions so far, uh, about type box or how, uh, or with the usage. Very clear. Okay. So there is one, one point here that, for instance, we have generated, uh, we are decorating our fast fi, uh, or fast fi instance with Delta and cage, right? So once we do it, we, we are able to do fast fi out and case, right? It is available here in this scope, but we are using the fast five plugin to enable it to run in every place, as Matthew said previously, but we can't do it. Uh, actually the fast fi you not, we will not understand that. Let me go here. Um, here, for instance, the first five, you will not understand, uh, the typescript, you will not understand that authenticate is part of the fast fi here. It's working because we have added the types, but if you don't have the types, it will not work. It will throw an error, throw an error because authenticate does not exist in the fast fi instance. Okay. How we, how we can solve it. We can make use of declaration, uh, declaration merging in typescript. How it, how it works. Basically you define a folder that contains a dot d dot t s. And then in fast fi, you declare a module of fast fi just to, to, to add some property to the fast fi instance. So here we have added the authenticate, uh, property in the fast fi. Okay. For instance, if we don't have it, it will not work. Property authenticate doesn't work, doesn't exist in the type fast fi instance. And if you run, if you try to compile it using a typescript, it will not work. It will throw us as well. The same error. Okay. It will only work if you, if you use, if you make use of the declarator declaration schema, uh, declaration merging. Actually you can check declaration merging typescript. Uh, this is the reference I will send also in the, uh, in the slack here. Okay. And in the fast fi, uh, typescript documentation, there is, uh, there's a couple of notes about how to, to, to create your plugin. You're making, uh, uh, using the declaration merging, uh, approach. You, you can also, for instance, fast fi provide some, uh, in the authenticate. Here we are decorating the fast fi instance, but you can also decorate the, the reply instance that is the fast fi, uh, request. Okay. Uh, and how we can, how we can add this property to the fast fi instance in the typescript, in the typescript land. The thing that you need to do is just export interface fast fi request here. And then you add my amazing property. That is a string. Okay. Um, I think that this is, uh, the most important thing when you are dealing with typescript, uh, and, and, and fast fi. Okay. Uh, one thing that will come in the fast fi or it will be released the next coming weeks, uh, is the, you don't need to specify the type right here. You just need to, to send the type in the schema. Okay. It is still a feature for the next major version. Uh, it will work. So it's, it's amazing to be honest. Uh, there is an issue in fast fi. I don't think that you remember. Let me see the pull request. I forgot the name. Yeah. Yeah. I won't be able to find it because it's too much PR, but it will work very good. Uh, it will very, it will be amazing. So this is what we, we have planned it for, for the typescript section. I know that the section of four hours of duration is tiring. It should be tired. And, um, do it as your lesson. Write fast for it. It's complete, uh, complete easy to write fast and doesn't mean it doesn't, doesn't, uh, doesn't matter if you are writing typescript code or javascript, it will be very easy to do. So that's it. I think that I, I hope to, I hope that you have to understand. Did you like it? What do you think about this workshop? I would like to hear, uh, follow me in the Twitter. If you have any question, yes, you can ask in the, in the discord, you can ask for in the, if you have, you have find some, some bug, open up, uh, issue and if you are able to solve, open up here. Okay. Um, thank you everybody. See you in some other workshop.