May 3rd, 2023 × #svelte#webdev#planetscale#prisma#performance
The Syntax Giveaway Site - Codes, Bots, Tech Stack and More!
Scott and Wes discuss building the Syntax merch giveaway site using SvelteKit, Prisma, and PlanetScale, handling heavy traffic, security considerations, and why it was an enjoyable developer experience.
- How codes distributed fairly
- Admin features added quickly
- Couldn't lose data
- Unique coupon codes important
- Needed to prevent code conflicts
- Considered existing services initially
- Success page captured hosts' tone
- Chose new stack to try out
- First time using PlanetScale
- Ported utilities from other projects
- Prisma recommended for stack
- Hadn't used Prisma in years
- New favorite stack
- Everything worked smoothly
- Schema design considerations
- Middleware for auth, database, errors
- High serverless usage on Vercel
- Site got heavy traffic
- Effortless SvelteKit deployment
- Avoided deployment issues
- Quick domain setup
- Database schema design
- Basic auth implementation
- Server hooks for auth
- Helpful middlewares
- Prisma middleware
- Client-server communication
- PlanetScale connection pooling
- PlanetScale eased scaling
- Many concurrent instances
- Simple codebase
- Unique coupon code generation
- Code format considerations
- Code status management
- Code distribution tracking
- Unpredictable IDs
- Address form improvements
- International order requirements
- Schema flexibility
- Type safety
- Quick ramp up
- Redirect handling
- Built-in type safety
- Global state management
- Form submission handling
- Progressive enhancement
- Reusable form logic
- Files kept in sync
- Database getting hammered
- Blocking invalid requests
- Small database usage
- Not actually a heavy load
- Code permutation limits
- Checking codes against list
- Funny error messages
- Possible improvements
- Cheap database pricing
- Minimal database usage
- Database sharding
- Handled unexpected load
- Quick live updates
- Botnets used
- Security improvements
- Reliability observations
- Reasons for delayed open source
- Minimal costs
- No server costs
- Free services used
- Framework productivity
Transcript
Announcer
You're listening to Syntax, the podcast with the tastiest web development treats out there. Strap yourself in and get ready. Here is Scott Silinski and Wes Boss.
Wes Bos
Welcome to Syntax, the podcast with the tastiest web development treats out Today we are going to be talking about the Syntax Swag giveaway site.
Wes Bos
So if you didn't hear Syntax joined Sentry. And as part of our celebration, we gave away 600 T shirts, 50 skate decks, 50 yetis, and that's it. Actually, I think we're gonna stuff some stickers in there as well. And it was it was kind of fun because we're We say, okay, 600 is a lot of T shirts, but there is many, many more than that that listen to this podcast. So we needed a way to first of all, like, how do we give it away to people who have been, like, long time supporters of the podcast? Like, how do we make sure they get something, at least enough of them. And then second, like, how do we make sure that it's not just like 1st come, 1st serve? So we landed on this idea of having codes. Right? Yeah.
How codes distributed fairly
Scott Tolinski
Yeah. Well, because it it was there's a lot of really unique challenges To to put in front of us here. And and we're typically when we first looked at this project, I think the biggest challenge for us was, like, how are we gonna distribute all this stuff? Are we gonna have to ship it to Wes's house? This is like when we learned that, like, oh, now being a part of a a bigger organization like, now those problems become less big Problem because we have access to distribution centers and different types of things that we we didn't have access to before. So now the challenge gets Put into the hands of, like, well, how do we make sure that this site ends up being interesting or fun or or a joy to use and actually works? And we have to be kind of ready and prepared for people to be hammering it.
Scott Tolinski
You know, initially, at first, I think when we very first started this project, I was a bit, naive on some of the aspects of things that it needed to have, and we'll talk a little bit about some of some of those things only because, like, Yeah. You can envision people people, you know, wanting the codes and whatever. But, you know, I think the amount of support and just how many people were hitting hitting the site, You know, so frequently and so many people were looking for the codes. I don't know if I was mentally prepared for that when we first, discussed this problem. But as it got closer to launch day, I sort of be like, oh, no. Wait. This It's actually, much bigger of a, a responsibility being placed on the site than I'd initially thought of.
Admin features added quickly
Scott Tolinski
So definitely, you know, the things that needed to happen, 1, we couldn't lose our data.
Unique coupon codes important
Scott Tolinski
Right? The data becomes important. If somebody submits this thing, Then all of a sudden, the the coupon codes have all gotten corrupted or or something becomes a problem, orders get deleted. Like, that that sounds like a a great way to ruin your entire life By having to piece together who actually had an order and what their order is from and all that stuff. So it had to be when we had to have a database, obviously, because You need a database that's going to store all that stuff. You also need unique coupon codes. We need, 600 unique coupon codes for that matter, to have each one of those coupon codes be something that is tied directly to, individual products, so to say, because you could think about this as being products.
Needed to prevent code conflicts
Scott Tolinski
Now it's really easy when you only have 2 bundles. It just becomes a bullion. Right? So in the database, that is a value of just premium. Is it premium? True or false? Right? So this entire site, it it started off kind of like, oh, we'll just build a little thing for people to, could could it be a Google form? I don't know. Could it be a Google Form and then like
Considered existing services initially
Wes Bos
Well, it start off being like, there's gotta be something like this that exists already. And I'm sure there is that you could pay for, but
Scott Tolinski
Yeah. Maybe bundle this thing up and have people buy this as a service now. It worked so well for us. So I had I had the problem when I did I sold my t shirts. I was using
Wes Bos
Snipkart.
Wes Bos
Mhmm. And you could say I I I had, like, a limited number of mediums. I said there's 15 mediums. But, like, if 2 people checked out At a medium at the exact same time or close enough.
Wes Bos
It didn't decrement it properly. And I was in a spot where.
Wes Bos
Like, I could possibly sell more than than there there was. Yeah. People have allocated things they cannot get. Exactly. And it's just like, I don't want that Nightmare to to have to do it. So, like, how do we how do we figure out where
Scott Tolinski
we lock it, you know? Yeah. So let's talk a little bit about, I think, the the way we should talk about this is, like, the challenge that we had. Right? We knew that Yeah. We knew at some point this thing was gonna get hit. We knew we had to have Although this functionality in here but we had, what, less than a week to put this together. And even, like, if you wanna count up the total amount of hours that I put in on this thing, I would say I put in, like, 3 hard days of work on this thing, which is pretty shocking that it was an end result. And and West swooped in in the last 48 hour. Not that you swooped in only in the last 48 hours, but you swooped in in the last 48 hours to make it look and have, like, all the charm that it has. Because Yeah. I'll I'll share a screenshot of something what it looked like on Twitter beforehand, but I was just, like, base a t a HTML and then, like, a really ugly gray color. Times New Roman until about 12 hours before launch. Totally. So I was, like, really focused on getting it functionally working and getting some of these admin tools in in West. Wes knocked it out of the park. And you know what? What? I gotta say, man.
Success page captured hosts' tone
Scott Tolinski
When you get to the the the success screen, it says, yeah, buddy. Like, I couldn't have I couldn't have written that better myself. Like, I say, yeah, buddy, all the time. How did you you don't you don't know that. You don't know that I say that. It's just something that we say. It's just some it's it's wild that, I I think you were able to, like, craft something that fit us both so well. It's just a testament, I think, to the overall character of this podcast. But so let's talk about the stack. Why pick the stack I picked? Because I I kinda Picked it because it was something I wanted to try is really what it comes down to.
Scott Tolinski
I wanted to try PlanetScale.
Chose new stack to try out
Scott Tolinski
I'd never tried PlanetScale.
Scott Tolinski
It's just a database. I mean, there it's not like there's an API in front of PlanScale that I really needed to dive in and learn. It's just like, hey. Here's the thing I've never used. Might as well give me an opportunity to try to use it. I knew I wanted to use SvelteKit for this because I I just really prefer working in SvelteKit at this point.
Ported utilities from other projects
Scott Tolinski
Svelte makes a lot of things a joy, but I also have a a fair amount of utilities and little tools that I use on the level up site that I was able to port over or drop in and Stuff to make it a little bit you know, save some time because I've already worked on some of these tools and know them really well.
Scott Tolinski
Prisma comes into play because, basically, when I started researching SvelteKit and PlanetScale, just about everything that came up was to say to use Prisma.
Prisma recommended for stack
Scott Tolinski
And now I haven't touched Prisma since it was, like, GraphQL, the cool days. I mean, that's not even Prisma. That's not the same product at all. So, like, I haven't really worked in Prisma in a very long time. Even
Hadn't used Prisma in years
Wes Bos
Prisma is not the same as Prisma. What is it? Prisma 3 is not the same as it's
Scott Tolinski
Not a GraphQL thing at all, anymore. And and we we've talked about that on this show. We we even talked to the Prisma folks. And and and for me personally, it was like, well, I have A limited amount of time to make something that a ton of people are gonna be using, and it needs to function at peak performance at all times. I might as well pick 2 things that I've never used before.
Scott Tolinski
But, you know, what I gotta say Is this has got to be my new favorite stack here. Oh, man.
New favorite stack
Scott Tolinski
Holy cow.
Everything worked smoothly
Wes Bos
The speed at which you are able to Set this up and crank on it and then just deploy it at scale to incorporate some of the traffic and iterate. Yeah. Aussie, like, Chef's Kiss. How amazing
Scott Tolinski
this whole stack was. I'm very impressed with I have very much enjoyed working on it too. Yeah. It really came together. And, I mean, they were what was so cool is that there were various points Over the course of, like, the 3 days in which we're giving out coupon codes, which, by the way, for anybody listening, you didn't get a code. I'm very sorry. Those 3 days were a blur for both of us. Yeah. I've never ever experienced anything like we're we're we're co co co co co co. I'm I'm, like, handing it out as fast as I can. I I I I feel like I'm, like, tossing paper towels or whatever. I I I could not I could not do it any faster and and still is shocking to me to wake up on Monday, and people are like, oh, man. I couldn't get a code. And I feel so bad about that because we really tried, to get them to everyone. It was an absolute blur. But in the midst of all that blur, We were able to push several updates to the site out that affected absolutely nothing user facing, beyond maybe improving, error messages here and there or little things like that. But, like, the admin tools, we were we we'd be, like, distributing codes and be like, oh, we Could really use this admin feature. Build it in. Alright. It's in. And and West West was there would there would be times that I'd I'd be checking the The repo and West had pushed, like, 8 updates, and I was like, how could how could you push 8 updates? It's been, like, 2 minutes. How did you do this? So we were both pushing straight to mass Or to Maine, I guess. Yeah. We were both cranking on it just in cowboy and straight up to Maine, and it just it was a joy. It was just a joy all every step of the way. So The the Stack, SvelteKit, Prisma, PlanetScale, some other dependencies and other things we used inside this. Of course, we used Sentry for our error and exception handling, which came in really handy in a lot of ways. We were able to see people who were abusing the site in various ways or people who are trying to abuse the site. Yeah. It it led to some, like, really interesting revelations about how people were using it, but Sentry was a a nice tool to have involved there.
Middleware for auth, database, errors
Scott Tolinski
We used Google Places to grab the when you start typing into an input box to autofill your address, That's just Google Places with the Google Places API key. We also hosted it on Vercel, so the whole thing was entirely serverless. Thank goodness,
Wes Bos
Because I'm just looking at the logs not the logs, sorry, the usage on Vercel.
Wes Bos
And we did last month, we did 2,800,000 serverless invocations, probably about, I bet probably 1,600,000 of those were just from the swag site.
Site got heavy traffic
Wes Bos
Getting hammered. Which getting hammered. And that's That is both people loading the the page, as well as people submitting The codes to it.
Wes Bos
But it was quite a bit, especially because people were trying to brute force it. But All of that was well within.
Wes Bos
We have a free plan from Vercel, and I know people Whine about pricing, myself included, on Vercel sometimes. But all of that, including the syntax. Fm website, Would have well fit in a $20 a month plan.
Wes Bos
So running the syntax.fm website, running the syntax API Endpoint, which is our biggest bandwidth use as people hit that like crazy.
Wes Bos
And this entire giveaway website Was under a $20 plan, so I was pretty impressed with Vercel on that. And it did not sweat a bullet The entire time even as we were getting hammered, hammered, hammered with traffic. Yeah. Totally. Very impressed with all of that. Also impressed with,
Effortless SvelteKit deployment
Scott Tolinski
SvelteKit and and Svelte deployment. You know, in the past, I've always just done a deployment of node and deployed a site, but I just use the baked ins adapter auto that works Out of the box so if you were to, like, download a SvelteKit site from the start and just push it up to Vercel, man, it would just work. We didn't Do anything to to get this working with Vercel specifically or even to get it building for Deploy.
Scott Tolinski
The adapter auto that comes with SvelteKit just did all the work itself, so that was really nice and easy. It's not have to even think about, deploying it because, you know, the last thing you wanna do is Spend a few hours fixing deployment issues.
Scott Tolinski
Wet West took care of all of the, domain specific stuff. I I I naively was like, oh, we could just have this on a generic domain. Right? And you're like, no. Come on. Just because I didn't I I don't wanna deal, like, with DNS stuff Ever. It's like such a nightmare to me sometimes. So, you took care of that in, like, no time at all, which was really great for me. So, you know, sometimes your your Hyperactivity, maybe you could call it, is like an extreme superpower where, like, you just do, like, a 1000000000 things before it can even Maybe I don't want to do that. You're like, I already did it. I already did it. It's done. Yeah. Yeah.
Avoided deployment issues
Wes Bos
The only issue we had there was We have as part of the century deal, we have to give them the domain name.
Quick domain setup
Wes Bos
And and I was like, I know that we signed some stuff, but can I can we just keep the domain name for, like, another week just in case? So we figure this out. Yeah. Oh, yeah. No problem. So, now that it's over, we'll Start to transfer the actual domain to them, but I'm very glad that I had access to all of that type of stuff. Yeah, totally.
Scott Tolinski
So what kind of, like, features does this thing do? Because you might be wondering like, hey. What does this actually do beyond just accepting the coupon code? And we can talk a little bit about, like, the database Schema as well because I think that's important.
Scott Tolinski
But the basic features is that we needed an an admin section so that we could see all of the coupon codes. We could know if they were premium. We could know if they've been used, locked, or, are available. We would need to know if they've been distributed somewhere. We'll talk a little bit all about this and more. But for the auth side, somewhere. We'll talk a little bit all about this and more. But for the auth side of things, you might be thinking, well, do you build it a whole auth system? No. We used web basic auth, Which, you know what? I've used this before in some context, but I've never considered it at all, because it's not the type of thing you use in a production app for real users, but it's the perfect type of thing for this type of scenario where You wanna have a section of your site that's admin protected or just a user password protected? And web basic basic,
Basic auth implementation
Wes Bos
What is it? What is it called? It's just all basic. It's got the dumbest thing to Google. And, yeah, like if you have ever had a database connection String or something like that where you see user colon password at whatever.com.
Wes Bos
That's basic auth.
Wes Bos
It's basically basically username and password are part of the URL, or if you visit a URL that is Is behind basic auth. It will prompt you for that. And then on on your side, you simply just say if The username they gave me header and the password header they gave me is what I'm expecting them like. We didn't have any auth. We just basically had a string That Scott and I knew. And there's an if statement in the codebase that checks if we put it in environmental variable, which is good, but That's it, right? There's there's no and the browser takes care of keeping you signed in and the browser takes care of prompting you for the username and password. And
Scott Tolinski
It's it's great if you just need quick off. It's it was it was like a joy to work in and you know what? We did this through a Svelte, server side hook. So hooks dot server dotts inside of SvelteKit. And these are basically a server side specific middleware.
Scott Tolinski
And we use a number of different middlewares on the site, which I can talk about.
Scott Tolinski
But this one in particular was really, really quite simple, and I got most of the code from this From, if anybody's in the Svelte community, you know, Ghost or Willow, she she's like a a member of the Svelte community. I found one of her repos, which was SvelteKit basic auth, And she had already written the hookup pretty much. I I need to tweak it for our use case, but she had written the hookup to give me the general idea of what the approach should be. And, really, what you're doing is you're just intercepting the request.
Server hooks for auth
Scott Tolinski
You're checking the headers, and then you're able to resolve whether or not the, authentication piece is is correct and then pass along essentially, the response if everything is is accurate. And it was really nice and simple. I'll post a link to, Her version of it at least. And once we're open sourcing ours, you can see ours as well.
Scott Tolinski
And, hopefully, maybe we can get this open source by the time this This, podcast goes live, so we'll update the show notes in that in that case. But, you know, it was really super easy to toss these these middlewares in here. And other Other middlewares that we used is the SvelteKit form data one that I I mentioned.
Helpful middlewares
Scott Tolinski
I wrote my own quick little Prisma mini middleware to essentially connect to Prisma And then pass along the Prisma client through the locals inside of SvelteKit. If you haven't used Falcon a little while, it used to be called stuff, but they kinda changed it to locals inside of all the events. So this means that you're connecting essentially once, which actually is something that when I hacked together, I accidentally put the Prisma client creation in on each request, and luckily, West found that.
Prisma middleware
Scott Tolinski
But, Basically, you're connecting to the Prisma client once and passing it along into locals, and then you're then able to do locals.prisma To access the database, anytime you want to access the database. This is how I've always done it Yeah. With our MongoDB setup as well on SvelteKit.
Client-server communication
Scott Tolinski
And then lastly, we also have the, we also have, like, handle error one where we are able to log our Sentry Logs for server side logs as well as we also have a client side middleware hook for capturing client side issues as well through century. Yeah. The
Wes Bos
The Prisma client on every request was a good example of serverless Kind of being long running, meaning that on a typical server, you would instantiate the Prisma client when the server boots up right on Start. Js and then You export it from a file and you reference that every single time.
Wes Bos
But with serverless, it's possible that we are running Prisma clients Eighteen different times all at the same time because we were scaling up. Right? But serverless functions are reused. So what we did is is Just in the scope of your module, you create a Prisma client, and then you reference that for as long as you want. Every time that serverless function is is used, it's warm.
Wes Bos
It uses it. And then if multiple instances of it are scaled up, then it can. And thankfully, we use PlanetScale because You talk about connecting to the database.
PlanetScale connection pooling
Wes Bos
PlanetScale does this thing called pooling connections, which is great because I wish first out would show you how many instances of your serverless function were running At once.
Many concurrent instances
Wes Bos
It tells you how many like how many compute hours you've used. But like, I'm assuming at certain points there was many, many instances of this spun up.
Wes Bos
And generally with a database, you can't connect to a database that many times. But PlanetScale does pooling built right into their service, Which is really nice, and it handled,
Scott Tolinski
many clients being able to connect to it at once. Yeah. Which is just overall a joy. And, like, so many of these things, they sound like they're intense. But at the end of the day, like, let's talk about you know, I'll talk about, like, the database here in a second, but this entire little Site is probably, like, 20 lines or 20 files of code. I mean, it's, like, hardly anything. Right? You have a handful of Svelte components, Maybe, like, 10 Svelte components, maybe, like, 10 server side files to handle working with the data, and then you have a schema. And that's pretty much it. It's Wildly simple.
Simple codebase
Scott Tolinski
And so the schema, you know, we have this database, and the schema is really 2 things. We have The coupon codes which have the email that's attached to when it was created whether or not it's a premium code whether or not, or what the code is, The status and the status can be either it's an so that status can either be active, locked, or used. And then you have, The order it's tied to once it becomes an order, but that's our relation, and then what it's been distributed to. So those Through the big things for us is that we wanted to be able to, 1, have all of the codes be unique so the codes are unique.
Unique coupon code generation
Scott Tolinski
I created all of the codes using a very simple website. We could have done this with code, but it like, honestly, it took me 2 seconds to go to voucherify.ioforward/generator and say, hey. Give me 600 unique codes that are 5 digits And included, you know, here's the patterns. Here are the characters to exclude. I excluded zeros from the code. I made them all capitalized.
Code format considerations
Scott Tolinski
I said, hey. Give me a through z. Capitalize it. Capitalize only. No zeros. 1 through 9.
Scott Tolinski
And it just spat out a huge list of them. I took that list. I put it into a TXT file. I read it into the server, and then I I I just looped over it and stored them into the database. So I was able to say, hey. That code needs to be unique. The status needs to be an of one of those things. The premium is just a bullion. In distributed, I let it be an open string.
Scott Tolinski
The The reason behind this is this is a feature that we added late, like, late in the game, like, day before it launched. It was like, oh, wait. When we're giving these things out, we need to know if we've handed this code out or not. Otherwise, Wes and I might be handing the same code out to 2 different people or, you know, if you're You're posting 10 codes. You could have posted those same 10 codes elsewhere. So we just said if it's an empty string, then it has not been distributed.
Code status management
Scott Tolinski
Otherwise, you can just kind of blanket put in it any string you want there.
Scott Tolinski
And that way, we, you know, we could have light metrics about where all of these things ended up going if we wanted to see that later. But most importantly, you could say, hey. Give me all of the ones that have not been given out. Mhmm. Give me all of The standard and premium were just the standard codes. Give me just the standard codes, and, give me 10 of them. And it just would spit it out into a a list. And sometimes you you may have seen some of the screenshots of this little admin section that we had for this thing, but, that ended up working out really well.
Code distribution tracking
Scott Tolinski
And that was pretty much it for the the code side of things. So what happens is you get a code. I put in your code with an email. If that code, it goes to the database. It checks to see if that code has been set to be locked or used. As long as the code is set to be active and your email is unique, then it then it saves your email to that code, And it spits back the ID of that code, the database ID. That database ID is then used in the URL to then allow you to complete your order. So then we can use that database ID, which is not something that anyone is ever gonna be able to guess. It's a giant long string ID.
Unpredictable IDs
Scott Tolinski
And keep in mind, we. So in Prisma, you have the option to set an ID field in the schema. And and we said this was an ID. It had a default value of UUID, Which is what generates a unique ID. Sometimes they can be an auto increment is also a way that you see a lot.
Scott Tolinski
Auto incrementing would have been a disaster. People could have been like, I want coupon number Thunderhead. Yeah. So it was important that those things were unique strings that were different or unguessable, so to say. So, you get that ID. That ID loads up the the Code, and then it gives you access to the address field, which, again, West dominated this address field. I had, like, a a a working version of it, but West has a lot more experience Shipping things. So we really tuned up that address field last minute and made it, like, way better. I I had an auto completing with the places API, but there was, Like, a number of little things that you took care of, like making the countries a drop down list. I was like, I don't want to do that, but you were like, no, we need to do that. Yeah. You need to do that because,
Address form improvements
Wes Bos
Like, I've gone through shipping 180,000
Scott Tolinski
stickers and T shirts and shipping.
Wes Bos
I've Felt all the pain that is especially like when you get into, like, India. A lot of the Indian addresses are just Like past the red house or like the instructions on the address line 2 are very long and often just very descriptive as to Which house it actually is.
Wes Bos
So you need to make sure you have space for that. And then also, like, you have to collect phone numbers for international orders.
Wes Bos
There's lots of, like, weird things like that. You can't use accented characters in addresses. We haven't dealt with that just yet, but I have scripts That can convert it. Should should we need to go down that route? Yeah. Totally.
International order requirements
Scott Tolinski
So that that was all really super interesting. I thought, you know, of the last minute changes is that it's like we made the phone number required. But, oh, wait. Phone numbers aren't required for everybody. So it was, like, functioning the right way on the UI, but we had to tweak it in the database at the last 2nd. Now the cool thing about working on Prisma here is that we essentially have for the entire database, for this entire application, like, pretty much the entirety of it, like, getting everything organized is, like, 43 lines in a schema file, and that schema file basically points directly to an ENV variable.
Scott Tolinski
So you just say, here's the d here's the EMV variable.
Scott Tolinski
Here's the the type of database it is. It's a MySQL database. Relation mode is Prisma.
Scott Tolinski
The provider is Prisma client. And then from there, it's like you just create your models. You create, your Enum, whatever you need here, and then you just run the deploy Or the migration command from the command line and bingo bingo keeps everything up to date. And and the CLI really lets you know if you've made any mistakes or, like, for instance, If all of a sudden you've added a field and there's no default value to it, it's gonna ask you to reset your database or provide a default value. It's looking out for you in so many ways that, you know, I I've worked in Mongo and Mongoose for a long time, and I really loved the freedom that I had working in those systems. And now I realized that was Just me being, not educated enough about this stuff because, really, what it comes down to is that I like it when the database laps my hand away and says, hey. You, you're doing something that you shouldn't be doing. You you you want predictability here when it comes to this data. And so for me, it was, like, a really great experience to work with these tools. My experience in in my my SQL in general has been, doing it by hand. So getting to do this with Prisma has been, like, a really lovely experience. And, honestly, like I said, this is this is might very well may become my go to stack Yeah. From now on because it was such a joy to work in. I was surprised at How easy I could just jump in. So I've never
Schema flexibility
Wes Bos
built a SvelteKit app.
Type safety
Wes Bos
I know enough Svelte To get by, but not SvelteKit.
Wes Bos
I've never used the new Prisma. I've used all the other versions of it, But I was able to just jump right in there and build all of the parts, all the server side stuff, all the client side stuff, all the database specific queries.
Wes Bos
And I think that is a testament to just understanding JavaScript and being able to Jump in. Whatever the framework is, it all made sense to me, and I was able to be productive in 5, 10 minutes of of with it from cloning the git repo. Yeah. And talk let's let's talk about that because, like,
Quick ramp up
Scott Tolinski
you know, as we were going live, it was, like, 30 minutes before the live show, and we're like, oh, no. Wait. We need to release all of these coupon codes that have been locked because some people were to run things that were locking coupon codes and then they wouldn't complete them.
Scott Tolinski
And so the we had, like, 40 50 coupon codes that were, like, locked, but we wanted to release those locked to become active again before the live show started.
Scott Tolinski
So, like, 30 minutes before the live show started, I wrote a database query and pushed to production and ran that database query without testing it. Why? Because we didn't have a test database. We had only the production database. Yeah. And, like, I just flat out did not have enough time to do it any other way. So, that's not how I would typically do things, and that's not how I wanted to do it live on the show. Actually, that's really what I wanted. I wanna hit go. West Wes talked me out of it, which is great.
Scott Tolinski
Was not a good idea. It worked first try, though. Yeah. It did. It would have worked, but it's also a testament to say, like, hey. This stuff is easy to work in, and especially because I've, had so much experience working in databases in Svelte connections and whatever. I get the flow But, man, I I think about all the neat little tools that I wrote for myself and just thinking how much I would not have to do any of that using the same stack Right now, this just all felt a little bit better, and everything was type safe down to except for, like, the, form data coming in from actions. I need to figure out types for that still. But, like, So much everything else was was type safe out of the box.
Redirect handling
Scott Tolinski
Anytime I was doing the a Prisma query or or or mutation inside of Prisma, It would, save my bacon in all kinds of ways to say, you know, this type isn't correct or perhaps,
Built-in type safety
Wes Bos
you know, the little red squigglies were leading me every step of the way. So, yeah, even the environmental variables being Typed was just like chef kiss for me. So I was slapping Century in there the night before And I put the century DSN in the environmental variable. And right away it starts auto completing when I'm processed Env. Oh, this is so nice where literally every method and property is fully Typed in the application. And I don't have to, like,
Scott Tolinski
make it ripple through the entire application. It's just everywhere that you needed it. Yeah. Let's talk let's talk a little bit about that, like, client to server side connection. So since this is using SvelteKit, we were using Svelte form actions, Which Svelte could form actions are basically a way to use real form APIs that sends a post request. And what you do is you drop in what's called a, an action in Svelte, Which is use colon whatever. And it's essentially just a way to get life cycle methods on a dom node. And the way this works for SvelteKit forms is you just drop in a use enhance on the form, and what it does is it submits your post request to to the correct endpoint, without you really having to worry too much about that, it handles all the progressive enhancement for you, which is why it's called enhanced. Right? So it submits the form without doing a full page refresh.
Global state management
Scott Tolinski
Now one of the things I built for level up tutorials was a generator function Called form action.
Form submission handling
Scott Tolinski
And what this generator function does is it basically runs all the types of callback stuff you would want from A progressively enhanced form. So what my form action does is at first, when that form is first starting to be submitted before the request goes out, It puts the application in a loading state. I have a global loading state, and it's just loading, set, loading, true.
Scott Tolinski
And then it does the request.
Scott Tolinski
When that request comes back, I'm checking the page status. So, one of the things that we had is that, unsuccessful coupon checks, it was doing a redirect. And, initially, I was checking for a status of 200, but it was coming up red, but successful saying you failed because I was Checking for status 200, so I needed to check to make sure if the status was also a redirect status as well. So if it was a redirect or a SaaS 200, The Toast is gonna do a toast dot success plus whatever message we've passed in here. If it's an error, it's gonna do a red Toast message. Then after that, it's going to invalidate the data. It's going to apply any of the, action stuff, which is apply actions, a function that basically runs The normal, use enhanced stuff inside of Salt because, basically, when you get into stepping into the, progressively enhanced form system.
Progressive enhancement
Scott Tolinski
You you kinda gotta hold its hand a little bit more to say, hey. Do the action stuff that you were gonna do anyways from this, And then set data loading to false.
Scott Tolinski
And then there's also an option for a callback if, we didn't use any of that inside of here. But if you Wanted to call back to run to maybe do, like, a redirect or something after here that's not like a server side initiated redirect. Mhmm. You could do it from that. But it was so nice to have that because it's something, like, again, I used some level up, and I could just drop it inside of here and say, hey. Form action, message, code check. And then if you did the code check, it would say code check success or whatever In the in the little toast message.
Scott Tolinski
So either way, the way that Svelte conform actions work is you submit that, and it sends it to basically, if you're on page dot Svelte inside of a folder that is, the code. It sends it to page .server.ts where then you have an action. If you don't have more than 1 action, there's just a default action, and that action would then have the locals property passed in there. You can also get the response or any of that stuff as well. But for us, the Prisma client was saved in the locals, and all the form data gets parsed from our middleware and passed into locals as well. And then so we're able to then basically do all of our database stuff from there. And, you can there's a nice little API in here where you can return a fail response With the response code in the message, or you can, throw a redirect here, or you could just return the data directly from the SvelteKit action. And and in its entirety, man, this this ends up working so smoothly. The files are pretty much right next to each other. You can hop you keep them both open side by side, submit the form, Do the database stuff back and forth, and it's just nice and easy.
Files kept in sync
Wes Bos
One kind of funny thing that I kind of expected anytime that you do anything For developers, people figure out, okay, how do we break this or how do I how do I gain this type of thing? So probably Near the end of 1st day, I was refreshing the back end dashboard and I was getting every like 5 or 6 Refreshes. I was getting a error that said error querying database.
Wes Bos
The syntax database is not serving. There is a re parent operation in progress, and I looked it up. That was a MySQL error that was coming from PlanetScale and what was happening. So I jumped into the the server logs. So what a lot of developers were doing is they were copying every single code they could find in the show notes on the website everywhere, and then they just wrote, like, a A fetch loop that would loop over and ping. They figured out what the what the API hit was, and they were just sending it over and over and over again And looping over every single one, which I think is probably what happened with a lot of the locked codes, is people were not expecting there to be Because once you lock the code, you couldn't redo it. Like you couldn't just put in your code and your email address and say, Okay. Now I'd like to fill out my shipping information. They were just locked, and you couldn't unless you are on the page to fill out your information and have that URL, You're kind of out of luck, which is good because we stopped a lot of the cheaters from getting in.
Database getting hammered
Wes Bos
But that error was because we were Hitting the database so often like, are you do you still have the PlanetScale open? Are you able to see how many, like, queries per second we were hitting at that one point?
Blocking invalid requests
Scott Tolinski
I yeah. I'd have to look at it. You know, they're the plan scale interface is very nice. I mean, it's very much Vercel interface. Yeah. But I found, like, the the clicky around stuff to be not as Oh, yeah.
Small database usage
Scott Tolinski
Okay. Let's see. Are you talk okay. So at its peak, it doesn't really say. It just says we were doing 1.6 writes per second.
Scott Tolinski
No. That doesn't make sense. That does not make sense. It was the reads that was telling us. But the reads that yeah. That none of this really tracks. So I I I'd have to look at these, analytics in a different way because none of none of this is really well, we had 1,600,000 reads, And we had 26,000 rights.
Wes Bos
So What was happening is that there was both those people doing it, and there was several Nefarious people out there. Literally, there's a couple of you all that have legit botnets that listen to this podcast because this is not like actual botnet. Yeah, not the first time that this This has happened, and at the peak of it, we were seeing 7 or 8 requests per second to the API endpoint. And those 7 or 8 requests per second were being sent to the database to check if the code that they were sending over was Legitimate.
Not actually a heavy load
Wes Bos
And Scott made them 5 characters long alphanumeric, which means that there are 42,000,000 different combinations.
Wes Bos
So the the the ability of you to possibly guess one of them by looping over it was extremely low. If we were to do it again, I would probably make it 6 characters so that that would go from 42,000,000 to 1,700,000,000 permutations.
Scott Tolinski
Yeah. Because they were initially initially, the codes were 6 digits, whereas 3 digits, hyphen, and then 3 more digits, And we decided that would be too annoying for people to try to hype in.
Code permutation limits
Wes Bos
Yeah. So what we what I did is I jumped in to The serverless function.
Wes Bos
And I said, okay, we got to stop.
Wes Bos
The serverless function was handling it just fine, But the planet scale, I don't know. Did you are you were you on a free plan? A hobby plan on planet scale? I'm on the free plan. Yeah. Okay. So Scott was on a Free plan. We're sending it literally 8 requests per second to, and it's handling it almost perfectly, which is surprising That you can do this. Yeah.
Wes Bos
But what I did is I said, okay, first, if it's not 5 characters, immediately reject it. And what that did is it stopped All the requests of people typing in syntax, hot tips, LOL, random stuff is stop those from going to the database because Clearly, they were not legit. They weren't 5 characters long.
Wes Bos
And then 2nd, I loaded up the Scott had like a seed TXT file on the In the repo that had all the codes in it, so I loaded that up with a and put it into an array.
Checking codes against list
Wes Bos
Shout out to Vite Being able to just require text files in a JavaScript function.
Wes Bos
So I loaded that up into an array and then I just check Array includes the code.
Wes Bos
And if the code wasn't in there, then it immediately rejected it. And then that Made the database, request go right down because we were we were simply just rejecting it via the serverless function before touching the database. If you aren't even in the neighborhood,
Funny error messages
Scott Tolinski
you don't even get to ask. Exactly.
Wes Bos
And then I was returning some really funny error messages at that point because
Scott Tolinski
it was clear that people were were goofing around with it. Yeah. That that was funny because, again, all that stuff was being added on the fly and being just Shoved up onto the Internet of this thing is being hammered. Yeah, and we had really no catastrophes in that way. So that's it was good. Very impressive.
Possible improvements
Wes Bos
The other people are probably saying, Like, there was a couple things that I kinda wish we had in place.
Scott Tolinski
Oh, before we get there sorry. Before we get off this database thing, If you're wondering why I chose to use the free plan of PlanetScale on something this, intensive, I had my credit card in there, just so you know. And we did have, like, I had a buffer in case we were exploding any of our our limits that it it would Charge my my credit card and let us, expand a little bit more or whatever you need to do there. I don't even know what their API is because this is my 1st time using it, but, we didn't even come close. Not even close to the the the free limits for anything. I'm just looking at the PlanetScale
Cheap database pricing
Wes Bos
hobby, and it says 5 gigs of storage, 1,000,000,000 reads a month, 10,000,000 writes a month, 1 production branch, 1 development I'm just looking at that. I pay almost $100 a month for MongoDB Atlas.
Wes Bos
I'm pretty I'm pretty sure I could run my entire business on the hobby plan. It's it's wild. So we use,
Scott Tolinski
for for all of that, we talk about we did 1,600,000,000 reads. We use less than 1% of our reads.
Scott Tolinski
We did. We use less than 1% of our rights. We use less than 1% of our storage, and this thing was a a horse for us. It was a beast. Yeah.
Minimal database usage
Wes Bos
I still don't know why the planet scale was returning that re parent thing. And if anyone is a my Well, what I looked it up and that was it was basically sharding the database, which Scott finds hilarious.
Database sharding
Scott Tolinski
I do. I love the word charting here. I just,
Wes Bos
yeah, scaling up something like that. I have no idea. But I would like to figure out If that was a limitation of the plan or if we were sending because, like, wow, this is a lot of traffic. But you know who also gets a lot of traffic? Like Stores get this every single day. The government gets a 1000000 times this. Comparatively, This was not very big. It was big for us. But you think about somebody trying to sell shoes from Nike And they do a big drop, you know, like, that's probably a a 1000 times larger, than this will ever be. This is really,
Scott Tolinski
This is really topical.
Scott Tolinski
Although, you know, at at May 3rd, this will not be topical when this is released. But, Wes, I don't know if you you're familiar with Love is Blind.
Scott Tolinski
I I've it's like a Netflix show. Right? It's like a Netflix show, and they were doing a live stream of their reunion last night. And, They just I I don't know what was going on with it because I haven't I haven't looked at any of the recaps if there are any recaps, But Netflix, you you think they have their stuff together? No. They had to, like, cancel it or delete.
Scott Tolinski
People people who are logging on, like, 2 minutes late, We're getting a message that was saying we can't let anybody else in. We have too many people trying to get into this. So, yeah, we're we're not Approaching, love is blind territory.
Scott Tolinski
I can't wait for some of those recaps to come out about that. But, you know, again, for the for the free The hobby plan on this thing, I was really super impressed, and and and it could've just honestly been something we were doing. And at one point, I I thought we were getting hammered another time, and it turns out I was just running a backup because I had I turned on scheduled backups. Oh, it was just running a backup. Oh, that's why We had so many reads and writes. I was like, I'll buckle up somebody else's head. Yeah.
Quick live updates
Wes Bos
So the brute forcing, the thing Generally, you want to do is if people are brute forcing it, I I usually just, like, quickly look at IP addresses. And you can if it's if it's like there was 1 guy from Australia that was Hammering it and unreasonably. And I just immediately put an if statement in the code because we didn't have we're on Vercel, but we didn't have Cloudflare set up. Vercel doesn't like when you use Cloudflare in front of them because Mhmm. It kinda messes with a lot of their CDN Special sauce. But like, I love running Cloudflare, so we didn't have the ability just to hop into Cloudflare and throw A list of IP addresses that we wanted to block. So at one point, I just threw an if statement in the I threw an if statement in the code that just blocked this 1 guy because he was doing it. But almost every other one that we're getting hit with was a different IP address, which is why I say a lot of y'all have legit Bought farms because they were not coming from the same IP address.
Wes Bos
They were coming from a different IP address, And you would see the same IP address come every couple of seconds or every 10 seconds. But it was clear that somebody had deployed some sort of Nefarious botnet that they had at us, which I thought was pretty funny. So we didn't have Cloudflare.
Botnets used
Wes Bos
We didn't have Captcha. That's another Easy way to stop this type of thing is you throw Captcha on the submit form and somebody can only submit it. So however many times you can also put rate limiting in, but Generally, rate limiting is based on either the person's browser and or their IP address.
Wes Bos
So the botnet Stuff doesn't get stopped by that. You have to use, like, a capture to get away from that type of stuff.
Wes Bos
And so we could have had that. But honestly, I was like, oh, should we add this type of stuff? Like, people are going to try to abuse it. But I was like, I was kind of looking at the stack. I was like, It will probably be fine even if people do, which they did.
Security improvements
Wes Bos
And it aside from, like, 1 or 2 failed admin refreshes that I had,
Scott Tolinski
it was no problem. We really just had to, You know, hold the door or we had to hold the door like Game of Thrones or whatever and just hope that, they didn't break down. And then honestly, didn't really even get close. Mean, there was a couple of, like, moments where it was like, alright. We're getting some failed requests here and there. And in in what's funny is that I never even saw them. You were the only ones out. You would be like, oh, just refresh the page 10 times, and I could not get it to happen. So I was like, alright. I believe you. It's happening.
Reliability observations
Scott Tolinski
But I'm I'm seeing the request come in, but I'm not able to crash it. So even at that, I was still not getting any any failed requests on my end. So, that was that was really impressive. And, so overall, I think, you know, my thoughts on this little stack and everything was that it's a success. I can't wait to open source this. We'll we'll hopefully have a link in the show notes again. Since this episode is coming out May 3rd, I can't imagine that I won't the reason why we we didn't open source it is because All of the codes are in a seed file, and and that's fine. I'd still wanted to publish the whole thing, right, if you're gonna publish it. So you could publish it without the seed file. I didn't wanna publish
Wes Bos
it right away because Oh, yeah. People will be hunting for holes. Yeah. Exactly. And, like, I was I looked it over, and I was like, this looks good, but you never know. Like, if you give people the instructions on how exactly it works, then they're gonna go even 1 step Further.
Minimal costs
Scott Tolinski
Of course. Yeah.
Scott Tolinski
Yeah. We pretty much covered everything. You know, it was a it was a fun little project to work in it, and it's, You know, it just goes to show you you can build something really functional without paying any extra money, like granted.
No server costs
Scott Tolinski
We got a little help from Vercel by having that free Vercel account there, but we didn't pay any money for the database.
Scott Tolinski
I'm not paying any money for SvelteKit or any of its dependencies.
Free services used
Scott Tolinski
Now Sentry, you'd have to pay for it, but we did not have to pay for that. So thank you, Sentry.
Scott Tolinski
And, the Google API, we're gonna have to pay a little bit for places but it ends up really being nothing. So you could toss something up like this and have it be so useful For so little money Mhmm.
Scott Tolinski
So quickly and have it be such a great experience is just a testament to where we are at in software development With all these UI frameworks, people say, you know, why use a framework or any of this stuff? But, man, it just really made things so much easier. Say hi to Scott. Hi. Where are we going? Rock climb. It's time to go rock climbing. You gotta wrap this show up because it's time to rock climb. Sick. Should we do sick picks? Let's do sick picks. I'm going to sick pick the Super Mario Brothers movie because we went to go we we took, Landon in Brooklyn to see their very first movie. They've never been to the theater.
Framework productivity
Scott Tolinski
And, this is the perfect time because, you know, Landon's gonna be 6. Brooklyn's gonna be 4 soon. But it's it's a perfect time for them to To get a chance to go to the movies, and they don't really know very much about Mario. Like, they know Mario Yeah. But they didn't know Any of the the lore or any of that stuff, and I gotta say, man, walking out of that movie, they were just endlessly psyched about it all. They love Donkey Kong. They love, Luigi. My daughter was like, my favorite part was when Mario and Luigi worked together. And we're like, oh, that's so adorable.
Scott Tolinski
But I gotta say, as a fan of Mario and it's like a long time, you know, I've I've played all the games since I was a little kid.
Scott Tolinski
It Really just put a big old smile on my face from start to finish.
Scott Tolinski
I had a great time watching it. It was a blast. The movie was It was just great. I have nothing bad to say about it. It was just fantastic.
Scott Tolinski
We came home, and we played a 4 person Super Mario game, all 4 of us. And and it was a lot of fun. My neither of my kids have ever played a video game, but they were like, we gotta play Mario. Well, that's what we gotta do.
Scott Tolinski
So we fired up one of the the 4 player Mario games. Yeah. They don't know what they're doing, but it was a lot of fun. It's a family thing. So check it out, the Mario movie, if you haven't seen, like,
Wes Bos
No. I didn't even realize that was out. My kids do actually really like Mario. We have the original NES at our cottage, And, they like being the green guy or the red guy.
Wes Bos
And we actually it's kinda cool. We have a wireless NES controller, And it does 2 player, and there's just a toggle switch where you just pass it from one another, which is so good because kids with with controllers.
Wes Bos
Oh, yeah. With a cable on it, they rip it down. So we found it at just a yard sale and it's like this wireless NES controller that you plug in It works great. And we have the Nintendo Switch, which you can have,
Scott Tolinski
you can have the old we we started with Mario one. Oh, yeah. And then moved moved up to Mario 3 and then did the new Super Mario Brothers ones. But, yeah, same thing. Remotes wireless. Gotta have to be wireless at this point.
Wes Bos
I will, sick pick. I'll I'll stick pick a kids thing as well. A couple months ago, we went to the Rochester Children's Museum, which if anybody lives in southern Ontario or northern New York, I would highly recommend going to check it out. So Rochester is about an hour and a half away from us. So we crossed the border one day and Drove to it, and they have this most amazing kids museum where they have it. It's all interactive, and there's so many things to touch. It's not one of those museums where you have to worry about them touching anything. It's just so much fun for them to play and there's unlimited stuff to do. We were there for like 8 hours. We Still didn't even touch it all. So if you're looking for something to do with your kids, definitely check it out. And Rochester has some cool,
Scott Tolinski
Cool restaurants as well. We went out for dinner after. Nice. We did, very recently over our kids' spring break, we did the Natural History and Science Museum for the kids, And we'd already been there once, but, like, these things are just the best, especially if you have kids. They go nuts for all this stuff. They end up with so many questions.
Scott Tolinski
I know my my son is a big question asker, but we have so much so much fun at the the museums around town. So, yeah, shout out to museums. Awesome. I gotta run to rock climbing, shameless plug. Westboss.comforward/courses
Wes Bos
for a list of all my courses. $10 off for syntax.
Scott Tolinski
Alright. Have fun at rock climbing. Shameless plug sentry at sentry.i0.
Scott Tolinski
If you have a project like this that you're throwing up in 3 days and it's gotta work for a a million some requests, you you're going to need Sentry on it. Otherwise, we wouldn't have found a lot of the weird things that people were trying to do to get into the back end of our site or just try to access things. So,
Wes Bos
Yeah. Shout out to Century for, you know, really saving our bacon there. The most hilarious part was seeing the errors of people trying to look on the window for codes.
Wes Bos
And you can tell that people were writing JavaScript to try to either programmatically Submit the form or to, like, just look on the window for like, they're looping over all the window keys and whatnot. It's really funny.
Scott Tolinski
It was really funny. A lot of it was a, a lot little lesson in the types of lengths people will go to for a t shirt. Yes. Yes. Exactly. And, also,
Wes Bos
we didn't turn it. I forgot to turn it off for local development, but it was actually kind of a blessing because I would break stuff, and Scott would fix it without us even talking.
Wes Bos
Generally, you don't you don't want it on during dev, but it was, it was it worked out for us. It worked out. Yeah. It was all fun. Yeah. Alright. That's it. Thanks, Eric, and King Ink. Catch you later. Peace. Peace.
Scott Tolinski
Head on over to syntax.fm for a full archive of all of our shows, And don't forget to subscribe in your podcast player or drop a review if you like this show.