Build a REST API in TypeScipt - ExpressJS and Prisma

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] what is going on you guys and welcome back to the channel in this video we're going to be building a web api using typescript along with express.js which as you can see here on the web page is a fast and opinionated and minimalist web framework for node.js along with that we're going to use prisma which is a node.js and typescript orm and this is what we will use to communicate with our database now as far as databases are concerned you can use whatever you want you can see here the listed databases that i think prisma supports such as postgresql or mysql even mongodb however to kind of not go too deep into the realm of setting up databases i'm going to use sql lite as that is pretty easy to do however if you want to go ahead and use postgresql you can or whatever database you want to use and if you want to follow along with how to set that up it's super quick and easy you can see here on their docs page on how to do that the last thing i want to note before we jump into making our installations is that i'm going to be using this application called insomnia and what this allows us to do is just very easily communicate with any api or in our case the api that we're going to build now if you're using postman this is very similar as well and if you're comfortable using postman or curl feel free to do so however i definitely recommend this if anyone's looking for a nice interface for our apis okay so that about sums up the intro for this video let's go ahead now and make first of all set up our project and then make the necessary installations so the first thing is that i've created a directory called express typescript api this is also a github repo which you can find all the code in the link in the description below however let's go ahead now and run mpm init dash y now this will just say yes to everything inside our npm init clear all this so now if you list it you can see that we have our package.json the next thing is to make the first set of installations so first we'll install express dot env x uh cause express validator i'll explain all of this in a second and prisma forward slash client hit enter now express which is just the web framework um that's for this one dot env that just allows us to load environment variables from our emv file cores which is just middleware for our express application and or that enables cause sorry expressvalidator just validate our body or when we post something or put something this just adds an extra layer of validation and then prisma forward slash client which is our prismaclient okay let me just clear that the next set is our developer dependency so mpm install capital d type script and then at types forward slash node at types forward slash express at types forward slash dot env at types forward slash cause okay so that's for our types and typescript the next is again some developer dependencies but i just didn't want to overextend that line so the first one being prisma itself then es build dash register and nodemon so we need es build as we're going to be seeding our database with data uh before we jump into the api that way we don't have to worry so much about always adding data in every time we reset our database and nodemon just for live reload so enter on that and we're all good so now if i clear everything and list out our directory so we have now our node modules package log json and package.json all right so now that we have our installations all done let's go ahead and set up our database and because i'll be using sqlite i'll be running the following command mpx prisma init and then dash dash data source dash provider and then sqlite so if you're using postgresql um yeah before uh replacing this with postgresql definitely go ahead and check out the docs or any other database the setup is very simple so hit enter and you should see something like this which is um basically something that indicates a success message maybe if you're watching this in the future it looks different but hopefully you should see more green and no red all right so now that we have our database let's i'm just going to go ahead and open this up inside of typescript typescript um vs code all right whoops so if i just zoom in a little bit maybe that's too much but hopefully you guys get a clear idea of what the explorer looks like on mine and hopefully it should look similar in yours but first of all i have this prisma directory which holds this schema.prisma and this is where we'll define our models we have this dot emv file which has been generated for us right now by prisma and this holds the url for our database again if you're using postgresql this could be a a link and otherwise that's pretty much it so the first thing to do is inside our schema.prisma we have all this added for us beforehand but let's go ahead and actually before we go ahead and define any models let me just first give you an idea of what this um web api is going to do it's something fairly simple it's just going to represent books and authors so kind of like imagine a library api where we have and we have a set of authors and we have a set of books now to begin let's go ahead and first define what an author will look like so i'm going to go ahead and say model and then author so this is the name of our table first indicated with the keyword model actually before i continue there are some if you're using vs code there are some nice extensions that you can add for example prisma which helps with the schema.prisma that way you get some color coding as well as type hinting the other one is sqlite so if you're following this tutorial word for words for example with the same database you can download the sql lite extension which just adds like a nice interface for you to view your sqlite tables all right so hopefully if if you guys are following along please go ahead and install those on your on vs code as they help a lot but back inside our author model first we need to add the id which is going to be an integer say id at default and we'll say auto increment that way the id will always increment by one so first we will have an author with id1 then author by id2 and we don't have to worry about setting this next we'll have created at which is tends to be customary to add for our tables we have updated at which will be date time and just here i've created that we'll say default and now and for our created ad we'll just say updated at then an author will have a first name which is a string a last name which is a string and that's about it so that's our author the next thing is our book so we'll say model book and this again will have id created and updated that so i'm just going to go ahead and copy this add this here then a title string is fiction which is a boolean so true false will have a date published which is a date time and next a book will have a reference to an author so we're going to just assume that one book will have one author rather than having a set of authors so we'll say author and then author if i hit save and if you have that extension that prisma extension on your vs code if you hit save you should see all this autocomplete now first thing to note is this author is just for prisma's sake it's for our orm you will not see this as a column in our database but rather you will see the author id representing the link between book and author and i'll show you that in a second the next is that inside our author we set the relations so we'll say the relation between book and author can be found inside the book model via author id and the references here is referring to the id of author so this will just store the author id and one thing it didn't add which i would like to is this on delete and what this just means is that when we delete an author all of the books will delete with it that way we're not left with authorless books in our database but that pretty much sums up our schema file the next thing we want to do is inside our terminal let's go ahead and tell or first create our database and add these new models to it and to do that let me just zoom in a little bit so you can see what i write to do that enter mpx prisma db push and you should get the following output which is pretty much a success message saying that your database is now in sync with your schema zoom out and just shrink this but if i open up my explorer now you should see inside of your prisma directory a dev.db file that's only if you are using sqlite if you're using any other your changes should be reflecting your database and you'll be able to see them there all right so let's go ahead now and use this sql light extension that i installed hit open database and you can see down below here you can see sqlite explorer now i can open this up and you should see dev.db or the name of your database and you'll see the models that we defined so we have author and book if i open up book you'll see all the columns that have been that we defined such as id created etc along with their types and as i mentioned earlier the author itself as we defined in our model book is not written into the database but rather the author id so this is the reference point between book and author and you can also see an author or the other columns that we added now you can click this play button to see what the table looks like however as we have no data there's no point checking that out just yet all right so that's our schema all set up the next thing i want to do is first of all let's go into our package.json now the first thing we should set up is our script so for our api let's go ahead and add in our dev setup so we'll say nodemon and then src force index dot ts so this will when we run npm run dev this will run our index.ts of course this won't work right now as we have no such file or directory let's go ahead and define that so let's create a new folder we'll call this src and inside that let's just create an index.ts file which we won't add anything to just yet but let's just keep it there for safekeeping all right so inside our src or our source folder i want to go ahead and create a new folder called utils and inside that i want to create a new file called db dot server dot ts or forward slash ts just delete that move to trash new file db dot server dot ts all right so in this file we're going to basically define our prismaclient now our prismaclient is what we're going to use to interact with our database via prisma so the first thing to do is say import prisma client from prismaclient so something just like this as i wrote on line one next they'll say let db which is of type prismaclient we'll say declare global and then var underscore it's called db prismaclient undefined and i'll explain why we're doing all this in a second then we'll say if not global dot underscore db we'll say global dot underscoring db equals new prismaclient and then db equals global dot underscore db and we'll just export this database all right so why are we going to such lengths to create our prismaclient whereas we could just import it in any file where we need it so the first thing or mainly the only thing is that every time we use or every time we reload our application as we're using a um kind of hot reloader so we don't have to keep on restarting our server a new prisma client will be created and what we don't want is like 10 or more connections to our database we pretty much just want one and this this will just check to see if a prisma client already exists or a connection already exists and use that connect connection sorry losing my words otherwise it will create a new one that way we can use this database elsewhere inside our project so i'm just going to go ahead and close this and close our package.json now back inside our prisma directory let's go ahead and create a new file called seed.ts and this is where we're going to write the functionality to load default data into our database that way we don't have to keep on adding data into our database every time we reset it so first let's go ahead and import that fancy db that we defined earlier from dot dot source utils db server let's go ahead and create some types so the first one is going to be the type author and this will take a first name which is a string and last name string and we're missing an equals here but why am i just defining first name and last name whereas in our author model we have a bunch of other columns such as id creator updated and this book thing here first of all this book thing isn't actually a column so we can ignore that one but for the first three so id create an update to that these are uh um this is these are pieces of data that are added by um by the database itself so we don't have to worry about adding any of this in as the id is set by default and it's just auto increment increments the created and updated ad just takes the current time of um creation for that row and adds it in so all we have to worry about is first name and last name the next let's go ahead and define the type for our book so type book equals and then we have our title string in lowercase we have is fiction which is a boolean we have dates published which is just a date all right so the same thing which i said for author can also be applied to the book as we're only worried about title is fiction date published all the other things are added by the um database um by default sorry um the other thing is that we haven't added our um author id as this is something that we're gonna handle ourselves manually all right so let's go ahead and create our authors first let's create a function that deals with that so i'm going to go ahead and say function get authors this is going to return an array of author we'll say return and then inside each one let's go ahead and say first name we'll say john oops last name doe we have fast name which we'll say is william and then last name shakes pierre and then let's add one more let's add yuval noah and last name harari all right so this is our get authors let me just shrink this a bit so we can see so this just returns an array of authors now the next one is our book so we'll say the same thing here we'll say function [Music] get books which is an array of book and this will say title is sapien so we'll just add a bunch of books by um eval noah harrari we'll say is fiction false and date published say new date don't worry about adding that in specifically and then title we'll say homo deus is fiction we'll say false and date published can be new date and finally let's just make up some fictional book that he wrote say title and let's just say he wrote the ugly duckling and is fiction true and date published new date all right so this gets our books that we'll add to our database and we also have our get authors now that we have this let's go ahead now and create a new function we'll say this is an asynchronous function and we'll call this seed and what we'll do here is first let's create our authors so promise dot all say get authors oops and then map author and this will return and this is where we get our first taste of our prisma client so db which we already imported earlier author and then create inside that we say data and sorry about all this tool all these tool tips and then we'll say fast name is author dot first name last name is author dot last name okay so this creates all of our authors the next thing is we need to go ahead and let me just make sure all these brackets align why is this guy complaining um all right let's just go ahead and finish this function first all right so now that we have this let's go ahead now and get our author so const author equals await and then db dot author and we want you've all know harare because we want to add the books for him say find fast and we'll say where first name is uval because we can't guarantee the id beforehand actually why is this complaining let me just take this and all right so we have this map we have author we have this guy and then this i think what it's waiting for is that yeah it was just missing a bracket there okay let me just paste that all stuff back in so let's get the author where the first name is yuval no harari we can't always guarantee you've all know harare will be id3 but we can guarantee that the first name is yuval noah as we have specified that here okay now that we have the author we can go ahead now and create our books so we'll do something similar as well so we'll say await and then promise dot all inside this get books dot map and we'll say element book let's go ahead and extract the the date the property so title is fiction and date published from our book then we'll return db dot book dot create and then data and we can just add in title as so we don't have to make the keyword as it can be in fad based on the name of the variable is fiction date published and the author id which we need to specify is just author dot id and then finally let's just below this let's just call our seed function so make sure you add this otherwise none of this will run but that's about it this just adds like i said earlier adds the data to our database however we need to let package.json or prisma know that we have this seed function so inside package.json what we need to go ahead and specify is wherever i don't think we already have it but just here let's go ahead and create a key called pris ma inside that we'll say we need seed and it's going to run the following so node and then require yes build dash register and prisma so inside our prisma directory forward slash c.t.s and make sure we add our comment just below all right so we should now be able to run our seed and add some data into our database i'm going to clear this in the terminal and i'm going to run mpx prisma db and then seed give that a second and you should hopefully see this cute little leaf here along with the following statement that seed command has been executed now below like i showed earlier with our sequel light explorer we can go ahead and just quickly refresh this we can go ahead and check out the author table and you can see just over here on the side that we have our authors added so we have william shakespeare yuval no harari and john doe along with their dates and their ids we can also see our book so if i hit play here you can see that we have three books added with homidear sapiens and the ugly duckling with one being fiction and the id of the author so author id2 which is referencing the uh our yuval no harari author so back in here we can see that you've all know harari has an id of two cool so that pretty much sums up our database setup the next thing now is to go ahead and start building our api and get this up and running so that we can use it in a much more user-friendly way okay so to get started with our api the first thing i've done is jumped back into our index.ts file which we defined inside our source directory let's go ahead and make first make the necessary installation so i'm going to go ahead and import all as dot env from dot env and then import express from express import cause from cause and that's about it so first let's go ahead and get our envconfig so we'll say that the next thing i want to do is inside our dot emv file since we already have one it'd be nice to define our port there as well so let's go ahead and say port i mean we could just easily define that inside our index.ts file but it seems that we have this let's just define it here so i'm going to run it on port 8000. close this now okay so back inside index.ts index.ts let's go ahead and first say if not process dot env dot port then process dot exit one so if there's no port fine then just exit the application next let's get our port from the env file this is type number and pass int say process dot env dot port string and then 10 like that so base 10 so we get our 8 000 next let's go ahead and create our app so we'll say app equals express like so okay so first let's assign our cause middleware to express and it's very easy to do that we just say app.use and then cause and we want our express application to use json so we say app use and then express dot json all right and just below that let's go ahead and add our listen so app.listen and say on the port add an anonymous function and say console.log listening on port and then our port so we'll say port that these are backticks by the way by the way if you um can see them clearly and that's just so we can add our variable port there as well all right now we can actually go ahead and run this so inside our terminal run npm run dev and if you remember earlier we defined our dev script here so it just runs nodemon on it and there we go so we should you should see hopefully this listening on port 8000 now if i go to insomnia i'm going to go ahead and create a new collection i'm going to call this typescript library api all right let's go ahead and create a new request it's going to be on http local host and then port 8000 if i create that and i send we get oops that should be the name let me just add that here so in the get let me just zoom in as well so here where it says get we can add our url so localhost port 8000 send and we just get a not found so cannot get but our server is up and running all right so the first thing i want to highlight is the way we're going to structure this application let me just close that so we're going to have our apis so our routers and then we're also going to have a service and the service is just going to be our way of communicating with the database so what we'll do is inside source let's first create one for our authors so i'm going to say author and inside that i'm going to create a new file i'm going to call this author dot service dot ts so first let's go ahead and create our services zoom in again or maybe not hopefully this should be fine for you guys all right so inside that first thing we need to do is import db from our db.server file all right okay let's go ahead and create a function that just lists out the authors so we'll say const and then list authors this is async as we're communicating with our prisma client it's going to return a promise of an author and we'll define this type in a second and there we go all right so above this what we want to return is let's say we just want to return the the what is it the id first name and last name so we don't want to return any of the extra added information with each author so we don't want to return the creator that updated that first uh or updated out and created that just these two so to do that let's create our type so we'll say author and then we'll have our first name which is our first property which is id and then first name which is string i mean we could just emit this from our author that we define in the model but this just makes it a little bit more cleaner to read all right so inside this let's go ahead and return db dot author dot find many and here we'll just say select which will just select the properties that we want and inside that we'll say id true and fast name true and a last name true all right so we're getting this error because uh last name is missing the following properties from type author and it shouldn't really be complaining we have the type author which we defined just now ah so the mistake these should all be commas maybe not why is this not const we also should export this i think we have this was this async promise uh and this is returning a list of authors not a single author so we're promising an an array of authors sorry about that that was just a silly mistake from my end but this function now should now work so let's inside our author directory again create a new file we'll say author dot rooter.ts and inside that let's go ahead and build our author endpoints so first of all we need express from express let's import some types so we need import type which is a request and response from express we also need our validator so what we installed the beginning our express validator so validation results from express validator and then let's just import all as author service from author service and we also need to export our router so we'll say const and then author router equals express dot root up all right so the first one we will just get a list of authors or all authors we'll say author router dot get say forward slash and we'll define the urls in a second so async and then request request so type request and response type response here let's define the body of it so first we'll say try and we'll say const authors equals await author service list authors then we'll return response of status 200 and json authors and then finally we need to also add our catch and we'll say error and we'll say that let's type any just so typescript does not complain and then response dot status say 500 and we'll just return error dot message all right so we have our first endpoint which is our get endpoint and now we need our actual api to recognize that so inside index.tsx what we need to do is first import our author router so we'll say just below here import author rooter from author orthorooter and now down below we can add that by saying app dot use and here let's define our endpoints so our urls so api forward slash authors and then author rooter all right that should be our author router setup so what we can do now is go into our um api interface so i'm going to use insomnia i'm just going to go ahead and change the name of this and say get authors and then just clear that now here we can say forward slash api so in the url forward slash authors and if i hit send we now get back a list of authors with id first name and last name as what we told our service function to get our authors is that we just want those three if you want to specify date created and update you can of course add that so back inside let me just adjust these quickly this screen oops what am i doing move this over here but inside our author service we can of course specify something like date created which is a date and then here we can just say date create i think that's what we called it am i wrong where's our schema we call it created app so back inside there we can just say something like created at and then [Music] here we can say created at and then true now if i go back and i hit send again we get our created at as well but i'm going to exclude that as it just kind of clutters it and just remove that here as well all right so that's our list uh endpoint now let's go ahead and let's say we want an endpoint that retrieves only one author so and that will be based on the id so inside our author service let's go ahead and add a new function and this will just be get author so we'll say export const get author equals async and this will take in an id of type number promise and this will either return back an author or return back no and inside that we'll just say return db.author dot find unique and inside there put in curly brackets and say where the id matches with what we passed in and again this is just shorthand for saying id id as both have the same name so we can just shorten it to id all right so that was again very very simple so we just had to write a few lines and we now have a service function that will retrieve an author from our database back inside our router let's go ahead and create a new endpoint so get a single author by id say author rooter get and here we'll say forward slash and then colon id and then what we need to add is the response the async response so say async request request response response and we'll get the id so id of type number equals pass int and request dot params dot id of radix or base 10 and then we'll do our try so try say const author equals await author service get author and then pass in the id and then we'll say if author we want to return that author so response dot status say 200. and then jason throwing that author otherwise we want to return a response status of 404 so response dot status 404 and we'll just add author could not be found and then finally had our catch so error of type any and just return the same thing that we did earlier which was our 500 so i'm just going to copy it from the last one paste it in and there we go so if we head back now to insomnia we have for example id and author of id1 so william shakespeare and if i add to this let me just duplicate this and say get single author here i can pass in the id of one if i hit send we get back the author id one created our updated first name and last name and then one thing to note as well is that this author isn't being strictly checked so if we want to just return the id first name last name and all that so we can just say select and then id true oops fast name true and last name true and now if i hit run again send we get back those three but i guess for the sake of our uh detail endpoint it might be cool to have have that and it's lucky actually that we don't have a strict checking on otherwise this one of run and types we would have complained that we haven't defined created updated at which i guess could be a bit misleading but that's fine for now all right so the next endpoint is one that will allow us to create an author so inside our services let's go ahead this is not services this is our router site services let's create a new um function that will allow us to create one so we'll say export and then const create author async and then author and this will use the same type as we defined earlier however we don't want the id so we can omit that by saying author and then id so we just want first name and last name and this will promise a author so we'll say author like so let me just shrink that okay so inside this we'll say const and let's extract the first and last name from our author that we pass in so we'll say just here first name last name and then we can add return db dot author dot create why is this complaining now create what happened here let me just go back second all right here we will add just add a space there okay so we want the const first name last name from our author and then let's return our db dot author dot create say data and we just need the first name and last name as that's all our database requires so last name like so and then below that we can just select the data that we want to say id true first name true last name true all right so now we have our create service function before we go ahead and add all this back so we so we so that we don't jump back and forth from our router file let's go ahead and create two more once you handle updating an author and a one for deleting so again just below our create we'll say update author async and this will be author of type omit author and id so we don't want to pass in the id id will be kept separately as that will come from our parameter or our url parameter and then promise say author and we're missing our const here all right so we need first name last name author and then return db dot author dot update and we need to specify where we want to update so we want to update it based we want to update the object based on the id that we pass in and then we want to give the data so data and this will be fast name and last name and then finally we can just select what we want so we want the id the first name and the last name and there we have it so that's our update pretty clean as well i mean we specify where the data that we're passing in and we can just select the properties that we want finally this one as well is very short and sweet so we'll say export cons delete author async say id number so we will delete the author based on the id that we pass in via the url parameter this will return nothing so we'll say void and we'll say await author dot delete and we'll delete it where the id matches the id that we pass in so that's our delete function we have our update and also our post now we need our apis to make use of those so inside our author.router.ts file let's go ahead and first create our post so we'll say author dot post and then we need just a forward slash next let's make use of our express validator so we want to make sure so we're going to be passing in two parameters and let me just specify that above so post create a author and we'll say params the first name and last name all right so we need to first check our first name so we one thing we can do is say body and then first name if you remember earlier we imported body above here and then we wanna let's say we wanna make sure that this is a string so two or is string we also want to check our last name so that's the same thing as well so body is our last name dot is string and then let's do async request request response of type response inside that let's go ahead and first check our validation error so we'll say const errors equals a validation result which is again something that we imported earlier from express validator and this will check to see if we have any validation errors that occurred so we'll pass in the request then we'll say if not errors is empty then return response dot status 400. and jason in there will say errors errors dot array so this will return back any of the validation errors that show up and we can check that out when this is complete so we'll say const author otherwise if everything worked out smoothly let's get the author from request.body then say our new author equals await author service dot create author and we just need to pass the network that we get from our request body and then finally let's just respond return response status 201 dot json and our new author otherwise that's catch error type any and we'll return our 500. so we'll just copy this from the last endpoint paste it in here all right so now we have our post or our create author let's go back to our endpoint i'm going to go ahead and duplicate this we'll say post author create all right so first of all if you're using insomnia let's change this to a post request and let's add our body this is going to be in json format so let's go ahead and first say first name camel case and we'll say the author is jane and last name is do let's go ahead and send this and we get that back we get back id first name and last name if i go now and get all authors so maybe i renamed them wrong this should be post create author and this one should just be get authors but inside our get authors if i hit send we can now get back our new author that we added which is jane doe let's check out our validation let's say if i miss out the last name if i send this we get back invalid value last name body and if i get the authors it wasn't added as it just returned the error or let's say for example i just bring that back if i set the first name to an integer so 234 i send that we get back first name invalid value and it returns a value as well so expressvalidator does a lot for us which is really nice so we can kind of leave this off now so let's now go back and add our put endpoint so that one that will manage uh our updating of an author so author ruta dot put and sorry if this becomes a bit repetitive but the point is to kind of drive this home inside this will have the a same of validations so we can copy this here so we want to check first name and last name as these are the only things that can be updated next let's add async and we'll have our request request response response and let's add some comments above that so we'll say this is responsible for updating an author so this is a put and inside that let's go ahead and first check our validation error so again we can copy this paste that in there then let's do our try so first let's make sure let's just go ahead and say const author equals request dot body we also need the id from our url so just above our try let's go ahead and get that so we'll say id number equals pass int request dot params dot id 10 and then continue we'll say const updated author equals await author service dot update author and then we pass in the author that we get from our body and then id if that works out smoothly then we can return response dot status 200 json and updated author otherwise let's catch that error any and we'll return our 500 i'm just going to copy the one from earlier and just paste that in all right so now we have our update we can go ahead and try that out in a second but finally let's go ahead and just add our delete which works in a very simple way as well so we'll say author rooter and then delete based on the id in the url async request i'll type request and response oops response and we'll say const id number equals pass int and request dot params dot id is 10 and here we'll say try await author service dot delete based on the id and then return response and here we can say 204 for no content and json we'll just say author has been success fully deleted and then for our catch again error any you can just paste in our 500 error like we did earlier all right so now we have two new endpoints we have our put and our delete just add this here delete an author based on the id all right let's go ahead and flex this so let's create a new endpoint so we'll say update author this will share the same or a similar url copy this one paste that in based on the id so let's go with number three this will be a put and we need to add the body so this is going to be jason and first let's just check what the id of three is so if i hit send here it's john doe let's update that say we want to change first name oops first name over to michael and last name we can just keep it as i always say smith if i send this we get back michael smith and the id is three so the one that used to belong to john doe if i go back to get authors and if i hit send we can see now that the one with id3 is michael smith and the same if i do the detail one it's michael smith and you also get to see the difference between the updated app so i created that uh is the one that when we initially created this and then we updated that is when we later changed it all right so that's our update let's go ahead now and create another one let's duplicate this and say delete author create and this is going to be a delete and let's delete the one with id let's do an id that doesn't exist if i hit send we get back this rather ugly one i mean we can of course change it but it says that this failed 500 error all right that's good if i run it with id4 if i send this now nobody returned for that response we just get 204 no content and that works out well so i would both our update delete work along with our post get single item or get detail author and get list authors all of those work as well which is great news now we can move on to working on our book service and router and this is where we'll also check out a bit more of what comes with prisma in terms of how we specify the data that is returned so just like we've done for our author directory where we have the orthodox root ts and the service ts file we're also going to create a similar directory for our books so i'm going to call this book and inside there create a new file first one being book dot service dot ts and whilst we're at it let's just create the book dot rooter dot ts file as well all right so the first endpoint we're gonna do we'll start off simple we'll just list the books all the books that we have in our database so the first thing is we need to import db from our utils db.server file then let's go ahead and define the type it's going to return so i'm going to create two different types one type is going to define the reading of a book so when we read a book from our database and the other is going to define what it will look like when we write a book but first let's just stick with reading a book so we'll say book read equals and then we'll have an id so we want to bring back the number we want the title which is going to be a string on date publish which is going to be a date is fiction which is a boolean and the author id so we'll stay with the author id and we'll extend on this by actually telling a bit more about the author rather than just that id so for our reading type the this is what we'll use for our list books function so we'll say export const list books async and then we will return a promise which will hold book read and there's going to be an array and finally we'll do that all right so first we need to just write our return we'll say db.return book dot find many and then inside that we'll set what we want to select so we want as you can see with book redo on the id title date published is fiction and author id so we can say id true actually i need this select here so we want id to be true we want title to be true date published true the is fiction true and the author id to be true and there we go it fits the criteria that we have for the return type so a list of book read in that in that form now we can go ahead and add the first router for our books so to do that let's go ahead and import express from express then we need to import our type so import type request if i can type request response from express we also want to import body validation results for later use from express validator all right so let's import our book service so import all has book service from book service let's create our router so cons and then book router equals express dot rooter then let's create our get them point so get list all the books say book router dot get forward slash and then async request is oops did that just import something okay i did this is going to be type request response response and then we'll save con we'll say try and then const books equals await book service dot list books and we'll set it as that and then we'll return response dot status of 200 if everything checks out and we'll jason the book so we get back and then finally we want to catch the error so again very repetitive from what we did last time for our get get list all uh authors here any and then return response dot status and then here we'll add 500 and we can just return json error dot message all right so of course our api or our server does not know about this we have to add that inside our index.ts file to do that let's first import that so inside index.ts import book router from book book router and then down below we can go ahead and say app dot use forward slash api forward slash books and we'll say book retail and there we go now our server knows about our new book retail so let's go ahead and run the server i already turned mine off but if you want to run it again so npm run dev so now i'm gonna head back over to insomnia i'm going to open up a new request it's going to be list or just say list all the books great and then here the endpoint is going to be you just copy this as a template and it'll be localhost port 8000 whatever port you set it as and then books i've hit send we get back three of the books that we added when we seeded our database so get back homodeus sapiens and the ugly duckling along with also mainly to look out for is this author id as it's just returning the id of the auth that we have however in reality this may not be that useful as you may want to actually represent the author inside of this json response so we can go ahead and extend that now so to do that let's head back over to our book service.ts file and for that let's go ahead and go back to the top of this file and where we have author id let's go go ahead and get rid of it i'm just going to comment it out just in case uh just for reference sake but above that we need author now the type of this is going to be something along the lines of id first name and last name and we already have that defined inside our author service so we need to import this otherwise we're just going to get these errors to do that first let's go back into our ortho.service.ts file and just before we say type with the author let's export it like so now back inside a book.service we can go ahead and import it so we can say import type and we'll say author and this is from dot author dot author dot service and there we go we should have no complaints with our types however our list books function is no longer working we're getting an error back because the what we're italian does not match an object inside this array so to do that we need to specify what the author will look like and we already have a reference to the author in book as uh we added that as a foreign key so we're gonna say oops i'll comment this out actually so we'll say author and then inside that we say select so what do you want to select from the author and inside there we'll say id true first name true and last name true so now we have the author and we have no more complaints so if we go back now to our to insomnia or whatever interface you're using if i hit send now now we get back author with the id first name and last name so it's pretty easy to extend that all we had to do with prisma is just address the foreign key and then select what properties we want of that foreign key so id first name and last name cool so that's our list books let's go ahead now and create the other endpoints now this is going to feel a bit repetitive um just bear with me but just for completion sake let's go ahead and add all of this so we'll say get book async this will take an id which will be of type number it's going to promise a book read or null if the book does not exist i'll say return db.book find unique and here we'll specify that the where is going to be where id matches the id and then we want to select what we want to select so as it's in the form of book read where we have id title and all this along with this author we can go ahead and pretty much copy this thing here if i'm able to copy otherwise let me just let's just type it out so id true we want title as true the is fiction i mean we could set this as a variable and just unpack it but it's i think just nice if we type this out explicitly and then author we want to select id true fast name true and last name true all right so now we have our get book so inside actually let's go ahead and just define all these service functions first and then we can head back into our router that way we're not jumping back and forth from each one the next one is going to handle the creation of a book so create book equals async and then book and now we need to specify the type of this book so we already have this book read and we can't really use that as unless you want to pass in the entire id first name and last name of the author which is definitely redundant especially with the first name and last name we could just pass in the author id so for this type let's go ahead and create a new one and we'll call this book right so we'll say book write equals and then in here we'll say title string then date published which is a type date then author id so that's what we'll pass in which will be a number and is fiction so boolean so now down below we can go back to our create and we can set book as being a type of book right then what we need to add is the promise so we'll say promise and this is going to return book read so we want the author id along with first name and last name rather than the id itself so here we can say const and let's just unpack book so we can get the title author id date published and is fiction then we can say const and let's just pass the date to make sure it's date we'll say new date and throw in date published and then down below we'll say return db book dot create and here we'll pass in the data which will be title author oops author id is fiction and date published we'll set it as pass date actually we'll name this past date has already been passed so we'll call it pass date alright so we're still getting a complaint because the return type of this does not fit book read and to do that we can just add in again the same select that we defined before so i'm just going to copy this the sake of time and down here underneath data so underneath that comma we can paste that in hit save it should format it for you and then yeah that's that's about it that's our create book now let's go ahead and create our update author or update book service so here we'll say export const update book async we'll say book book right and the id so the id that we passed in that we will pass through via the url param promise will be book read let's go ahead and write that so we'll say const and then that equals book and we can extract the properties from that so we'll say title is fiction date published and author id now we'll say return and then db dot book dot update we'll set where so when you say which object you want to change in the database so where the id matches with the id that we pass through and then data we can just say title and then is fiction date published and author id below that we can select what we want so i'm just go i still got it on my clipboard so i'm going to paste in that select and that should be it for our update so the select to make sure is the exact same as we have in all the other functions that we defined above so that's our update book the last one is just to delete a book and this one's fairly simple so we'll say export const and say delete book equals async id number promise it's going to return back void and here say await db dot book dot delete where id matches the id that we passed in that's all our service functions done again so it's all just crud staff create read update and delete so we have update our delete one and also our create get and get list all right so that's our services done let's jump back into our router file and let's add or let's utilize our service functions inside our api so the next one is to get a book based on the id say book router dot get and then id say async request request response response and then here we will get the id and make sure that it's a number so we'll say equals pass int and request dot params dot id base 10. and then underneath that try const book equals await book service dot get book person id and then if the book exists return response dot status dot or 200 dot json book finally we need to catch any errors so error of type any return response status 500 and then jsonify the error so error dot message okay that's our get id we can go now and just test that out so i'm just going to go ahead and actually duplicate this so get a single book and here we can pass in the id so if i pass an id one send we get back the first book which is homo deus along with the author date published etc if i pass in a id that does not exist we get back hopefully if this responds is it going to respond try again okay maybe it resolves in a second but for some reason this is taking a lot longer than it should let me just restart the server all right never mind we'll come back to them so the next one is our post endpoint so we'll say book router dot post here just forward slash and then for this one we also we need to set up our validation as well so we'll say body so what we imported at the beginning of this file title dot is string so that make sure it's a string body and then author id because we'll be passing an author id when creating a book and then we'll check to make sure that this is int let me just save this and then we want body shrink the side body and we want the date published for this we'll say is date and i know we kind of convert it into a date later on in our service but we can add today which should also do the same thing or convert it to date and then body will add is fiction and we'll say is boolean all right so underneath that we'll say async request request response response and let's go ahead and define the body of our function so we'll first check to make sure there are no validation errors so const errors equals validation result and request and then if not errors dot is empty return response of status 400 and jason errors errors dot ray underneath that let's add our try and this will say const book equals request dot body and we'll get our new book so we'll say const new book equals await book service dot create book and throw in our book finally let's return response dot status and we'll say 201 jason new book and then here let's add our catch so i'm just going to go ahead and copy the catch that we've defined earlier save some time paste that in and there we go so if i go back i don't know for some reason why this one didn't run but let's go ahead and create a new request it's going to be create book and we'll post it let's get that url from this one paste that in now if i just send anything we get back as we didn't pass anything in the body we get back all the errors the validation errors so we need title author id date published and his fiction so for here i'm just going to copy the date from this one we only need the date time doesn't really matter so if i go back to create book let's create a body json and we'll say title let's create harry potter and we'll say the author id which we need as an integer we'll say is 2. date published we can paste in this date let's just change it up a bit let's say 2002 and the last one i think was is fiction and we'll set this to false because it's based on the true story so let's go ahead and send that and we get back our book so we have harry potter is fiction false date published which is 2002 and the time if we don't add a time it just sets it to midnight the author id you all know harari which i guess we've added quite a few books written by him but let's add something else who else do we have for get authors so we have william shakespeare of id1 can do something for him let's go ahead and add macbeth we'll say id one this is published oops this here was probably i don't know when it was published under like 1600s or something so 1640 send that so we now we have a book for william shakespeare if we list all the books now we get back all up so we get back our new ones harry potter and macbeth all right so that's our create book now we need one for our update which again is very similar to our create just that we have the id passed in the parameters so i'm just going to go ahead and copy this book group to post and paste it down below now let's make all the necessary changes so first of all this is a put let me just add the comment above it so put update book so our validation still checks out in the case of our errors all this can remain the same we can get the book from this and here let's call this updated book and rather than create book we need to update book and we also need to pass in the id so just above that so actually here we'll say const id type number and we can oops pass int and request.params.id 10 and in our update book we can pass in the id and for our json response update updated book which is that so let's go ahead now and let's copy this duplicate update a book so update a book this is going to be a put let's update the one with id4 let's take the body of this and actually let's check what idea 4 is so what's the one with id4 so it's harry potter and ivana harari let's say we want to change the author of this so in put updates a book in our json let's face this in let's say the id is now the author with id3 if i send this we cannot put api books why is that uh booker let me just restart the server oops if i send this now 404 not found ah i didn't put in the id in the url parameters so just here where you see my cursor we need the id save that now if i send it we get back the author is now a dude called michael smith all right so and we also have macbeth i think before was harry potter i think we changed we had it we changed quite a bit of this but the id is still four so it didn't update everything it just updated all the properties apart from id all right so now the final one is just to add our delete endpoint now this one again is very simple so we'll say book router dot delete inside this we need the id say async and then request type request response of type response and then we can say const id number equals pass int i will say request.params.id say try await book service dot delete book and then just passing the id there return response dot status and this will be a 204. jason will just say book was success fully deleted and then for our catch say error i'll type any and return response dot status 500 json and we'll say error dot message and that should be it so let's create a new endpoint let's say we want to delete the one with id4 so new request delete book this will be a delete throw in that let's send it and we get back 204 no content and now if i go back to get all books hit send we see that the book with id4 no longer exists and that pretty much wraps up our typescript express with prisma api where we just did some simple crowd stuff but also made use of foreign keys and how to treat those within our database but i hope this video was of great value to you if you enjoyed it please leave a like and subscribe all of this code will be made available in the github link which i will put in the description also i have a discord server so if you want to join that ask some questions or get to know people feel free to join that the link for that will also be in the description below but otherwise stay healthy stay safe and i hope to see you in the next video [Music] you
Info
Channel: rithmic
Views: 33,536
Rating: undefined out of 5
Keywords: TypeScript, RESTful, JavaScript, API, TypeScript API, Prisma, Programming Tutorial, Software Engineering, Software Development, ExpressJS, Express, Express TypeScript, SQL, Postgres, Web Development, Web API, Prisma library, REST API, web framework, TypeScript Tutorial, JavaScript Tutorial, SQLite, Backend, Programming, TypeScript Programming, Software Engineering Tutorial, API Tutorial, Prisma Tutorial, Express Tutorial, TypeScript express
Id: PM58NEMJgMw
Channel Id: undefined
Length: 96min 58sec (5818 seconds)
Published: Sat Jun 11 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.