Build a High-Performance API with Next.js, Hono, Redis (2024)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey man in this video we're going to build an ultra high performance meaning speed API latency in this video together this idea is not new it's based of a video I did on the main Channel like a month ago that you all really liked and the cool thing is the tools you're going to learn in this video to make this high performance happen which are reddis hono Js and cloudflare workers that we're going to use to deploy our backend you can use for anything else we're going to take a look at an example in this video it's going to be a search app a search functionality but this is useful for any scenario where you need seriously fast and cheap apis that's not just search but anything you can imagine we're going to go through all Concepts step by step together from simple to easy no not to Easy from simple to hard that's what we're going to do we're going to go through all Concepts from simple to hard together step by step and we're also going to take a look at the concepts why is this so much faster how do we achieve these better latencies why is this cheaper than the traditional way of deploying nextjs everything together in this single video and also for completely free uh you can follow along without any credit card no payment for any tool and we're going to do it all together in under 1.5 1 and a half hours so if you ever need serious performance in nextjs it's going to be super useful knowing what we're going to do together in this video and that's it let's take a look at the example why this is so much faster the thinking behind it and then let's get coding and implement this together let's go and this is what we're going to build together in this video it's called speed search a high performance API build with hono nextjs and Cloud flare we can type a query below and get our results in milliseconds so let's try this out we can search for any country that we want for example let's search for Germany and there we are Germany found one result in 11 milliseconds and same thing for any other country right if we just type an a here then it's going to list all the countries in here that begin with an A and list at the very bottom how many results we got in how many milliseconds how about United States of America in yeah in parenthesis the all right that one interesting so we can just select that and now I want to point your attention to this one right here we can choose the engine we use for the search the postgress is arguably even the slower one and that does get especially clear in the hosted version right here these results are not very realistic because if you notice we are on Local Host 3000 however if we switch over to the hosted version you're going to see a pretty big difference if we search for example for aeran well it's going to get a cold start that's not a very fair compar person but in general we're talking about 94 95 to 100 milliseconds for post GR in reddis that is very different but let's prove my point we are always at about 93 94 milliseconds with pulg let's switch over to redus let's get rid of it all and let's try this again in the Rd search mode so right now we're at 75 milliseconds 74 now we get 80 70 if we type in Justus an a we can see we are about 76 milliseconds so it tends to be quite a bit faster than the postris search engine now how do these differences happen why is reddis like 25% or something faster than poges so I went ahead and did some benchmarks for example with esite with poges and with rdus and went ahead and compared the results now is this super scientific probably not I did like 10 searches just eyeballing it and then write down the times for the respective database search times but this does allow us to get a pretty good idea of what we're talking about here so SQ light surprisingly also to me was actually the slowest with on average about 110 milliseconds for the search results then came pulse gr with about 92 milliseconds what we just saw in the other Tab and that's about 16% faster than escolite and lastly oops again 20% faster this time is redis with on average kind of about um 74 milliseconds and if we compare redes to escolite directly that's an about 33% decrease and compared to postgress that's about 20% so redis is pretty damn fast but it's not just redis it's the entire infrastructure that we are using to build this high performance API that I'm talking about right the secret here is not just using redus right a high performance API doesn't just depend on reddis as the engine which also is super fast but there are other tools involved like hono like Cloud flare that help make this API super performance and as a basic overview I want to give you why is this so much faster than PG or sqlite or current high performance API setup well let's take a look at the conventional way to write an API or to host your infrastructure forward right for example the database we are using in this deployed application the postgress one is deployed in Europe in Frankfurt right here with no additional read replicas but once a user for example right here from the US West Coast makes a request it doesn't go directly to the database right that doesn't happen there's a proxy in between and that is wherever we deploy or Cloud function for example on AWS Lambda which versell uses under the hood if we use the postgress search engine and deploy this to verel and by default I think this is hosted right here on the US East Coast that request then has to go to the database hosted wherever you chose right that single region this could be in Europe this could also be in the US but then imagine if the user came from somewhere else basically the entire thing would be backwards right so there would still be a pretty decent bit of latency involved here once our database retrieve the data it sends it back to our function which then sends it back to the user and that's quite a long way to go for data if we take a look at the infrastructure behind the API we're going to build in this video it looks a bit different because the thing is with the tools I'm going to introduce to you that we're about to use in a second this is how it looks like architecturally right our database has multiple replicas around the entire Globe which means no matter where the user is chances are the next region is going to be pretty Dam damn close to the user wherever they are and this is also a super easy setup right this is not with architectural overhead at all you're going to see this literally takes a few Mouse clicks to do um so it's it's very very easy and the region where we deploy our function is also distributed around the globe you can imagine it very similar to our database so if a user is on the US West Coast There is almost no distance that or data needs to travel it's all already there same thing if the user is in Europe for example right all the important infrastructure like or function and or database is already there and same thing for the other regions so you see the difference to the conventional database setup right where the database is always in one spot the function is always in another spot this kind of setup with the tools I'm going to show you in a second allows us to get those better latencies when using the kind of fast mode the reddest version that also uses hono and Cloud flare in a super easy to write super enjoyable API to actually get those um sub 100 millisecond latencies whereas with postgress those tend to be just a tad slower you know on average they tend to spike a bit more tends to be a bit slower I guess on average around those 93 92 milliseconds um that I put in The Benchmark down here and that's how we achieve a really really good performance and we're going to build it all together in this video so this doesn't just apply in any way for a search right this is just an example anything that involves a database and an API you want to be fast Works super well with this approach using for example hono a framework that we're going to use to write or nextjs API super nice to write an API in hono by the way and we're going to take a look at some examples you're going to see exactly how this looks like and they have full support for versel as well if we take a look at that here can simply set up our API like this and this kind of replaces or out of the box next TOS API so it's a proprietary syntax it's going to be a bit different how we write our API but what this kind of setup allows us to do is now to deploy to not forel but to Cloud flare workers directly I did an entire video on why this is faster for example the versel logging overhead is not here if we deploy directly to Cloud flare workers and Cloud flare workers if you're wondering what is the role of this um that's basically the CF that's the cloud flare I'm going to mark it for you these are the cloud flare workers basically a globally distributed version of our a Pi so this is nothing else than hosting or nextjs backend code in horo syntax and distributing it across the globe so it's always close to the nearest user and lastly for the globally distributed database we're using upses for that of course full disclosure I work there but it's genuinely a really nice solution we're going to use reddis and we can have some read replicas distributed around the entire globe that basically let us have low latencies from anywhere and the bypass that restriction of the database only being allowed in one certain area right so our final infrastructure will look very similar to this with a lot of distributed database instances and a lot of distributed function instances so no matter where the user is it's always going to be close to them versus in the conventional setup that is not the case and that's how we get the really nice latencies so as I said we're going to do it all together in this video it's going to look nice you can put it on your portfolio if you want there's even a little animation I put in here uh just for fun you know it doesn't add any functionality but I think it looks nice and if you decide to put this on your portfolio um then it's going to look even better with an animation the functionality I try to keep as simple as humanly possible to really focus on the high performance on the speed of the API rout and not get too caught up in the exal search functionality because chances are you might need that you might not need that um this is just an example to demonstrate the API speed now to get started with all of this open up your command line and we're going to navigate to our desktop at least I will this depends on where you want the project you know to live on your PC I generally put these on my desktop and we're going to say pnpm DLX create D next- app and let me zoom in so you can see this easier at the latest and then we can give this a name for example let's call this fast API and hit enter before I'm going to hit enter by the way if you wondering what this is pnpm DX well it's basically telling nexj to install the dependencies using PN npm which is just a package manager you could use npm or npx just as well same thing with yarn I just personally prefer pnpm because that caches very efficiently uh through Sim links but that's just a tiny detail if you want to use any other package manager just replace this part right here and then hit enter that's going to ask us a bunch of questions like typescript yes we do es yes we do to ensure code quality Tailwind CSS yes I like it Source directory this is very much person preference I prefer it as well I think the code looks a bit nicer a bit more readable that way and the app router yes and no we don't want to um customize the default import Alias and then hit enter that's going to install all the dependencies and this is a beauty of pnpm it added 353 dependencies up until this point but it only downloaded actually two and it achieves that through Sim links now I could do a whole video on how that works basically it's a caching mechanism on your system that uses packages instead of installing them separately in every npm modules that you have on your PC which is very efficient um but I guess if you don't like pnpm for any reason um then you could also use yarn or npm same thing okay we can navigate into the folder we just created we call it fast API and then say code Dot and all that's going to do is open up this project in vs code it's going to do it right here on my second monitor so let's drag this over um and you could could also navigate into the folder yourself and then right click and open with vs code same exact thing and the Beautiful Thing is now already all the dependencies are installed using pnpm now let's verify that everything worked correctly we can simply start up or development server and oh I already have an app running on that Port so let me quickly stop that let's run yarn Dev npm runev or pnpm runev once again and that's going to open up our basic next project on local host 3000 so let's try this out I already have Local Host 3000 open here so let's refresh the page and we should see the very basic um nextjs kind of setup without any functionality so let's let this load sometimes this does take a pretty long time especially the kind of cold starts when you first start this like 2.4 seconds Ah that's kind of a lie I guess I think it took longer but anyways um there we have it we have a basic next s page perfect this is a very very nice place to start now since I want to show you how this works under the hood let's start with a very very simple implementation on the front end that allows us to get to the actual high performance API really quickly and then kind of build out the UI and make it look good so if we had to visualize this um let's go into dark mode Again by the way light mode looks absolutely Dark Water step one is going to be uh basic very very basic front end then step two is going to be high performance API and lastly the step three is going to be make things not look bad so essentially make things look nice you know these are the three steps we're going to follow first build the basic front end and then get to the high performance API in the next like 5 minutes cuz as you're going to see the react implementation of this part um is going to be really really straightforward so first thing we're going to do and let me make this much larger for you so you have an easier time seeing what's up here first thing we're going to do is go to the very very top of the page. TSX that nextjs generates for us and the reason we go at the top here is to say use client this is basically telling next CH to render this page on the client s which is a requirement for us to use things like react hooks for example the state hook now I have a snippet for this but since you probably don't have it let's declare State manually right here um and we're going to worry about the return in a second here um so for example we're going to say con Mt array we're going to worry about that in a second is going to be equal to use state that we import from react and this is going to be a string which you can pass in as a generic to tell typescript what the value of this will be and then let's initialize this as an empty string now do we have to do this for typescript no typescript script is actually smart enough to infer the value by itself and we can see that if we destructure from the array the uh input and that's also called a set input right here so as you can see the input is automatically inferred as a string and so is the input for the set input as a string but this is just personal preference I like doing this because chances are if this didn't have a string as an initial value then the inference of course doesn't work and we would need to tell act explicitly what this is so why not just do it anyways and I think it's also very nice and readable so that's just personal preference that I like to do in all my projects and chances are you might like it too so next up we're going to declare one more State and this is going to be let's call use State and worry about the array destructuring here in a second and we're going to leave this empty we're going to initialize this as undefined but again we're going to pass a generic into here to tell typescript what the type of the value will be later lat on and this is going to be the results and it's going to be a string array these are going to be the actual country matches that we get like Germany like the United States of America like India and so on that's going to be the results as a string array and then the second thing is going to be the duration how long did it take to get or data from the database this is going to be a number and that's what I showed you in the previews right here that's how we measure the latency it takes to kind of search for these countries so if we were to search for a country right here here I think it's aeran there we go um or Germany or India that's how we measure the latency at the very bottom right here that's going to be our duration we're saving perfect okay let's get started with the UI finally a very basic implementation could look like this where we have a div in the return statement and we also have an input right here now to make this a controlled input we already have or state and we basically want to save what the user typed in the input right here in the state the way we do that by passing a value which is going to be the input and an unchange Handler in the unchange Handler we get access to a callback function that contains an event so let's call this just e and then let's say set input to the E do target. value just like that so we're saving whatever the user input in this HTML input field right up here in state and the reason we are doing this is going to become very clear right now so inide of a US effect right let's put that right down here this receives a callback function as well and this receives a dependency array basically every time the input changes every time the user types something into the field we want this callback function in the use effect to run and fetch or most recent data so to do this we can define a custom function let's call it for example fetch data and this will be an asynchronous function right here an arrow function um so we can make a request to our backend and awaited it and then at the bottom we're going to call this fetch data function um just like so so when this use effect runs it calls the fetch data function there we go the logic is being executed but if we don't have an input so if the input is an empty string for example in that case we're going to return early we don't want any logic to happen and we want to reset the search results because if the input is empty chances are the user also deleted what was in the input and we want to clear all the search results the way we do this is by destructuring the search results and also by convention the set search results from the use State hook right up here and now we can use that and return set search results and we're going to set this to undefined essentially removing all the data that is inside of the state um when the input is set to an empty string now if the input is actually any word any string that is valid that is truthy so this if condition doesn't get triggered in that case we're going to make a request to our back end for the actual countries that match the user query let's say con stress is going to be equal to wait fetch super simple functionality no react query in here no axos nothing um I just want to show you how to write how to write a really fast API and we don't need those tools um to do this so we're going to make a fetch request to the SL API SL search and then we want to pass a query parameter now we can call call this anything we want I decided to call it Q for query and this is going to be equal to and then in the dynamic kind of syntax right here um so this is a template string and we can now dynamically insert values here that's going to be the input so what the user actually typed in now let's try this out already right let's save this page and let's start our development server it is already started fantastic and then let's go into our Network Tab and see if this actually works so whenever we type something in here like an a for example we should see a network request being made to our back end and there is which is perfect let's zoom in here and we can see a network request is being fired to Local Host 3000 API search perfect right now we get a 404 because this endpoint does not exist there is no endpoint to receive this search query and that's perfectly fine it makes sense and this is where we use the First Tool in this video which is hono JS a nextjs compatible fast lightweight web standards following framework for or backend and they have a native nextjs implementation like a starter kit um so the implementation is honestly super basic they explain how to do it here and this is what we're going to follow right now so let's navigate into our project and you're going to see how simple this is in our app folder let's create a new folder and call this API this is going to be our backend right front end API folder is going to be our back end inside of here new folder and then in two angled brackets like the JavaScript array Syntax for example dot dot dot route and then two closing angled brackets what is the syntax you might ask what the hell is this basically it's a catch all route so when we make a request to/ API SL whatever whatever then it's still going to be received by this endpoint whereas if we had just route in here you don't need to follow along with this then only if we made a request to specifically curl um HTTP Local Host 3000 API route now it would match or folder structure right because we have a literal route right here but if we wanted to change this to/ API search for example well there wouldn't be an end point to receive that in or syntax that we have right here with the angled brackets this would still be called um for or call request because anything that comes after the API will be matched by the syntax and inside of here let's create a new route. TS file this time now for the actual logic we're not going to use the buil-in nextjs end points I don't like them that much anymore because the better alternative or the faster alternative at least for this video is going to be honu so we're going to say pnpm install npm install yarn at whatever you want and that's going to be honu and hit enter that's going to install that dependency and by the way if you're wondering how many downloads does h get well basically recently it's been gaining a lot of traction and that's for good reason it's a really nice framework small simple Ultra fast web framework for the edges it works on any JavaScript runtime so it's super flexible and we are going to make use of the cloud flare workers um that it works there it's going to be very very useful for us but if you want it you could even deploy this on verell but then some performance benefits of the high performance API um would not be there because Cloud flare workers are extremely cheap and they are extremely fast and performant as well so we're going to make use of them now after installing our hono dependency let's start back up our development server and let's do a couple things first off let's export a cons oops cons runtime from this route. and this is going to be equal to Edge so if you were to deploy this on versel this would still under the hood at least be deployed to Cloud flare workers because that's what versel uses under the hood if we deploy straight to Cloud flare workers you don't need this but um this way this is compatible with both versel and cloudflare workers directly without any modification which I think is a super nice thing now the actual app right right let's say const app and this is going to be equal to a new hono that we import from hono at the very top and we can simply invoke this class and instantiate it like that and we can even give this a base path as a string and this is going to be slash a API so basically if we were to make a request to/ API search we wouldn't have to specify that every single one of our routes like for example the app.get that we're going to declare right here like for the/ search and then the um function that's going to handle the logic when a request is made to this HTTP endpoint we don't have to specify SL API each time because we passed the base path once and that's just something super common you're going to see in every good backend framework um for example in fastify that used at my previous job or in Express or in hono and so many other languages and Frameworks um like the base path functionality is super super common now in the Callback function hono gives us access to something called C which is the context that we can receive right here and then let's already return some c. Json just to make hono and typescript happy and this doesn't have to contain anything yet basically this is the setup for or high performance API it doesn't use the regular nextjs syntax however we can make this actually compatible with the basic nextjs syntax so we get the performance benefits of deploying this to Cloud flare but also the compatibility benefits of deploying this to versel if we want it to and doing that is one line of code it's extremely easy we can export a const and then the HTTP verb which is for example get this could also be post whatever you want to handle and this is going to be handle and then just WP or app and if you're wondering where this comes from this comes from h/ verel so they have a versel integration we can use um if you want to deploy this to versel then this will handle our requests or the user requests and if we deploy this to Cloud flare workers directly we can export default app as never at the very bottom now why the as never basically that's a kind of hacky typescript workaround to make the nextjs compiler happy cuz by default it doesn't really like default export from an API rout it doesn't expect it so it's going to give us an error um however that's not any important error we can simply bypass it with the S never and then everything works super super smoothly perfect we can save this file and this is literally the entire setup we need for a super high performance API that we can now deploy to cloudflare workers and in doing so we should notice that the 404 error that we used to get on Local Host whenever we wrote anything inside of our input should now be gone because the API rout to catch that request now exists and by the way did we name this SL search by the way yes we did so this is going to be important for later and but we did name the SL search so let's restart our server head over to the network tab under the fetch request and then type in anything and that's going to get us a 200 okay with an empty response because that's what we sent back from hono perfect very very nice this means we set up everything correctly and we're now ready to get set up with our data database to give actual search results right here in the response to get set up with our globally distributed database that I talked about earlier right here so basically we get this kind of infrastructure which is faster than the conventional one we're going to use up stash and now again full disclosure I work there that's how these videos are possible but even if I didn't work there I've used them before and let's log in on my second monitor there we go and the service is just nice it's just really damn nice that's that's all I have to say um and that's how we achieve the speed um in this video so we're going to navigate over to the reddest tab right here oh and basically this is free as well like it it doesn't cost us anything it's free tier uh so this is just um really nice so we can click the create database let give this a name like Fast API for example and you could even go Regional right I guess some performance benefits would be lost what the regional means is basically you choose to only have one database replica somewhere but if we wanted read replicas around the globe so no matter where the users this is always going to be close um in that case the global makes more sense with a primary region and then the regions you want um the read replicas to be in so basically what this does is if you executed a reddis command like set F Bar for example as a reddis command then this would not only be propagated to your primary database but this would also be propagated to any replica uh replica one for example any replicas that you have right so if we have one in kind of India region or something and one in US region and the primary one in Europe then this full bar key value pair would be present in all of them so no matter where the user is they're going to have a pretty fast time retrieving data from your database and that results in the faster search times right so let's go with the global one and for example we can select one that's what I used to do personally um that's what I like to do it's one in the US and one in southeast like Singapore for example so we have basically the entire Globe covered so this would be very similar to this setup that you can see right here no matter where the user is it's always going to be one database pretty damn close to where they are and we're going to hit create that's going to create the database for us and also give us a way to connect to our database right here connect to your database we can choose JavaScript and I'm just going to copy this over for our seeding script because what we're going to do together is insert data into our database which are going to be the countries right that we search for like I don't know why I keep coming back to aeran by the way but any country right we want to have a list of all countries a b c and so on to kind of search through and need to get them into our database so that's what we're going to create something called a seeding script for um to get all that data into our database once so we can then always search it in our API endpoints sounds more complicated than it really is let's go into our source folder create a new folder called lib which stands for libraries by the way so basically it's a convention in this folder to prepare libraries to be used in your project at least that's what I always use it for and that's what we use it for at work at my previous work and so on so it is a pretty common convention inside of here we're going to create a seat. TS file and first thing we need is so paste what we just got from up stash and also initialize or install or rice so we're going to say pnpm install at up/ rdis that's going to install our reddis SDK to connect to our database via HTTP save that perfect and now what we need is well a list of every country there is in the world we don't want to type this out um ourself and this was just some debugging I did not important uh and there is actually some mad guy that actually typed this out himself um right here I'm going to link this GitHub just in the description basically it's a list of all the countries there are in the world that we are going to use to put them into our database to make them searchable right so you don't need to Google this I'm going to link this GitHub gist um in the description directly so you can just go ahead grab all the countries and then paste them right here in our application by the way we can also open this up in a kind of side by side just to make this look better and to see what the hell we're actually doing um right here on the right hand side so perfect we have the country list all right and that's the perfect basis to put everything into our database now so below the country list we're going to say country list. for each and we are going to execute some Logic for each country and why is the vs code intellisense taking up that much space on the screen that looks absolutely horrendous so I'm going to zoom out a bit hopefully that fixes things and basically for each country in the country List as a string we want to put it in our database and in order to make this searchable the algorithm we're going to use to do so is inspired as I probably teased in the very beginning of the video which I didn't record yet but uh I will and I'm probably going to mention it there um is created the algorithm is created by the founder of reddis which is antiz and it basically works like this we have a word let's say for example um Germany right as the country then how we break that down and make it searchable is basically like this first off we have a g in our Reddit database then oops then we are going to have a g in all uppercase by the way everything is going to be an uppercase in our database um so the user input is not going to be case sensitive then we're going to have G eer so basically for every letter we're going to make a composed instance of it that that leads up all the way J M then J May and so on and so on you can probably imagine uh I don't need to tell you and then the last entry is going to be the entire word Germany so the finished thing that we want to suggest to the user and with a star at the end so we know this is the entire word so basically when you type in G when you type in g e g r and so on no matter which combination of the above you type in the search bar is always going to suggest you the word with a star at the end and not these these should never be suggested these are just to make this one searchable right and that's a really clever algorithm to make reddis search possible um that we're going to make use of made by the creator of reddis and I think it's really really clever to allow very fast searches evidently as I showed you in the preview that's how it's possible and to make this algorithm work let's say const term and this is going to be equal to the country dot oops country. to uppercase as I mentioned these are all going to be uppercase so there's no case sensitivity involved in the search and let's also initialize a new con and call it terms as the plural and to tell typescript what this will be this will be an object with a score of zero all of them will have a score of zero and a member and this is going to be the string this is going to be the country and this is going to be an array of these objects we can initialize as in an empty array now to get all the combinations for all the countries into this array let's start off with a four Loop so the iterator is going to be called I so from let I equals to zero we're going to go to I is smaller than the term. length so how long is the string and of course we're going to go in one step so for each character right the g g e g r and so on that's what we're doing right now basically we're going to push into the terms so terms. push and we are going to push the substring of the main word from zero to the actual index that we're on that's how we get every combination of the word um into our array so we're going to say terms. push and then here we're going to say the score is going to be zero and the member is going to be the term and term do subing and this is going to go from zero to the current index that we're iterating over just like this perfect and below this for loop we're going to say terms. push right so this is every letter combination and now we want to push the final thing with a star at the end so what we're actually suggesting to the person searching in our app that's what we're pushing now the star thing so to do this we're going to do basically same thing score is going to be zero but the member is going to be the final term so the actual country name plus the star at the end so we know this is a work we want to suggest instead of just the words we use to make this final term searchable and then as the final thing we're going to do in here is declare a const populate DB and this is going to be an async arrow function in which we just say await reddis doz add so we're adding to a sorted set which is basically just a reddis data structure and I can show you that red is sorted set where basically we have key value pairs but every entry also has a score attached to it and is there any good example I can show you to see this well maybe as the images yeah this makes sense so let's see this one basically we have a rank for each entry with a score and the member the member being our country and the score being zero and that we can then search by the rank later that's going to allow the search functionality so basically what you need to take away from this sorted sets are a redest data structure that we can use um to make this PO possible and in order to use it we can give it a um key this is the single entry the single name space all the following values are going to be stored as in our database and we can simply spread in the terms now the typescript implementation of this kind of lags but trust me this works so this is an error we can totally ignore um I don't know why it happens we might have some typescript incompatibility in our uh SDK for Redd is I'm not sure but this is error that's totally fine to ignore we're just going to execute this once it works and we never touch this file again essentially and then we can run the populate DB function right at the bottom here now if we run this file that's going to put all combinations of all countries into our Red's database and build the foundation for or fast performance search so to try this out let's install one package pnpm install as a development dependency because we don't need this in production later on and that's going to be TSX and all that TSX does is it allows us to easily run typescript files as if they were JavaScript files without the transpilation and so on so what we can do is say yarn TSX and then navigate to this kind of location which is Source SL lib SL seed. TS and hit enter and that's going to prompt TSX to run or file connect to our database run through this for Loop and put every country into our database and it did that in 2.6 seconds perfect so what we should see now is if you go over to your uh up stash data browser right here we should be able to see the terms right that's what the key is for here and if we click that then we should be able to see and if I zoom out a bit and there we go that all the countries and all the combinations are in here and all the countries that we actually suggest to users for the above combinations have a star at the end so we know this is something to suggest right perfect this works really really nice and that's how we make all the countries searchable through an inmemory very fast data store which is redis now how do we make this data show up in our search and wow dude this just looks horrible um again that's going to be step three right making this look good but let's at least like at the very least change the class name on the input to be a text let's say zinc and do this this suggestion from vs code takes up way too much space maybe I need to change that sometime so it doesn't appear um anyways oh and is the oh we need to start back up our development server and let's give the input a class name of text zinc 900 that's going to make the text we put in there dark and hopefully at least we'll be able to see what um we're typing in so we can see for which term we get the results here in a second from our back end so actually we can show the data we have in our red database um right here in our UI okay great so as we type something in let's say ASD right here a query is made to our back end every time perfect that's exactly what we want and now the question is how do we extract the search term on the back end and then search or database with it right that's the question how do we do it let's switch over to or. yes on the back end then let me show you how to do this because while it's different than regular xjs it's not actually very hard the first thing we're going to do is Define a type and that type is going to be named EnV config for or environment variables and this is going to hold two things first off the up oops the UPS dashcore red iscore restore token and this will be of type string and the second one is going to be the upore rore restore URL and this is also going to be a string the reason why we're doing this this n config type is so we can get access to our environment variables inside of the API route and that is the core difference between regular xjs and hono in regular next you can for example everywhere access the process.env values in the cloud flare worker runtime there is no process. EnV cuz this is a node.js thing a nodejs runtime thing and the worker dun time that cloud flare uses does not allow process. EnV it works different there the way we get access to environment variables in Cloud flare is like this we can destructure them from the EnV which is a helper we get from h/ adapter and we can simply wrap the C inside of it now to make this type save because currently it is not we don't know what is stored in our EnV values we can pass the EnV config right here as a generic into the EnV function and now this is types save so we can get the up R rest token as as well as the up rdus rest URL just like this and then go ahead and instantiate or reddis instance to actually communicate with our database right here inside of this API route the way we do that is by saying cons redus is equal to a new redus instance or class should I say we get from up// rdus and we can pass two things in here that is the token and this is going to be the upore reddis rest token as you can probably imagine and then the URL oops URL and that is going to be our up/ RIS rest URL there we go now we have access to our database on the back end the redis instance and now getting access to the search query so what the user typed in is also really easy let's say cons query is going to be equal to and then the c. Rec that's how we get access to the incoming request dot query and in here we want to pass the query parameter that we called it right so we called it Q so imagine the URL was like HTTP whatever whatever whatever slash search and then Q is equal to uh let's say g r so the beginning of Germany for example then this and let's change the font this is hard to read then this part the gerer is going to be part of the Q parameter of the request and going to be saved here as the query right so this is incidental that is the same name right this is the query parameters and this is what we're calling this um in memory so the Q so the gerer in this case for example whatever we get from the incoming request and we're going to save that as the query constant right here and if there is no query passed into this API route in that case we're going to return let's scroll down a bit ac. Json and in here we can say as the message that we want to pass inside of this object we're going to say invalid search query and now as the status which is the second object we can pass in here we're going to pass 400 so invalid or bad request however you want to call it right to let the user know hey you forgot to pass the Q parameter when making this request so for example if you just omitted that then of course that would be an invalid request we don't know what to search for and now we get to the fun part which is implementing this algorithm basically the user can search for any of these and if it matches any of these Search terms the query then we give back the item the nearest item with a star right that's the algorithm we're going to implement it's pretty straightforward and it works really nice and really fast the way we're going to do this is by first declaring an empty array let's call this res because this is later going to be the response we sent back from this API route and let's also declare a cons called Rank and this will come from our database this will be a wait reddis doz rank so we can use the rank command for a sorted set and in here we're going to pass two things first one is going to be the name under which we store all that we want to make searchable so in our case that's going to be term and the second thing is going to be the query and now you might notice that the await keyword is highlighted in red and that's because we did not mark this whole thing as asynchronous so let's do that and then the weight will work now what does the Z rank do basically it gives us back the rank of the query inside of our sorted set so you can see that each um item in here has a score and it has a member and the rank in here is the how many item it is and this is going to be really useful right now so before we continue let's do a quick check if the rank is not equal to null and the rank is not equal to undefined only in that case we want to continue because if the rank is null then that means we don't have any results for or search query if the term we search for right for the query that the user is searching for is not a member then of course we can't show any results because that is not something we have in our database and therefore we need to do a check and we're only going to continue our search if it actually exists in our database if not that's the case we're going to handle in a second we're just going to give back an empty array because we couldn't match anything there are no search results and here let's define a con temp which stands for temporary because we won't need it anymore in a second it's just to Temporary hold a value and that value is going to be a wait redis doz range which is the range for a sorted set and in here we're going to search in or term ter kind of name space right the what we call this entire set we're going to pass in two things the minimum as a number and the maximum as a number and these are the ranks we are filtering by so the minimum is the rank we just found out that's where we are starting right so if for example we matched this search term then we also want to include in the temp everything that comes behind it all the items right here until and that's the point we reach the star item because we're also matching that that's exactly what we want to show to the user right all the prior stuff that doesn't contain the star is just for searchability so we're going to start at rank so if you typed in afgh ha we would start right here and then as the maximum we're going to say oops as the maximum we're going to say rank plus a 100 this is kind of arbitrary I think a 100 is a fair um kind of assumption to make which means if we match this one so the user typed in af GHA then we include the next 100 elements and to also see which elements match from it containing the star so we can show those to the user technically yes you could go for 50 more you could go for 200 more which would increase the computational cost of this whole thing um I think 800 is a good idea and but of course you can change this if you notice that it doesn't work very well for your app but this is a pretty good default that mostly works for a lot of use cases now we're going to enter a four Loop right here so for each let's say const L for element of temp we're going to execute some logic there we go so in this case in element is nothing more than one string match right here like aler like alery like Algeria each one of these is going to be one element of or temp because this will give us back a string array and we know that but typescript doesn't know that it thinks that this is an unknown array so to make this very clear to typescript what we're getting back is a string array of these members right here we can simply pass in a string array explicitly and tell typescript that hey what we're getting back is in fact a string array so it can infer that each element like this one or this one or this one are in fact a string and we can work with them a bit easier and the goal of this for Loop is to construct an array to push those elements that we want to show to the user so only the ones that contain a star that's what we want to filter by therefore if not the element dot starts with which is a string command we can use in JavaScript with the query so if the result doesn't start with the search query we're going to break in that case we just don't want to continue but in the case of if the element dot ends with a star which is the important thing we are looking for all that means is that this is in fact a search result that we want to show to the user that we want to send over the wire back to the front end therefore we're going to push it into the res the response we're going to say rest. push and we're going to push the element do substring and we're going to go from the index of zero so the very first letter to the element. length minus one so we're sending back the entire thing except the star at the very end because of course we don't want to show that to users right why would they want to see a star at the end of their search results doesn't make sense so just the word except the star we're sending back over the wire now one thing that I added in here is to count how long this actually takes to make the comparison so to show users how long did your search take this is of course fully optional but I think it is a nice addition so let's quickly Implement that and in doing so you're going to learn one very very cool JavaScript API which is the let's say cons start the performance um API we can say performance dot now this will give us back a number of when this um started executing so the exact point in time right here that we can measure and then at the very bottom when we're done with all the logic um right here we can also in a little comment kind of just space it out visually and then say const end is equal to performance. now as well so we have two points in time we have the start and the end well the other way around right so the start and the end of this entire operation how long it took and we can simply send back to the front end the duration which is nothing else than the end minus the start right because both of these are numbers we can simply subtract them and that's easy that's how long this took as it number and in milliseconds by the way this is going to be in milliseconds and as for the results we're going to send back to the front and that's simply going to be a res array now only containing a string or which is a string array of only the names um without the star and not with any element that we only want to use for searchability now as a kind of best practice what's a really good idea to um do before you deploy this to production is grabbing the entire logic inside the app.get and simply wrapping it inside of a TR catch block let's name this error just in case anything goes wrong paste the existing logic as is in the tri block we're not changing anything about it but if anything goes wrong right we're going to land in the catch block and can handle the error accordingly for example one thing I always do is console. Arrow the error so you're going to see this in your actual runtime logs in case anything goes wrong and secondly we can return a c. Json back to the front end for example with the results being an empty array and we can also send back a m message and this can be for example uh something went wrong period and then of course we also want to adjust the status of this so let's say for example 500 so the user will get a 500 error on the front end um if you want you could also check which error is coming back with which status code and handle it according to that but I think this is a very simple very good way to go about things um in this demo application perfect that's the logic done very nice let's see if this works let's give our front end a lot more space and I know this front end looks absolutely horrendous trust me we're going to fix it we're going to make it look good for now let's search for for example uh in D oh and we get a 500 error something went wrong okay so ideally it should show us a country like India right now but it doesn't why doesn't it do that cannot read properties of undefined reading starts with and a very likely reason of why this happens is the following we didn't create a EnV file at the very root of our project so what's happening here is that it's trying or API route is trying to create a redus instance with or environment variables but these are actually undefined because we've never defined them anywhere so let's create a Dov file where it can draw these values from and also go to up stash and then the details and under EnV oh it seems like this not longer exists anyways let's create it ourself then let's go into route. copy the up RR token and paste it into .v file that's going to be the name of this environment variable and then as the value let's copy the token from the up dashboard with or without quotes I don't think it really matters and let's paste it here and then the second thing we want to copy over from or route. TS is going to be the URL so let's copy that over as well and this is going to be equal to the URL you can see listed right here and hit save on that and while we are doing this we can already do one other important step and that's going to be important later for deployment to Cloud flare workers to make this publicly accessible to make it um really really fast and that's going to be also at the very root of our project creating a Wrangler dotl basically Wrangler is a tool made by Cloud flare that lets us super easily deploy to Cloud flare workers directly and then order for cloud flare to have access to these environment variables we need to Define them in or Wrangler dotl so this takes only a couple things first of the name let's call this fast API for example second thing this takes the compatibility underscore date and this is going to be 2024 0402 so the 2 of April 2024 and then two lines down we're going to pass in the vars the environment variable and this is nothing else than the exact same thing we have in ourv file just so cloudflare can access it once we are in the worker run time and I'm not sure if this is needed by the way but I'm going to separate the actual values with a space from the equal sign and then hit save that's how I did it in the demo again I'm not sure if it's really needed but I know it works like this so uh let's just do it and that's going to be important for later we don't need that right now we can close out of the EnV and the regular. TL and that's done now with this in place what should happen is that our search now works so when we enter a name like in D for India first off we get a 200 response which is very nice and let's see if we actually get India back and we don't okay interesting so we get back an empty results array but we do actually get the correct duration for this so let's see why this doesn't work let's give this a bit less space so something is apparently going wrong in our routts that's causing this whole thing to not um put the correct results in our array so I'm going to take a second to debug this and then I'm going to be right back oh and without even debugging I think I already know where the problem is and that is currently the query is actually case sensitive we're never converting it to uppercase right because if we look in our data browser everything we have in here is once that loes is uppercase right but the query currently is exactly how the user types it if it's lowercase it's lowercase and let's validate if that is the issue by simply typing this in in uppercase and that should work so let's go into our Network tab lets read out the page and type in i d and let's see if we get results now and we do India and Indonesia perfect very very nice so we are sure that this is the issue now so we can very easily fix it by pending the dot to uppercase right here to our query by the way with a question mark because if this doesn't exist then we also can't convert it to an uppercase um so this is some optional chaining right here to make sure and with that in place even if we type in D in lower case now we should get all the relevant um results in IND D in our Network Tab and we do perfect India Indonesia what about United do we get the United States United Arab Emirates United Kingdom of Great Britain and North that is a long long name dude and because we only included the first 100 after our rank that's probably why the US isn't included here so if you wanted to you could just you know bump this up 200 250 500 whatever just be aware that this will actually cause more compute in memory um on your Edge function but that's not a big deal either um especially at this scale like that's not a problem but perfect very very nice we know this works now and now our job is to well basically it's two things right first off making this look good this looks absolutely like dog water and secondly actually deploying this to the cloud to see that this is actually really fast and working in production okay A little cut there because for me it's the next day but I very vividly remember that we wanted to make this look like not absolute Dark Water right cuz this absolutely looks horrible and let's do that and we're going to start right here in the jsx where we're going to change the div that we return at the top level to a main now this main is going to get a class name and that's going to be of height screen oops screen and width screen and we're also going to apply a grainy texture in here now this is not something that Tailwind has out of the box this doesn't apply anything this is something we can Define ourself and that's going to make our entire Page look really nice with a kind of background texture and we're going to um put that right here in or global. css this grainy texture however all this grainy texture really is and that might be a bit small right here um it's basically just a b 64 encoded string right and we're not going to type that out ourself so I prepared you a copy paste list you can use to follow along with this video because there is absolutely no point in typing this out we don't want to do that so just grab the grainy texture from the copy paste list I Linked In the description and it's going to be the very top item in there just go ahead grab that and paste it in here and you can see the reason why we don't want to type this out right this doesn't make any sense and so we're just going to paste it here in our global. CSS and that's going to apply the grainy texture right here to this class name if we save that we can already see what happens there is our grainy texture very very nice and the input Still Remains right here now below the main let's put a div and this div is going to get a class name and let give this just a bit less space of um Flex a flex-all again gap of six an items Das Center a padding top of 32 a duration of 500 this is going to be important for the animation we're going to add to this this is the transition duration let's add an animate Dash in an animate then a fade in five and the last class name is going to be a slide in from bottom of 2.5 now these class names also don't exist out of the box in Tailwind that is why we're going to inst one package for this let's clear this and that's going to pnpm install at Tailwind CSS SL an oops animate and then hit enter that's going to and why did that not work did I misspell something oh this is not at Tailwind CSS slash animate but it is a tailin CSS Dash animate without the ad and then replace the slash with a hyphen and then hit enter that's what the package is called there we go and what that allows us to do once that is installed we can already navigate into our Tailwind doc config.txt we're going to get rid of this in a second we just want to make sure that the animation works and in order to do that we need to start back up or development server so let's quickly do that and then hopefully we should see once that has all loaded the example text kind of fade in smoothly from the bottom if we set everything up correctly and it does but it's um it's white it's super hard to see let's quickly give this a text zinc of 900 class to A P tag and put the text in there you don't need to follow along with this I'm I'm just doing this to show this to you so we can see it smoothly fades in from the bottom perfect that looks really really nice and we can continue knowing that our animation Works super smoothly okay so in here above the input and below the div or inside of the div we're going to create an H1 element with a class name of text- 5xl a tracking Das tight we're going to give this a font Das bold and that's already it and inside of this H1 we're going to say speed oops speed search but really this can be anything right it it doesn't really matter this is just for um kind of decorational purposes and this text appears to be white which looks super awkward and no contrast the out of the box and so we're going to go into our global. CSS and quickly get rid of some stuff we don't need which is this entire stuff I don't know why it put that there didn't do that in my demo project we don't need that let's get rid of it and uh hit save on that and then our text will be black so so we only have the kind of Tailwind initialization we have the utilities layer and then the granny texture that we put there great below our ag1 let's go ahead and put a ptag and this is going to get a class name of text zinc 600 a text of large a maximum width of pros and a text- center and inside of here we're going to say a high performance API built with hono oops hono not hobo next.js and Cloud oops Cloud flare period let's insert a br a bracket a break element in HTML and right behind that let's say type a query below and get your results in milliseconds period and again this is just for decorational purposes you can follow along with this if you want you don't have to um this is very much personal preference and then right below that let's create a diff right below this P tag and right above or input element let's create a div here and this div is going to get a class name of Maximum width of MD for medium and also a width of full there we go and inside of this div is where the entire magic will happen for the input element now we could do all of the input logic and displaying the search results and so on or s that is totally possible but it does take a lot of time and it doesn't make sense for this video If there are already really accessible nice components we can use for that and one of them is from a UI Library called Shad CN and it's called the command component inside of here it's basically a very little abstraction component that we can use to beautifully and accessibly display or search results out of the box that we're going to use in this video um so for example we can search in here and it's going to show us the relevant search results just like that it's really useful and we're going to make full use of it um in this video now to get set up with this UI Library it's super simple go into your CMD and type in npx Shad cn- UI at the latest and then in it and that's going to ask us a bunch of questions to set up this UI library that we're going to answer together right now once it loads for example the style that we would like to use let's go for New York let's go for zinc as the base color but again all of this also the style they really are just personal preference whatever you prefer I prefer this kind of setup um would you like to use CSS variables yes we definitely want those and that's going to set up our global. CSS uh for us and I hope it doesn't overwrite what we already have in there oh man it did it overrode okay it overwrote or grainy class well let's paste it back in I didn't know it would do that that sucks um let's quickly grab our grainy class and paste that back in uh just so we don't lose the kind of background texture uh we have in here just looks a bit better that way and after getting set up with our UI Library we can say npx Shad cn- UI at latest and we can add the command component and hit enter and that's basically going to create a new folder in or app right here under component slui with a new command um file in here that's going to set up everything for us install the packages we need for it and basically it builds on top of a package called CMD K so Shad CM the UI Library author didn't just all do this himself but this built on top of existing packages and with that in place let's get started on our page. TSX inside of the div that we just created so what are we going to do inside of here we're going to put the command component we have just installed and man these suggestions from vs code take up so much screen space it's ridiculous I really dislike that and that seems new to me that didn't happen before um anyways doesn't matter right now let's let's keep building this and let's make this beautiful sometimes I feel like it's just maybe a bit hard for you to see the code that I'm writing there's like really big overlays from BS code but whatever okay so the thing is we already have a state for the input right where we keep track of whatever the user types in into this input field and we are going to make use of that to keep this command as a controlled kind of input so this is going to happen inside of the command component inside of the command input that we also get from our component slui command both of them right here which is basically the codee that our UI Library put into our own project that's what I mean with the zero abstraction right and this command input can be self closing and this is going to get four kind of um props we're going to pass in here first off is going to be the value and this is going to be or input so what the user types in second thing is going to be the on value change this gives us back the string you don't have to follow along with this I just want to show you what this does so basically it gives us the string that the user typed into the um kind of command input and instead of doing something like this where we where we receive the string and then say set input to that string right to the user input there is a shorthand we can use for this which is basically just passing the set input that's automatically going to take whatever we get access to the Callback function and call or set input function with it so this is just a really nice short hand but it does the same thing as this right it just looks a lot cleaner third thing is going to be a placeholder and this is going to say search countries dot dot dot so it's clear to users what they can do in here and the last thing is going to be the class name that we're going to pass in here so this is going to be a placehold oops placeholder colon so that's how we can specifically address the um placeholder right here in CSS and we're going to say text zinc of 500 and let's it already entered to see what this looks like and did we start up our development server no we did not uh so let's quickly do that and we can close this down and once that loads perfect we can see uh let's move this into a side by side you can see the command input right here beautiful search countries this already looks absolutely great out of the box much better than the input we had before beautiful that's our Command input and now to actually list the search results that we get back from our API right how do we do that that's going to happen inside of the command list also from our custom component that we're going to put below the command input this is going to be responsible for two things first off displaying the empty state if we don't have search results in that case we're going to display an empty state right here how do we check if we have search results well we can say um in a dynamic kind of syntax right here the search results question mark. results. length if that is zero right triple equal to zero in that case we're going to render out some jsx and in the other casee we're going to render out n and the Beautiful Thing is the jsx that we're going to render out if we don't have search results is already done for us so this is going to be the command empty also from our Uh custom component and then here we can say no results found period so if we don't have any search results this is what we're going to show to the user it automatically looks good because it is pre-styled we can see that if we go into it kind of already has some pre-styling applied to it beautiful and now for displaying the actual search results and and it's going to happen very similarly right we're going to do a check right below the conditional check we just did and this is going to be search results dot results if we have those right if the array is truthy in that case we're going to render out some jsx and in the other case as always we are going to render out null now what is the jsx that we want to render out basically it is going to be a command Group which is also a component we get from our custom component and the heading of this is going to be results Great and with that heading in place let's actually display the search results right super important and we can do that by mapping over the search results that we get back from our back end which are nothing else than a string array if you remember so we can say search results question mark because once again this can be undefined right if we don't have the data yet at the very start of the rendering cycle this is going to be undefined and we're going to map over the results so map over the results right here and for each result that we get access to in the Callback function we can render out some jsx right away and the jsx that we are going to render out is going to be a command command item also from our custom UI um kind of component right and this is not going to be self-closing it is going to contain the result which if you remember the string array right so this is going to be a single string each result which is the actual country so like Germany or India or United States of America and whatever we're searching for that's what we're rendering out right here and this command item also gets um a couple properties for one that's the key because every time we map over something in react we need to pass the top level item a unique identifier a key and this is going to be the result the value of this is going to be also the result and lastly we can pass this an on select Handler and basically this is going to set the input as well and if you remember the short hand right here again all this means is basically we receive the event and it's the same syntax as then executing whatever function we pass into it by just um kind of forwarding the event to it this is just a really nice syntactic sugar um on top of that but it does the exact same thing so let's try this out man uh let's save the file let's reload the page and then hopefully we should see our search results so if we type something in then we should see or search results oh and of course we don't because we never actually assign the response we get back from the server well that makes sense so let's uh do that so let's say cons data so the actual data we get back from the back end and this is going to be in parenthesis await res. Json so we are converting the response we get back from the back end Jason and then we're going to type or we're going to cast this into a typescript type so we can say as so we're telling typescript what the type of the result will be and this is exactly what we send back from the back end so if we take a look at what we see in the or what we get back in the front end right it is essentially the data structure that we have right here it's a results a string array and it is also a duration as a number so we can tell our front end exactly that we can say results are going to be a string array and then also the dur oops duration we get back on the front end is going to be a number and the benefit of this is that we now get type safety on the front end and can for example set the search results to the data that we get back just like so because the data structure here and what we get back from the back end is of course right here you see that the exact same beautiful let's save that and see what happens so right now we should really see our search results so let's type this in oh perfect India Indonesia let's type in gerer unit United perfect very very nice we can type in just an A and and right now that you can see probably that these results are kind of grayed out and they're not clickable right which is really weird and the reason for this is that the cmtk package CM DK let me show you that actually received a update a breaking change very recently they upgraded to the 1.0 and in Shad CN well that didn't really work out it still uses the kind of old implementation and the breaking change happens right here in our Command and the difference is that we need to change some things in here let me see where those are so basically it also depends on when you're following along with this video right if you watch this video right after it comes out then probably you need to follow along right now if you watch this in a month or two then hey maybe this is already fixed right um but in my case this is not fixed yet so we need to change the data disabled right here for example where the pointer events are um none inside of the command item we need to change that to data minus disabled is equal to in these single quotes true right because if it's undefined this is also going to be falsy and we need to insert this check and basically here and then the same thing um down here for the opacity 50 and then hit save and that should get rid of the problem which was just um caused by these two lines right here so let's search for a perfect that works we can now click these and that's going to actually um select the country Germany let's type A we can navigate through with our arrow keys and then also select using the enter key very very nice um now we don't we don't need the other input right that just looks bad uh we replace it with the command which is accessible it looks much better so we can completely get rid of the old input and just use the command instead um very very nice uh we get an error here but if we reload the page that should be gone sometimes nextjs does that once you make a change and then reload it for the first time um oops didn't mean to do that but once you reload it for multiple times that is actually gone right and then we can search for any country in here very very nice one thing we didn't do yet is display how long the search took and I think that would be a cool addition actually to get a feel um of how fast this actually is so right below the check still inside of the command list but below the null right here is where we are going to do that let's insert another conditional check here and this is going to check the search results do results so if we have results then we're going to render out some jsx and as always in the other case and we're just going to render out null just nothing and the jsx that we are going to render out is going to be a react fragment because we're going to put two elements in here and we don't want to add any element to the Dom for that so that's why we use a react fragment first one is going to be a self closing div and this is going to get a class name of height PX for one pixel a width of full and a background znc of 200 and if you're wondering what this does all this is is like a visual separator between the search results and the actual you know time that we're going to display to the user and to actually show the user that duration and how many results we found let's insert a P tag with a class name of padding two a text of XS for extra small and let's also put a text zinc of 500 inside of here in the ptag let's say found and then we're going to insert the number of how many search results we have which is nothing else than the search results do results. length right that's how long the array of results is that's how many results we got and we're going to say results in and then we're going to insert the second Dynamic value which is going to be a search results dot duration. Toof fixed of uh zero and all the toix pix does is take the number we get back from the back end in milliseconds and limits it to the well basically uh this is kind of hard to say in English but if we have like this as the number from the back end right super long comma number then the tofix zero basically says well we limit it to zero um numbers after the comma right so we don't have a comma if this was two then for example this would be limited to the 0.12 as well but we just want the milliseconds um even more fine grains doesn't make sense and then we're going to say Ms for milliseconds because that's the unit that we measure this in beautiful let's try this out let's type A and we should be able to see found 14 results in 108 milliseconds American Samoa found one result in 29 milliseconds really really nice now um one very tiny detail that we can add if we want is going to be a lightning emoji and we can simp simply add that copy it from the web from Google somewhere and add it behind the speed search I just think it adds a little bit of color and just looks kind of nice but uh you don't have to do that this is just purely optional and now the important question is is how do we deploy this to Cloud flare workers cuz that's you know the actual fast thing that we want to make API requests to and the answer is that's actually super simple so cloudflare workers has a tool and that is called Wrangler and Wrangler let's go to this is a command line interface for all things Cloud flare workers basically it allows us to deploy to CF workers extremely easily and let's get an overview a lot of people are already using this cuz it's super simple and we already set up everything that we need with or kind of Wrangler do tml right here right so all we need to do is go into our command line and say pnpm install Wrangler minus D for a development dependency uh because we don't need this in production just for deploying this to CF workers that's going to install Wrangler and now we can simply go into our package.json and Define a script to deploy or application so how do we want to call this let's call this deploy this is going to be our deploy script so whenever we run yarn deploy that's going to run the Wrangler deployment to cloudflare workers and that deploy script is going to be Wrangler deploy well pretty intuitive right and we're going to pass this two arguments we're going to say D- Minify and we're also going to say d-name and then whatever name you want to give this uh for examp like I don't know maybe fast API or whatever you want to call this um in your account that's going to show up in your cloudflare dashboard and we also need to pass this the route of the file that we want to deploy and this is going to be Source slapp SL API SL and then the double angled brackets dot dot dot route uh closing angle brackets SL route .ts so basically going from our source folder into app API route route. TS this is the file that we want to pass in as a uh argument here into the package.json and let's run this let's try it out let's close all of this clear the screen and run yarn deploy and hit enter now if you've never worked with Cloud flare workers and we're going to fix the bug here in a second don't worry uh unexpected character expected string number date time bulling okay we probably need to wrap this in quotes we're going to do that in a second or actually no let's uh go ahead and fix that right now it's a very very simple fix we can simply grab or environment variables in the Wrangler do tml and wrap them inside of quotes right so that's what it's complaining about um these need to be wrapped in quotes and then let's try that again let's run yarn deploy that's going to run or rangler deploy Minify name fast apii and so on and that worked beautiful now for you if you've never worked with cloud flare before and chances are it's not going to be that easy but it's going to ask you to log in first basically you I think you get a link that you need to click on that's going to take you to the cloud flare dashboard and mine is on German here let's switch that to English that's going to take you to the cloud flare dashboard where you need to log in and then you're going to be logged in into your CLI as well and that then allows you to actually publish your script so if I were to log into cloudflare workers um right here it's workers cloudflare.com and we log in here together let's click the log in let's accept the cookies I'm going to log in here there we go I've logged in and this is um what the dashboard then looks like right so we can see I've tried out some things here next back and fast search and the fast API that we just deployed so under dash. cloudflare.com this is where your um cloudflare workers will then be listed once you deploy them and in here we get all the metrics and logs and request times and everything and that is kind of important to our Cloud flare worker and we also get the URL that we need to make request to so if we see the logs right here we can see we deployed or Cloud flare worker under the URL and my console is bugged it doesn't show us so let's try this again let's run yarn deploy that's going to just deploy everything again um and that's going to give us the URL so let's see this there we go publish fast API https uh and so on and so on and this is the API that we can now make requests to so let's try this out let's enter this um URL that cloudflare gave us for the deployment into our browser and then under SL API SL search and then question mark Q is equal to uh for example G for Germany um we can type that in and we get an error something went wrong Aha and the problem is and I just saw the problem here um in Cloud flare if we take a look at the logs right we can see everything that goes wrong and that goes right and the arrow message that we get in the worker is that reference error process is not defined and the problem here is that or redus tries to use these values by default from our EnV file from process so it assumes a node.js runtime right but this is not a nodejs runtime this doesn't work so all we need to do to fix this is say SL cloudflare at the very end right here so upst R is knows that we are trying to run this in the worker D run time then we can save that hit yarn deploy once again and hopefully that will fix all the issues with our API Rod I mean the variables are there after all those are correctly set up in our Wrangler DOL so we should be able to deploy this and there we are perfect we can see results Germany let me zoom in here and the duration it took for this search beautiful 44 milliseconds for Germany hey dude this is super cool okay perfect and the last thing we can do right now is if you wanted to deploy this entire project to versel for example is instead of making a request to this URL we can simply prefix that with the URL that cloud flare gave us for example this one right so we can paste that in and now we're getting all our data from our actual backend hosted around the entire Globe by cloud there so let's quickly try out if that works let's start back up our development server and save or changes with the remote URL that we're now making request to let's navigate to Local Host 3000 and ideally everything should work just as fine as making request to our local endpoint right because essentially same thing right because it's just all routts that now runs um remotely distributed around the entire um world right so that's what I showed you in the diagram that's going to be where was it right here the CF these are automatically running in all regions of the world so let's type in gerer that's going to make a request to our remote endpoint and it seems like that doesn't work and I and dude I already know why and that's again super super simple fix um and that's going to be that this is a course error and we can probably see that if we go into a network tab uh let's let's make this again let's go to all J M and we can see yeah Status course error very simple fix this is exactly the same thing with if you've ever worked with any kind of backend framework right we need to use a course middleware and all we need to do to fix this is say app.use and use the middleware that hono provides to us so for any route so for slst Star any route in our entire app we're going to make use of the course middleware from honos course and invoke that and then simply go ahead and redeploy um or backend to Cloud flare right to make use of that um course middleware to allow requests from anywhere basically including Local Host 3000 once that's done we can restart our development server and now this should work now this should really work as so we should get data from our remote environment from cloud flare so let's try this out let's reload this all right there we are let's type in ger Germany beautiful 63 milliseconds let's type in United 45 milliseconds dude today red is is today red is is like really F this is much faster than wow okay interesting uh let's type in I don't know aeran 43 Mill dude this is seriously fast wow but this is also oh okay yeah this is Local Host probably that's why cuz the main database region is in Frankfurt I guess beautiful and you could even go as far as deploying this as is to versel um even use the versel API if you wanted to right because we export at the very bottom both the app HTTP verb and the actual app as the default this is compatible with both Cloud flare workers and versel out of the box um so for example you could use the front end and deploy it to versel and and get all your backend data from the cloud flare worker which I did in the demo which is the fastest way and but you can always change your mind if you want to so dude beautiful job I really hope you enjoyed this project it was a ton of fun to build I really like this we got animations in here this was just a ton of fun to build um it's fully accessible it's super damn fast and it's not just for search functionality right if you want any kind of speed in your API for search or for whatever you can imagine right this is the infrastructure to do it um or well should I say this is the infrastructure to do it it works um just super nicely out of the box and I'm really happy with it okay I hope you enjoyed this video I really hope you do thanks a lot for following along I hope you learned a lot that you can use in your future projects and then let me do the outro in person hey I really hope you enjoyed this was a ton of fun to make as you can probably tell from the video I I had a lot of fun doing it and it's just super useful knowing how to build a high performance highspeed API that is globally distributed it's just it's just a really cool thing to know because it's useful for a lot of cases like for example the search functionality or I've had use cases at work or in personal projects in the past where knowing this would have been really useful but I didn't and now you do and now I do and it's just a really cool technique so I really hope you enjoyed following along that's going to be it for me for for this video and I'm going to see you in the next one until then have a good one and bye-bye
Info
Channel: Josh tried upstash
Views: 16,528
Rating: undefined out of 5
Keywords: web development, project, tutorial, fast api, performance, nextjs, next, next.js, react, typescript, nextjs api, hono, honojs, cloudflare, cloudflare workers, redis, upstash redis, software development, josh tried upstash, josh tried coding
Id: 2Y3A4deNs9A
Channel Id: undefined
Length: 90min 0sec (5400 seconds)
Published: Sat Apr 06 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.