Build a Fullstack Music App with Next.js Serverless API Overview
A second version of this course released using Next 13+, but this course is great if you want to see another example fullstack project. We now recommend you take the Build a Fullstack App with Next.js, v2 course.
Transcript from the "Serverless API Overview" Lesson
>> We're gonna start the off process slash API process. So we're gonna be locking down our half UI half layout app. So I'm switching focus from UI to move more to database stuff because I'm getting ready to build out the pages, right? So if we go back to the design, we're getting ready to build out these pages.
[00:00:25] And I would prefer that we have access to the current signed in user, so we can build out this page. In order to do that, we need authentication, in order to have authentication we need a database setup. So that's why I did all that. That's why I started with the layouts, and then I was like, what's next?
[00:00:43] This homepage is next, we need a user, and we need a database, now we need the routes. So that's why we're doing this. So for me, I'm always driven by the feature and not like, let me do all frontend verses all back end or all backend, then all frontend, I'm like feature by feature, left to right, that's kind of how I think, it makes more sense.
[00:01:02] I've tried all the ways, and to me this just makes more sense about the feature by feature versus just doing one thing at a time completely. And then go on to the next thing, because I found doing multiple passes like that usually results in two things. One, you have to do multiple passes, you have to go back and sweep over your code over and over and over, replacing mock data with real data, fake servers with real servers, fake databases with real databases over and over and over.
[00:01:29] And then two, you start to get lazy because what happens is like, imagine if you wrote your front end first. And it was expecting the data to come back a certain way. And then you want to go write your backend. You might just make your backend bad because the front end is expecting a data a certain way, so you model your backend to match that frontend.
[00:01:52] But if you did it the other way around, your database probably would have been a lot more optimized, and we're gonna do things differently. But then your front end is gonna have to, but let's say you did do the database in the backend first, and then you want to go make the frontend.
[00:02:04] Now the front ends, like, I got to do whatever the database says, it has like these really bad routes, so now I got these really bad routes. And typically, a lot of people don't go back and just like, I'll just make these routes better cuz they don't want to do a second pass.
[00:02:14] Then even then, again, you're doing multiple passes, where if I just do feature by feature, I do them together at the same time, the frontend and the backend for a specific feature. I typically don't have to do those other passes. But I guess the downside of that is if you're doing feature by feature you're not really thinking about the whole architecture.
[00:02:32] And typically I see a lot of performance problems and things like that with feature by feature. But I guess I would rather go back and tweak performance and bigger architecture things than having to go back and rewrite a whole route because it's better that way. I don't know, there's always trade offs, there's no perfect way, this is works better for my brain, so figure out what works for you.
[00:02:53] Okay, so now that we got that done, we're seated, we got that going, we're going to create a signup route that allows us to sign up, and yeah, we'll go from there. So what we'll do is go to our code here. And if you join me inside of the pages API, you'll see a file here called hello.js.
[00:03:20] So any file that's inside a page/API folder is actually going to be a API route. So in this case, we have an API route to /API/hello, any verb. So post, put, get, delete, it's gonna go to here. So we can actually test this out. So what I'm gonna do is I'm gonna go to my terminal, I use this thing called httpi.
[00:03:47] And my terminal is basically like better curl. You can use curl if you want to. You can download some GUI like insomnia or postman if you'd like to, you could just do a get request in your browser if you want to. It localhost 3000/API/hello, and hit Enter, and you'll get back the same thing.
[00:04:07] I'm just gonna do an HTTP pi. If you wanna use HTTP pi in your Mac, you can just brew install httpi like that. If you're on Windows, you gotta go look it up on their instructions, but it does support windows I believe, but I'm just gonna say http.
[00:04:23] I can just do the port. It already knows I'm a local host if I don't type in a host /api/hello. There we go, and you can see I get back name, John Doe. And that's exactly what it responds back here in the code, name, John Doe. So again, you could do that in the browser.
[00:04:42] So people who don't have any API client installed, you can just type in localhost 3000/api/hello, and you should see name John Doe. If you've never created a serverless function before, you're about to create some. Serverless functions are awesome, there's literally exactly what they sound like. So instead of creating a server that's constantly running, and it's constantly on and you're maintaining all this stuff, you just create a function.
[00:05:05] You can think of it as like a callback in the cloud. That's the way I think about it. It's a function that gets executed off of some event. Usually that event is tied into a URL. So in this case, the URLs is whatever the folder is, so /api/hello, that is the URL.
[00:05:20] When that URL gets executed, this function runs, that's it. It starts up and then it shuts down and you get charged half of a half of a half of a half a penny to run that function, and then you can run as many as you want in parallel, so it scales to infinity, and it works.
[00:05:38] There are downsides obviously with like, yeah there are downsides. We can talk about that later, but so far that's what we're gonna be using. That's what next JS has built in support for on their platform, for so, so we don't have to worry about a server, we can just write some code here.
[00:05:54] So, we need to make a route to be able to sign up. We're gonna have a forum on the frontend that somebody can type an email and a password and sign up and create an account. Where is that gonna go to, or is that gonna post, so we want to be able to make a route that does that.
[00:06:07] So if you ever made a backend before, it's literally the same thing. This is all just gonna be in this function, that's it, that's all we're gonna do. So let's do that. We're gonna make a new file in the api folder. We're gonna call it signup.ts. And the reason we're gonna call it that is because we want the route to be /api/signup.
[00:06:26] That's why we're calling it signup. It's whatever the file name is, that's what the route is gonna be. So /api/signup, that's gonna be the route. And what we can do is we can just exports, default, this is gonna be an async function. We're gonna do some crazy stuff in here.
[00:06:42] And we're just going to do that, make an arrow function. A couple things we need to import here. I just need to import bcrypt because we're gonna be hashing some passwords in here. When someone signs up you gotta hash their password. We also need to import something called a JSON Web Token, or JWT from JSON Web Token, you should have that installed too.
[00:07:07] If you don't know what a JSON Web Token is, don't worry about it, we'll get there, but this is just how we're going to authenticate you. You need to also install something or import something called cookie from from cookie. If you don't know what a cookie is, it's a dessert that you can bake to taste.
[00:07:26] [LAUGH] A cookie is something in the browser that follows you everywhere and helps you see ads you don't want to click on. So we're gonna use that to help with the JWT and track you as far as authentication, and then we're going to import a Prisma Client. So we're gonna be using the Prisma Client in many different places.
[00:07:51] So far we've only used it in the seed file where we made it. But the seed file is not actually part of the app, like I said, it's a one-off script. So typically like one-off scripts, you want to avoid importing other files from your app because your scripts might have a different configuration and runtime that your apps might.
[00:08:24] And then it also has webpack that handles file imports differently. If in your script, you try to import one of the files from your app, it probably wouldn't work. Because if you're running your script just against node and not wet pack, it wouldn't know what to do with those image imports.
[00:08:37] It wouldn't know what to do with those TypeScript things. So typically in these one off scripts, you don't import things. So it's totally okay that we created a new Prisma Client here. But while in the app and this signup function and other pages that we're gonna do, I probably just wanna reuse the same Prisma Clients over and over and over again.
[00:08:55] So I'm not gonna make it here because I'm actually gonna use it somewhere else in our app later on. So what I'm going to do is I'm going to make a new folder on the route of our project, and I'm gonna call this lib. And inside of lib, I'm going to make a new file called prisma.ts.
[00:09:11] And really all it's going to do is, it's just going to make a Prisma Client, it's just going to do what the C thing is doing here. So I'm gonna copy that. And I'm gonna paste this in here and I'm just gonna say exports, default new Prisma Client, that's it.
[00:09:30] That way I just have one Prisma Clients in my app, so I don't have to import the @prisma/client every time I wanna use it. I can just import from this file and it always gives me the same one pretty much. So I'm just gonna do that. And then back into our sign up, I'm gonna import that Prisma instance.
[00:09:48] Next thing is every servierless function takes two arguments. It takes a request object and a response object. You can type check these, which is really helpful. The request is gonna be NextApiRequest and the response is gonna be NextApiResponse. It's very helpful to type check those in TypeScript. I know I said, if you don't need to know TypeScript to do this course, you don't have to type check these.
[00:10:12] These are TypeScript types if you've never seen this before. The reason I'm putting these here is because it's really nice to get some autocomplete on these things. Otherwise you probably would just come in here and console.logres to see what it is, or you got to go look at the documentation.
[00:10:26] It's really cool just to get some nice editor type ahead stuff here. So I'm just gonna put some types next to those, and then we should be good to go. So what's the strategy for signup? Well, just like any other app, you send us some credentials, in this case is gonna be an email and password.
[00:10:45] We're going to attempt to create a new user with that email and a hashed password. Because emails are unique it's either gonna create you because you don't exist or it's gonna say sorry this email already exists and it's gonna throw an error, that's it. That's all sign up is gonna do, and then if that is successful, we'll generate a JSON Web Token and we'll save it as a cookie, so it'll be set in your browser.
[00:11:10] And then that cookie will be sent on every other requests that we can use to verify that it's you. That's how we're gonna sign you up. And then as far as a JSON Web Token, a JSON Web Token is just a, the best way I can describe it is, imagine an object that gets turned into some generic string, but it's deterministic.
[00:11:29] We can undo that string and get back the same object, and typically, what we do is we put the ID of the user on that object. What roles they might have or access, when that object expires, different things like that. And we'll put that in a cookie so it can be saved in a browser, and then every request will have that cookie on it.
[00:11:47] And we can check to see one, is this server the issuer of this token because I'll know because we're using a different passphrase. Or two, even if this is a right token, is it expired. Or three, even if it's not expired, is this a valid user ID? So it's like three different ways we can check.