skip to content

Val Town wants to make serverless JavaScript easier

HTTP handlers, cron jobs, email handlers — all the little things we need to set up as web apps get more complex. Steve Krouse will teach us how Val Town can help.

Full Transcript

Click to toggle the visibility of the transcript

Captions provided by White Coat Captioning ( Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.

JASON: Hello, everyone, and welcome to another episode of Learn with Jason. Today, on the show, we are going to have a lot of fun. We're going to get into something that I honestly have struggled to describe because it seems like it does so much. Before I start the show, I'm going to do a quick shout out to our captioning and sponsors. We have Diane here from White Coat Captioning, taking down every single word we say and putting it into the live captions. You can see the stream URL at the bottom there if you want those assistive captions. And that is provided by the support of our sponsors, we've got NX and Netlify, both kicking in to make the show more accessible to more people, which I very, very much appreciate. And here today to guide us on our little adventure into serverless is Steve Krouse. Steve, how are you doing?

STEVE: I'm great. Thanks for having me.

JASON: I am super pumped to have you here. I always love it when a product does so much that I struggle to describe it. And looking forward to digging into this. Let's talk about you. For folks aren't familiar with you and your work, you want to give us a background on yourself?


STEVE: I have been into programming languages, developer tools, frameworks and programming education for my whole career. I guess, some people might know me from the Future of Coding podcast I started a couple of years ago. That is currently run by some other folks. Before the Future of Coding podcast, I ran an after school program teaching kids to code, scratch programming and kids learn to code. And what I found out when working with kids and building learnable programming environments for kids, kids don't want learnable programming environments for kids, they want to do what adults do. They want adult tools to be learnable by them. And that's kind of what put me on the path to starting my current company.

Very cool. All right. So let's talk a little bit about, like usually what I like to do is I like to start by going over the kind of the problem space that a product is solving. And when I read what your company can do, I sort of I struggled to come up with the specific, and I was worried that I was going to put it in too small of a box. Let's talk a little bit about kind of what problem are you solving? When you set out to build this, did were you saying to yourself I'm going to build everything? Or did you have kind of a set goal in mind?

STEVE: Hmm, when we set out, you know, this idea it's a weird one, it keeps kind of growing in scope, in the beginning I wanted to build a place where you could run server side code from the browser with no setup. You could pop open a new tab, write code, hit run, it runs, it's in a deployed format, you can host a website from it, accept webhooks, all of the things you would want from a server kind of platform, but you didn't need toe use the terminal. You don't have to download anything. Don't have to deploy anything. I wanted a browser focused environment. There have been a lot of these over the years, Glitch is one. It's kind of like Code Sandbox or Codepen, but the backend. That's another way. Runkit as some of you may have heard about. That was the original idea. Small snippets of server side code in the browser.

Gotcha. OK. And so it has it now feels like you've expanded a little bit. Well, I guess, we haven't said the name yet, so this was your idea was server side snippets in the browser. What did it become? Yeah, so the company is called Val Town. And it's still a lot of server side. It's still really a server side snippets in the browser. But the platform has grown into being able to handle most of the things you want to do in a full stack backend platform. So in some ways, you think about us like couple (inaudible) Heroku, we're kind of like a place you go to build your whole app.


STEVE: With an emphasis on lightweight, fast, and fun, you're not going to build a company on this but it's a really fun place to build a hackathon project for yourself. Little chrons for yourself and your family. Over time, we want to handle workflows, but we're starting with light, simple, fun, friendly ones.

JASON: OK. Cool. Very cool. So, I guess, this is all really I'm glad you're here because you can answer a question I've had... when I talk about something like Glitch, in the past what I've always found is that I think it's super fun but I haven't been able to find like, I haven't been able to fit it into my workflow. And I don't know why.

STEVE: Yeah.

JASON: So with Val Town sort of being comparable in it's, you're not going to deploy a full app on it. It's sort of to, I guess, what do you do on it? What's the use case you think really makes this like this is how it fits into your workflow and levels you up as a dev?

STEVE: Yeah. So today, Val Town is most used, 2 or 3 categories most popular for Val Town, one category's very popular is what I call zappier for developers. If you have a small thing to automate, SaaS stores from one to another. If you have a pull job. I pull APIs, I pull for the weather. I have all sorts of pull jobs running. If they find something, they'll Tweet for me or send me an email. We have all of these hooks that make that really delightful, in the same way that Zapier does. You don't have to point and click. They charge you if you write three lines of code, they call a three step zap. But in Val Town, you hit the enter key. It's approximately a programming language for people that don't know how to code and they also have all of these great hooks. And it's instantly deployed. Val Town has some of these great hooks instantly deployed but it's for programmers. So you have everything you want at your fingertips not at the mass pointer.

JASON: Got it. OK. That's very cool. And so, it's... yeah, I like this, because to me, that is the there's this point of pain I've always felt as a dev where there's something I need to do that feels too small to stand up a server for.

Mm hmm.

JASON: But I definitely don't want to try to cram it into another codebase or something because then I can't remember where code is. So I end up with these, I don't even know what to call... glue code sort of pieces.

STEVE: Totally.

JASON: I have a little bit of functionality that's really important but I don't know where it belongs, and that has historically led to me having some deployed repo somewhere, that I could literally just call junk drawer. It's like every little task I need to run. If I'm pulling, handling webhooks, doing, you know, little teeny things that need to get done all the time. And I just don't know where they live. And I think companies keep trying this where you'll have a serverless functioning offering, or you can stand something up on AWS lambda or whatever. But if I deploy anything to AWS, I almost immediately forget it exists, disappears into the config pages. And so, if I do this on something like Val Town, what you're saying is I would be able to sort of not but I said junk drawer because that's what I feel in my heart, but that feels derogatory. But if I
[ Laughter ] If I go to Val Town and treat it as my like glue code home, I'd be able to just see a list of all of my pieces of glue code and have them organized a little better than they would be if I'm tossing randomly named files into a repo.

Totally, yeah. That's a pattern we've seen where we kind of SLURP up things that are currently on, like, a random Heroku instance, or like a random digital ocean droplet. We like SLURP up those sorts of scripts that people already have and now they just locate them on Val Town, which is like a great place to host them and also social, so you can make your scripts public and other people can

JASON: Oh, interesting.

STEVE: Pull request, you can use other people's code. We have the GitHub style social elements.

JASON: And that's very Zappier, too, where you can put a workflow together and go use it.

STEVE: Yeah, exactly.

JASON: That's nice. Very nice. The chat's excited, I'm excited. How does this run? Like how is it you mentioned server it is serverless? I didn't misname this?

STEVE: Yeah. Serverless serverless is a funny word. What does serverless mean? I have a friend who likes he likes to call it I can't believe it's not server. Because, like, really at the end of the day, serverless is another it's definitely there are servers. That is what it is. But I think the mind set of serverless is you don't have to think about servers.

JASON: Right.

STEVE: Val Town fits into that. You don't have to think about how many servers we have, you write code and it runs and scales up and down. You don't have to worry about servers.

JASON: Right.

STEVE: In that sense.

JASON: And unlike I can't believe it's not servers, this does not have any partially hydrogenated server oil. [ Laughter ]

STEVE: Yeah, exactly.

JASON: Sorry, you're welcome to leave, if you want.

STEVE: No, no, that's great.

JASON: There's a line and I've crossed it. [ Laughter ] All right. So let's do let's do this. I could probably ask you a million questions about this, but I'm going to, instead, ask you how it works. Let me take us over into our paired programming mode, which is this one here. And we're going to jump in on this view. And I'm going to throw up this banner here. All right. So first and foremost, we are talking to Steve today, so make sure you go give him a follow. And we're talking about Val Town. So make sure you go and check that out, as well. Oh, and we've I'm sorry, Vinny, I apologize. [ Laughter ] Stick around, it's going to be worth it. All right. So if I want to get started, I want to try something out and learn here. What should my first step be?

STEVE: Sign up slash log in with GitHub.

JASON: OK. All right. I'm in.

STEVE: Nice.


STEVE: All right. This is your first Val.

JASON: All right. And so, we're looking at importing from NPM. So this is Dino, right?

STEVE: Yes, good eye.

JASON: OK. Cool. I'm writing Dino code but I can use NPM because we learned that was important. And yeah, we've got react coming in. So we're doing full blown this is cool. We have a little server going right now.

STEVE: Yeah, this is a little server HTML and react.

JASON: Oh, I didn't see this was down here.

STEVE: Yeah, live and deployed, fully hosted. Change something and then hit command enter.

JASON: OK, I can send this link to anybody. If I open this in another oh, cool. All right so then, we can say something like this. what did I just do?

STEVE: I think

JASON: The auto complete.

STEVE: Yeah, the co pilot. But yeah, if you hit preview, it should give you the new version.

JASON: And there it is. Very cool. So, I like this. This has got, you know, it's reminiscent of something like Codepen, but we're running server side code, so the fact that we've got a Dino environment, we're sending an actual response, that's pretty slick. OK. I love that. The instant deploy is cool. All right. I'm going to hit done. And now.

STEVE: Yeah, this is your home space. There's the tips at the bottom. You can make a bunch of different kind of Vals. I can go over what each type does.

JASON: That's probably a good idea. Let's step through the high level of what we can do on here and go into something practical.

Maybe zoom in on the tip section, it lists the four kinds of Vals you can make. Script Vals, just run like scripts. They don't anything that interesting. Http Vals, that's the one you need.

JASON: If I wanted to write myself a utility function or something. But actually, that's a good question, if it's not http, how would I access it? Is it manually I can run any script I want?

STEVE: Yeah, scripts are good for playing around, you know, testing out a library. Or, like making a script calls a file maybe it doesn't do anything, but it defines functions that you import in other Vals. Vals very easily import from each other.


STEVE: That's another kind of like, you know, Val Town is like an onion in that you keep getting deeper and deeper. One way to think about it is each Val is like a gif but it runs. But each thing is instantly a module that's importable. It's like NPM, as well. So anyways, a script is most boring one. But we'll get back to that if we need to. Http Vals, that's the one we did where we have a website.

JASON: Mm hmm.

STEVE: And you could also accept webhooks or accept JSON, return JSON, that's straightforward, scheduled Vals are chrons are on a timer. You can send an email to a Val and it will trigger that Val with the body of the email. So you can

JASON: Fascinating.

STEVE: I feel like if you install that in your brain that, wait, I can trigger code by sending an email? All of a sudden, you're going to see the use cases in your life. Wait a second, I just forward this email to code and trigger some stuff.

JASON: And I have a million workflows for myself where I like email myself something because that's the only place I consistently check.

STEVE: Yeah.

JASON: I can see a lot of ways that this type of functionality can we'll see, this feels like a rabbit hole I'll fall down at some point.

STEVE: Yeah. It's really fun, you can send an email to a Val, that's easy. Or you could very easily here, we'll start with that one because it's really simple if you zoom out and go up to the top. Just click on email handler. Yep, nice. There it is. It's live. There's your email address on the top, right corner, copy it, send it emails. You can if you just do console.log email and then send it an email, it'll show you what.

JASON: I'm saving that. Going to kept my email client over here. I'll send one of these. And let's see, subject line of testing, and one of those and then, we'll send it.

STEVE: Cool. While we wait for that, I guess you can... get rid of this co pilot hallucination. Sorry about that. Oh, there it is. That was quick.

JASON: Really quick. Yeah. That's nice. So, we get, there's the email body. Got, yeah, subject, we've got plain text, this is great.

STEVE: Yeah, and then, so one thing that's really easy to make in Val Town is let's say you wanted to let people contact you by email but you don't want to give away your actual email address, you can give away this email address, just created for you. You can change the name of it if you want, there's an edit button on the top left. There's a little edit button for the name of the Val.

JASON: Oh, I got it.

STEVE: Yeah, you can give it a name, and then, if you wanted to make it a really simple forwarder, accepts emails and sends an email to you, I'll show you how to do that. This will involve me explaining the Val Town standard library. We want to give you everything at the fingertips. We have a number of hosted services that normally you would have to sign up for, Send Grid, get an API key, put down a credit card, instead, we give you a small, but enough of those services for free, just bundled into your free Val Town account and more for the Pro Val Town account. And you can send an email right now. Type the @ symbol, our clever way to trigger this auto complete thing and is the one we're looking for right now.

JASON: Oh, that didn't work.

STEVE: Yeah. There you go. Nice.

JASON: Oh, it did do it, yeah, I understand.

STEVE: And then, you can put, like, you know, it's the argument is an object with, you know, two from that kind of thing. It implicitly will email the owner of the Val Town account. So you don't have to fill you don't

JASON: Wait, what am I doing? The thingy is being weird on my, when I'm trying to auto complete.

STEVE: Yeah, it's being weird. We can turn that off because I think it's hurting more than helping us. If you go to your preferences in the if you scroll up to the top in the right preferences and then... scroll down a little bit. And you can just turn off the AI thing. And save.

JASON: OK. Fail to update?

STEVE: Oh, rough. Try, again.

JASON: Let's see.

STEVE: That's an annoying bug. Refresh the page and try, again. I don't know what's going on with that.

JASON: It's going up to that page. Your bio is apparently required. Cool, I think I've got it. We're in here, this will hopefully stop helping. I do a two and we

STEVE: Two is actually the one you can leave off. It'll imply it'll go to you.

JASON: Oh, interesting, OK. And we could do something like, subject, email

STEVE: Email that subject.

JASON: Subject oh, I have, here's what's happening. We have dual declarations here. I need to rename this as incoming email.

STEVE: Nice.

JASON: That explains a lot about why this was fighting me so hard. I understand what's going on. There we go, now our auto complete works. We can do one of these and incoming email.from. And then, we can do a we'll do the text, I think, is fine. So theoretically speaking, anything I send should relay through my through this Val into my email. I'm going to send an email from one of my other email addresses. Actually, I'm going to yeah, I'll send it from this one here. And let's see, please, fix the website. All right. So I'm going to send this, and we're still logging so we should see the console log come through. And I should also, theoretically, see this relay into my inbox. And once that shows up, I will put this back on the screen. OK. So there's the new email. And it is

STEVE: Oh, yeah, yeah, yeah, I see. I forgot about this. You can't modify the from field because, like, we haven't verified that you own the from.

JASON: Oh, I got it. So did it fail, then?

STEVE: Yeah, just failed. There's an error down there that explains it. Leave off the from field and it'll work. You can or you could change the from field, yeah if you undo that, change from to "reply to." It's not the same, but I don't know if you're familiar we mails reply to field.

JASON: Yeah, yeah, I've got that.

STEVE: That's the best we can give you without

JASON: I gotcha, I'm testing, again, and it's that's the email, so we'll do one of these, and get that sent. It's off, it should show up momentarily. And... I did send it, right? I did.

STEVE: Sometimes, if you click out and click back in, it'll pull faster. If you click out of the tab and back into the tab. Hmm.

JASON: Now I'm worried I sent it to the wrong... no, I sent it to the same place. Here it is. OK. So that went through. And then, looking at mi... look at this, y'all, OK, I'll bring this across so everybody can see it relaid. So that's pretty dang cool it did that, that quickly and didn't require me to, like, go get a bunch of API keys and stuff that I would normally have needed to do. I'm a big fan of that.

STEVE: Yeah. Yeah, so we have in our standard library, we have email, Fetch, so if you want a proxied fetch, a randomized IP every time you fetch, we have that does that. And we have blob storage and SQLite storage, built in, no cost, an @ symbol away.

JASON: Very cool. That is very cool. And also, hi, Ally and friends, I think we got a raid. So, we've got access to... actually, if I just go in here and I do the standard, then I can see SQLite, Fetch Blob, oh, Turso's built in, OpenAI is built in. That's pretty cool.

STEVE: Yeah, so, Turso, I'm realizing now, we should prune this list. Turso has been renamed to SQLite.

JASON: Oh, I got it.

STEVE: I should remove that. And then OpenAI, which you saw, that one is like launching tomorrow, but I made it public for the stream so we could use it today. [ Laughter ]

JASON: Sneak peeks here on Learn with Jason. All right, that is that's great. So this is and this is cool I do like the idea of having there's a standard library and if you know to type the @standard, you can basically see what's available to you right there. I love this is one of the things I love about I assume this is driven by Typescript so we get auto complete and magic.

STEVE: Yeah, we're fans of Typescript.

JASON: All right, so we've got a good tiny preview of one thing we can do. I love the idea of being able to sort of have almost a burner email is kind of nice.

STEVE: Yeah.

JASON: I like that. For so what else can we do? How do we take this further?

STEVE: Sure. Yeah. I'll kind of evoke a couple of email handler ideas. And we can move on.


STEVE: One thing that's, like, you can build a bot with email really easily. You could send an email to a Val and arbitrary and email you back, you could have a conversation with your code without building a UI, that's kind of fun. You can forward it, spin, you could forward it, I don't know, any email you get oh, so here's a fun one. Our hosting provider is Render. And they don't have webhooks, but they do send us emails, autoforward filter and I can do whatever I want with it. Which in this case is forwarding it to the team's discord.

JASON: That's also interesting, too, because it creates the idea that like any email can be a webhook.

STEVE: Yeah, you got it.

JASON: Which is kind of fun because I love doing stuff with webhooks. It's nice to be able to update something whenever a thing happens. I'm thinking of silly things that you could do, like, have a spam filter for like when you get a recruiter email. And just update a counter on a website somewhere. Like, how many recruiter emails I got today and just have that number tick.

STEVE: Yeah, totally. Or send the whole email. And strip out any public stuff and send the whole email over.

JASON: Yeah.

STEVE: You could even you have ChatGPT, strip out any private information and add it to a SQLite database.

JASON: Yeah, I think there's really fun stuff you could do with this. And it's also interesting, too, because, like, I'm thinking about my own my own process for my company, for example I do a ton of sales as part of my day to day. And a huge amount of that happens through email. And so, if I'm not setting like what I do right now is I snooze emails so they come back after a certain amount of time. Sometimes, I forget to do that. And that means that I end up like panicking a week and a half later when I realize I didn't send the followup for an email. If I had the ability to forward these emails to some kind of system that would set a timer for me and remind me to followup with the clients and put them into a queue that's like, hey, these are the people that you need to follow up with today as opposed to me looking at what boomering back to my inbox today. That's a nice quality of life thing. I could send myself a private message in Discord or Slack, here's what you're following up with today. Those are things that feel like I'm not going to build a whole app for that, but if I know I can catch an email and add it to a list and that list gets pulled every day. That's cool, very cool.

STEVE: Yeah. I guess, you're touching on two ideas I want to highlight. One is what I call end programmer programmability. People may be familiar with the end user programmer. And this is old timy dream that end users would be able to really program the apps they use. And it's like a dream from the 1960s.. And we still haven't come anywhere close to it. So Val Town is asking the question, what if we allowed programmers to be able to shape the apps they use on a daily basis? And this is an example of that. Instead of relying on Gmail's snooze feature, you whip up your own snooze feature system in a couple of hours. And then, you own it, you can make it exactly how customized you want it. Someone else can improve it a pull request or copy it on their own thing. So Val Town is like GitHub in that you can forward stuff, but also like an app store, the thing you fork now runs. It's like forked code, but also, running code.

JASON: Yeah, and it is cool that you do things like auto fill the "to," for example. That's slick, because for me, I don't have to edit this code even to run it. Anybody could fork this and the name of it changes so the email the email you send it to updates automatically, and it'll automatically send it to my email address. Which is pretty dang cool.

STEVE: Yeah.

JASON: That sort of stuff, yeah, like you said, makes it easier for me to reimagine how I would interact with different parts of my workflow because it's not like this huge task to set something up, it's more just like, well, OK, if I could get an email, I can do something with that email. And, you know, knowing that I've got access to, as you said, email, ChatGPT, you know, databases, like all of a sudden, I can do interesting stuff, and these all you said on all of these, you're providing a small amount of free tier access to these services?

STEVE: Yeah.

JASON: That's pretty cool for personal use. I can think of a lot of ways that, like, I'm not going to go I'm I'm not going to go set up like custom ChatGPT keys every time I have a silly idea. But knowing I can just, like, OK, will this silly idea work? And then, if it does work, I can go build it out for real. Just whacked my light.

STEVE: Yeah.

JASON: That's I think that's the other thing, too. One of the things I like about platforms like Val Town is the barrier to experimentation is virtually zero.

STEVE: Mm hmm.

JASON: I love that, especially when you get into server side stuff. One of the things that stops me when I have an idea that leans too far into the backend, I don't want to have to go and create 6 rounds of credentials from the database service and the email service and the whatever service and get all of their boilerplate about how to set it up and connect them all. I just want to try the thing. And this, like being able to do it this way, all the credentials are handled, all the, you know, the boilerplate is handled. I just had to have the idea. And I think that really is a that's a major unlock, even if this isn't what I ultimately ship to production, this is a great thinking tool.

STEVE: Thank you, yeah. One of my favorite users likes to talk about how Val Town lowers the activation energy to do a thing. We're not competing against your normal way of doing things, we're competing against you not even writing this code in the first place.

JASON: I think that's a really, really valid thing. I talk myself out of a lot of ideas because they'd be too hard to build.

STEVE: Yeah. So let's come up with another idea and give it a go. I feel like http handler, like a so, I think you saw I did a little poll yesterday about what folks wanted us to make and folks seemed excited about like a little full stack app with a little SQLite database, and maybe a chron, maybe GPT using the yet to be released free, included GPT thing, I think some combination of those primitives.

JASON: Yeah, just that little bit you said all in like 40 minutes. [ Laughter ] I think you're kind of proving your value prop right there when you can say all of those things in one sentence and know the time limit and say it with a straight face. [ Laughter ] If we want to do it like this, so I've created an http handler. What should I do first? I think you have an idea in mind of what we want to build so.

STEVE: Yeah.

JASON: What do you want to build?

STEVE: Yeah. So a friend at a hack night had a project that I thought was really fun kind of idea, he called it a collaborative poem builder where everyone writes a line of a poem.


STEVE: It's really just a comment section of a website.

JASON: Sure.

STEVE: But I think a collaborative poem builder is kind of fun. And if we want to throw GPT in and had a human write a line and GPT write a line, we could do that. Anyways, we'll start with that. It'll involve some frontend and backend database. And then, maybe GPT, as well.

JASON: Let's do it.

STEVE: All right. So, like the first thing that like the first decision point that you would want to make in a situation like this is what server framework and JSX frameworks would you want to use? And I'm happy to kind of give you the choice, but I'll also tell you what I've been using recently. I switch it around a lot. The amount of times I switch from React to preact, I keep switching, so I'll let you make the final decision, but I've been using Hono and Honojsx recently.

JASON: Let's use those. The first one and most important one being if I get stuck, I want something that you are 100% confident we can bail out of quickly. Let's use your current favorite to make sure that's not the thing that slows us down.

STEVE: Great. I would recommend starting from a template. We have a template thing right there. Yeah. And then, grab scroll down for Hono. There's a router example on the left.

JASON: I'm going to get rid of this one. I want to use the name. We're going to call this Poem Builder. I haven't actually used, but it looks pretty familiar. Reminds me a lot of what an express setup would be.

STEVE: Yeah, pretty similar, Hono is a web standard lightweight alternative to express. It's built on top of the request response objects that are from the browser and shipping a lot of serverless runtimes like Cloudflare. Hono's great. I'm a fan. There's one line that's kind of annoying to write I want to send you in the chat.


STEVE: To copy and paste to be the first line, it tells your editor how you want your JSX to be turned into JavaScript. And so, in this case, we want to use Honojsx, it's all kind of built in, it's easier.

JASON: Yeah, and this is the what do they call this? Pragma?

STEVE: Yeah. We really I feel like that's maybe the ugliest or most foreign looking part. You throw in a pragma and do the jsx of your choice. The up side you can use any jsx you want.

JASON: Mm hmm. And yes, Val Town is running on Dino.


JASON: And Pragma, this isn't the first time I've seen it. I'm trying to remember where I was using it before. Some other framework had the pragmas if you wanted to swap out for which thing you were using, solid for JSX or React or whatever. So, it's actually I mean, to be completely honest, if this is the hard part instead of having to swap out your webpack build or something, I'm kind of on board.

STEVE: Nice. I don't think we'll need that second route. You can get rid of the line 8. And then, let's write some HTML instead of text. Instead of C.text, you put any JSX in there

JASON: OK. I'm going to do it. Let's go with something like this for now. . There we go. Easy enough, I understand this.

STEVE: Cool. I guess, the next thing maybe wrap that in a div and make the second element of the div div form, and inside the form, put input box.

JASON: OK, so we're going to do... a form and inside the form we want what's the is it add the next line of the poem is the input?

STEVE: Yeah.

JASON: Line of the poem. And we're going to go with quick and dirty here. Text, required, and I guess it needs a name.

STEVE: Give it a name.

JASON: Yeah, a name of next line. Now we've got our next line of the poem.

STEVE: Great.

JASON: Probably need a button.

STEVE: Not for forms, enter will work.

JASON: Yeah, that's true. We can do it that way. All right.

STEVE: I would set the method of the form to post. And then, we'll make a post a post handler for the slash route.

JASON: Right. We're not adding an action, it's going to submit to itself and that'll work in Val Town. It'll submit to the same page?

STEVE: Yeah.

JASON: That's pretty slick. OK. And that's going to be on the same route.

STEVE: And then, I guess, I know you're going to run into this. You can make both of the handler functions async because I'm pretty sure we're going to need that.

JASON: That's yelling at me because it was... async. All right.

STEVE: And then, so, let form equals C dot rec dot form data. The typescript should start helping you.

JASON: There it is.

STEVE: You'll have to await that expression and also call it. It's a function. So this request object is it's the web standard request object. And this is the web standard form data object. If you've ever used form data on the client, this is the same object.

JASON: OK. So we'll be able to do form.get or get and that'll be next line. OK.

STEVE: Boom.

JASON: And then, we need to save this.

STEVE: Put this on the screen?

JASON: Yeah, why don't we just put it on the screen. That seems like a good idea. [ Laughter ] We can we'll do an HTML and we'll put out the next line. OK. So now, we have the ability to... what did I do?

STEVE: That looks fine. Maybe try saving it, again, maybe the preview button. Oh, yeah, preview is what you have to click. Save. Probably wouldn't do what you want.

JASON: OK, I'm doing something wrong.

STEVE: Method equals post.

JASON: Do I have to return the

STEVE: Yeah, yeah, good call. I hope that's the issue.

JASON: Do you have to turn in bad habits from express?


JASON: Yeah, so the implicit return here broke my brain. Got it. I'm with it now.

STEVE: Great. Now back to you were, we need to store it somewhere. So every Val Town user gets a SQLite database. Let's make a table in the database you have but maybe didn't know you had.

JASON: OK. And I do that up here?

STEVE: Yeah, go for it. At SQLite.

JASON: All right. One of these.

STEVE: Yeah, dot execute. And create table if not exists, poem lines.

JASON: Oops, table, if not exists, poem lines. .

STEVE: And then, yeah, then left parentheses. Here's where I wish we could bring in ChatGPT, again. I'm realizing that we should probably have a way to like turn it off, but on a keyboard shortcut trigger it. Because most of the time, you don't want like completing your thoughts because it's noisy, but this is a good example I think we can do it ourselves. Line, you can do ID

JASON: We'll do an ID and that's going to be, what is that like primary key?

STEVE: Integer

JASON: Is that how primary key works?

STEVE: It's integer and

JASON: Full on integer.

STEVE: Primary space key and autoincrement after that.

JASON: Auto increment, is it like that?

STEVE: No underbar.

JASON: And it's supposed to be all caps, I truly don't write much SQL these days. SQL doesn't really care. It's just for consistency. I guess, right?

STEVE: No space between autoand increment.

JASON: Oh, got it.

STEVE: I have to look this up every time. And then, line, comma you know, you could call it line text.

JASON: OK. We'll do line, and then that's going to be text.

STEVE: And that's it.

JASON: That's kind of good, right? Do we need anything else?

STEVE: I don't think so.

JASON: Let's roll, then.

STEVE: You clicked await the first time it runs, yeah. You could throw that, you could run it, and now, once it runs the first time, it doesn't throw an error, then the table's been created and you could comment it out. That will make things faster if it's not running.

JASON: Got it. Now that we've got it.

STEVE: I don't know if it actually ran. Maybe comment it out, hit save and preview. And then, save and preview. And then, as long as that doesn't error.

JASON: Seems like we're all good.

STEVE: Seems all good, now you can comment it out. And then


STEVE: Now, back to where you were, you can add it back in. Yep.

JASON: Now we need SQLite, isn't just executed, again.

STEVE: This time, instead of just a string, do an object because we're going to send in parameters.

JASON: Oh, right. It'll have two properties, one is SQL colon and that's the string and the other property will be args colon, and it'll be an array.

JASON: OK. And that's going to be our next line, we're going to insert into poem lines. Values. And is it a question mark as a place holder?

STEVE: Yeah. Yep. And poem lines, after the word poem lines, left parentheses, the word line and the right parenthesis.

JASON: Oh, that's right.

STEVE: And you can say online 32, you could say as string to convince it that it's a string.

JASON: Ah, yes. OK.

STEVE: And maybe do an await online 32. And then, online 37, do delete that, and do, yeah, delete that, and instead, we'll do I think it's c.redirect. Return c.redirect, I think, and slash. We'll redirect to the home screen. And then, on the home screen, we should

JASON: That is not the word I meant. There we go.

STEVE: On the home screen, we should do a get request kind of a thing. But maybe there's an alternative way yeah, that's fine. You could do get request. You're half way there.

JASON: Well, is there an alternative way that you think is better?

STEVE: The alternative was, like, a debugged view. Just poke in your SQL database, SQL database and see if it's there. But it seems like you'll get a render on the screen, you know, in the next 30 seconds anyways so

JASON: Let's do one of these. And we don't need one of those this time. We just need select everything.

STEVE: ID comma

JASON: Yeah, why not be explicit. From poem lines.

STEVE: Nice.

JASON: And we don't need any qualifiers, we're going to roll with that. And then, I think, I'm going to dump this so I know what it looks like. But I'm pretty sure I remember. There's our poem. And if I is it command, enter, save and preview?

STEVE: Yep. It's already there.

JASON: And there's our rows. What we'll be able to do here is we'll, a poem written by

STEVE: Someone in the comments asked for a bigger font. Maybe that's a good idea.

JASON: Is this better? Can everybody see now? I'm going to roll with that. And so, what we will do is we'll set up an unordered list. No, I'm not going to set up an unordered list. I'm going to set up a paragraph because it's fine. It's fine. And then, in here, we're going to go over, and for each line... or wait, hold on. We get back the ID and the line, so we're going to destructure line out.

STEVE: So it's an array, not an object, so just make an array with ID comma line.

JASON: Oh, it's an array. We'll do one of those and skip the ID. No, we need the ID because we're doing React. So we'll do a span with a key of ID does hono yell if you don't do this.

STEVE: I'm realizing no, it's all server rendering. It doesn't care. At the end of the day. I didn't realize that until now, I've been supplying the key because I'm so React built, but this is also
[ Laughter ] It doesn't matter.

JASON: OK. So this should be fine, I got something wrong. Poems row, whatever, what are you mad about? Identifier oh, it's jsx. There it is.

STEVE: Nice. Good catch.

JASON: OK. So this, then, should spit out our poem, and I should be able to get rid of this, then.

STEVE: Yeah, let's add some lines.

JASON: Let's add some lines. We'll say roses are red.

STEVE: Boom.

JASON: Hell ya.

STEVE: That's exciting. So yeah, maybe we should share the link so we can dangerously allow strangers on the internet.

JASON: Chat, you know how this works. If you do anything that I can't show on screen, nobody gets to have any fun. So behave. And this is

STEVE: One other idea.

JASON: I'll need to refresh to see lines?

STEVE: Yeah, exactly. So, one idea I had was we could build a spam filter using ChatGPT. That would before adding to the database, it could we send it to ChatGPT and say, you know, is this spam? Do you think it's spam? And then, if it isn't, then don't add it or you can add it with like another call for spam is true, or maybe everybody's nice and we don't have to do that.

JASON: I want to try that, though, because I want to see how that would work in practice. And my AI experience is honestly very limited.

STEVE: All right. Let's do it.

JASON: So if one wants to do that, I remember I saw it in here. I'll start looking for Open AI. I'm going to go with the standard AI. Where is it? There. OK.

STEVE: So if you scroll up to the top, the Open AI function has a snippet you should probably copy. If you hover over it or command click it, it should open up that Val. Maybe you have to hover over the URL part. Let's see.

JASON: It keeps almost doing it.

STEVE: Yeah. The URL is...

JASON: Slash

STEVE: I'm sorry. Hit escape. Hit command K, like you doing that reminded me, we have a command K bar, we have a search. OpenAI and then scroll down. Yeah, there it is. Copy everything but the import here, and then, go back to where we were.

JASON: OK. And then, I want this to be in here, right?

STEVE: I think it might make more sense to create an if spam function.

JASON: That makes sense. I like that. Let's do that. We'll create a function up here called if spam, and that's going to take our input and OK, inside here, we've got our OpenAI, messages roll user content and we're going to say something like, I feel like you already figured this out, I'm going to let you tell me what to say.

STEVE: For here, the content of the user in this case will be the input, so you can just complete whatever's here and just and then, copy this whole line and put a line above it. Yep. And we're going to have role of system, this is us telling GPT, you are a spam detector. Let's see, determine if the following is spam or not safe for work. And then, I say, you know, reply only with spam in quotes or safe.


STEVE: And if you go back to the beginning of this line, max tokens, we could say two. We only want one word. The word safe is one token, but the word is two tokens.


STEVE: I learned that one the hard way. Why is it sending me back spa?

JASON: So the function expression, choices zero message content. That's what's actually coming back. So I want to return this. And then, down here.

STEVE: Did you make an async function? I want to weird it's not complaining, but yeah, it should be async.

JASON: Something is complaining, why are you mad?.

STEVE: Yeah, maybe we need to refresh the page. The typescript is a work in progress.

JASON: OK. We're in good shape here, now we've got our is spam. And down here I can say let's see, is safe equals await, is spam, next line

STEVE: I think maybe for debugging purpose, just don't do the equals equals. Let's just deal with the thing it gives us.


STEVE: Just to make sure. Sometimes ChatGPT will go off the rails and it's a little bit... I think the first thing I would recommend trying is adding another column to the database and storing whatever ChatGPT gives us in the database. And then... the screen.

JASON: Will I have to write an alter table.

STEVE: No, create table does not exist, create poem lines two. We'll start with a brand new table.

JASON: OK. And then, we'll we can call it safe. OK. And that means down here, we need to change these to be poem lines to, and poem lines to, and then, we also need the safe. Which, I guess, we should just call this safe, then.

STEVE: Yep. Nice.

JASON: Nice.

STEVE: And get it on the get request and put on the screen.

JASON: Ah, right. Yes. Safe. OK.

STEVE: The one issue with this is yeah, that should work.

JASON: I feel like there was a way, I think this will get flagged by... no! What did I do? I got bugs.

STEVE: Let's go to the logs. I don't know if we played with the logs too much. Yeah.

JASON: Here's my 500. And it says safe is not defined. Oh, no.

STEVE: Online 47.

JASON: On line 47. Oh, right, I didn't destructure it out.

STEVE: And at the top of the file, comment out making the table, that'll speed everything up if we don't make the table every time, or don't try to make a table every time.

JASON: OK. All right. Let's get back into...

STEVE: There we go.

JASON: Hey, look at that. Oh, poopy head was fine. OK. Well, whatever. [ Laughter ]

STEVE: Got the script tag. It knows the script tag is spam.

JASON: It did, that's good. And we can say we can actually update this do say where safe equals safe. And theoretically, that will drop how what?

STEVE: Did you do command enter?

JASON: I thought I did. Oh, am I

STEVE: That looks like it should work. Hmm.

JASON: Where safe equals safe.

STEVE: I guess, one thing that I'm curious about

JASON: Single quotes?

STEVE: Yeah, but I don't know why it wouldn't give you an error.

JASON: That does seem like it should just explode. Now, it works.

STEVE: Yeah. Marquee is safe. That's funny. That's really funny. Well, so, this is pretty cool, though. I like that this is it's doing what we want. And then, we would be able to drop this part out now that we're not displaying any of those anymore.

STEVE: But you still have them in the database, you as an Admin can go see them. [ Laughter ] Let me show you this fun SQLite Admin table thing. So, this kind of gets to the point of like other users in Val Town can make code that basically apps you can install on your own account, it'll run with your SQLite database. And yeah, you can customize them. Hit command K and type SQLite or type, I think explorer is the unique word is what someone explorer. Yeah, that's the one. So Niko is one of our favorite users, he builds a lot of really cool things and this is the app install in your account. So you can hit that button and install nice. And then hit fork. Yeah, that one. And here we are. This is your app. So this is kind of funny. Like Vals are by default. This is a URL. So this app is a website hosted on your Val Town account.

JASON: Right.

STEVE: We need to password protect it. It's all of the SQLite data. The scheme we've come up with, for now, is your we've wrapped it in a password protection middleware and your password in this case is your API token, Val Town API token. That's like the the simple scheme only you can access this Admin panel.

JASON: Got it. If I go to my API tokens, I'll be able to

STEVE: Hit the copy button.

JASON: Copy. And then, if I go back, it's hidden, OK. Cool.

STEVE: Yeah, and then run, yeah, exactly.

JASON: That's pretty slick. I'm worried about scrolling down in case anybody was trying to test that spam. This is great. This is actually wonderful. So I'm able to do something, like, I could insert into I can run any old SQL in here. Which I'm not going to bother writing a whole SQL command, but, like, that's pretty slick you can do that. Or if I want to select like ID and safe from poem lines, I can skip the line itself.

STEVE: Yes, great idea.

JASON: And we can see, like, not a lot of spam coming through, which is great. Ai, this is a cool this is a cool I love little tools like this. I think they're a game changer, especially when you spend so much time. That's amazing it caught that. That's like the Nigerian prince thing.

STEVE: That's good.

JASON: That's better than I expected it to be. It doesn't all right. Cool.

STEVE: Yeah.

JASON: So, then what? Then what happens? We've got an explorer, this is extremely cool. We've got so if I go back to my home

STEVE: I think that's just a temporary, I think if you refresh the page, that'll go away. This is the app, the poem builder. I think it's a pretty good, you know, little demo of stuff. Obviously, you could make it prettier in a bunch of different ways. We could throw on a classless CSS to make it prettier without any effort. Are you familiar with classless CSS frameworks?

JASON: Classless, no?

STEVE: Classless CSS frameworks are CSS frameworks that style HTML all of the links and stuff. You don't have to add classes for it to work. You can throw it into a project.

JASON: I gotcha. OK.

STEVE: We can do that. Here, let me get one classless. Yeah, I think if you do command K and then type classless, it'll pull up this helper function that I made for classless CSS.


STEVE: I don't know. I don't even know if classless CSS is that interesting. But potentially, I think maybe the next thing we could do is a chron. Like a different type of Val that runs on a schedule.

JASON: Yeah, why don't we do that and that would be a way we could let's see, we could we could clear our poem every minute or so so that you kind of get a fresh start every minute. That seems like a pretty simple one, I think. [ Laughter ]

STEVE: Super simple. Yeah, that one we'll be done with that in 3 minutes.

JASON: Which is good because we've got about 15 left. I'm going to

STEVE: OK. Great.

JASON: I'm going to hit the function here and we'll call this one poem killer.

STEVE: Great. [ Laughter ] So I... yeah. Nice. Yes, this is a Dino project. Someone asked in the comments.

JASON: Minimum is 15.

STEVE: If you pay us, you can do faster, but on the free plan, 15 is what you get. So, you type the @ symbol, get yourself your SQLite. And then, SQLite.execute, delete from poem lines. I guess, for this one, I personally feel like it would be more interesting to leave up to keep the data for historical purposes and then, and then in your renderer, you just store like timestamps and filter that way. But whatever, for the purposes of this demo.

JASON: If you had a different idea to do with the chron, I'm up for that.

STEVE: Totally up to you, if you're like not precious about the data, that's fine. Another thing, you can send yourself the current status of the poem every morning by email.

JASON: Oh, yeah, let's do that.

STEVE: That's another one. Yeah, now, we can use that to get the data. Exactly.

JASON: So we'll get everything from poem lines to, where safe equals safe because I don't want whatever the terrible stuff is. And so we'll get const poem equals await. All right. So then, I need to email myself. And it's already going to me. So I can set a subject of current status of the poem. And then, text will it does text respect line breaks?

STEVE: Yes, I think so.

JASON: If I just did poem rows dot let's see, let's do this. Line.

STEVE: Yeah, nice.

JASON: We'll do poem, rows dot map.

STEVE: Join. I think just join, new line.

JASON: Isn't that oh, and OK

STEVE: You're right.

JASON: An array, it's going to be an array of arrays, and so, then I would need like SQL map, we'll get the line we'll return the line. And then, we'll join all of that with a line break. And that should, I think, oh, right, this needs to be wrapped in, oh, damn it, one of those. There we go. So that, theoretically, every day will send me the current status of the poem.


JASON: Every 15 minutes, I guess.

STEVE: Maybe change it to a chron express that we'll send it to every morning. Or you could make it, yeah, go back and change it from every 15 minutes you can change it to every one day. Next run, 23 hours, and I can say run flow. And if I go look at my email out here... I have current status of the poem.

STEVE: Nice.

JASON: That's pretty slick that you can do that kind of stuff. Like, this is, this is very fun. And I really do like the just the quickness that you can set these things up it feels very. I don't know, I'm seeing possibilities I would have written off as I don't have time. There's that XKCD about automation. You think you're going to do a little bit, but then you spend all of your time doing automation. This feels like, for certain things, especially something like this. This feels like the sort of thing where it really does save me time because this took me 10 lines of code. And I get some update of what's happening in a database. I didn't have to write a dashboard, didn't have to figure any of that out, not managing credentials, it all just works. Good stuff.

STEVE: Totally. Thank you. I was thinking we could go through some of the comments and answer some questions folks have or, you know, build in the direction people have. I don't have that much time.

JASON: Yeah, we've got about ten minutes, that's a great idea. Chat, if you have questions, please, hit us up. So we've talked about this a bit, but Val is built on top of Dino, which is why we've got the URL imports. Vinny wants to know, you got a dark mode?

STEVE: We do. We do. We're built on, we use tailwind for styling and it's cool library. I forget its name that automatically converts your tail wind to dark. So things work pretty well.

JASON: There it is. OK. We've got excitement from the from the dark mode.

STEVE: We have emax and key bindings for those that partake.

JASON: No, you can't have my API keys. [ Laughter ] Can you pull in libraries Val Town doesn't include?

STEVE: Yeah, everything in NPM that's Dino compatible, which is 90% of NPM works or just any URL with JavaScript works. So and we convert, when you import from a Val, another Val, another user's Val, or library Val, we convert that @ symbol import thing to a URL. So yeah, maybe go copy and paste on line two, or any of the lines with import, copy that URL into the URL bar so people can see, it's really fun, like the future of JavaScript is these web standard imports.

JASON: What happened just now?

STEVE: You may have command clicked and redirected.

JASON: I did command click.

STEVE: If you command click, it'll redirect you to the Val, which is nice. In this case, I want to show you what's behind the Val when you do an import, so maybe go back and then like copy and paste it into the URL bar so people can see what like http style imports are really simple. Just pop that open into a tab. Any code that you can get hosted on a website you can import to Val Town and run in Val Town.

JASON: You can run this off GitHub gist.

STEVE: Exactly. You can import code from Val Town on the client side, too, you can write your React component and have the component render on the server and import it on the other client and then do client hydration. Kind of like Next.js, without syntax.

JASON: Very, very cool. Chat got their wish and I did absolutely show an API key, I'm going to recycle that while I'm where was it?

STEVE: Which one?

JASON: Oh, you pasted it

JASON: Yeah. [ Laughter ] How about that, chat? No API tokens for you. [ Laughter ] No, that's great, though. That's really fun. Question about cold start times.

STEVE: Yeah. So the short answer is Val Town is the fastest in the world at deploying your code but we're not the fastest at running your code. There are tradeoffs. We chose iteration speed over deployment speed. When you're using Val Town the product, it's fast as possibly be, 100 milliseconds to deploy. But Val Town will be have some cold start times. The nuance is to when and why that can get into in a second. And in general, will be like 100 milliseconds or so slower than Dino or AWSM or whatever. We're doing our own thing, we're a small startup and we haven't had the time to dial that in yet.

JASON: OK. Cool. And I think the followup question there is, like, in what are we expecting in terms of delays? I feel like I hear people talk about cold start times. And I know that there's, to me, I've never seen this, but people will talk about, yeah, you can get a 10 second cold start time on AWS lambda. I've never seen 10 seconds. What are you seeing in terms of cold starts?

STEVE: Yeah, if you're just evaluating with no dependencies, there's no cold start, our servers are hot, ready to go, running your code. If you have a your code has a lot of dependencies and hasn't been running in a long time, the cold start will take as long as it takes for us to download all of the dependencies.

JASON: And that depends on where those dependencies are hosted because of the dependencies have cold starts, for example, if you were doing something I don't know why anybody would do this, but I've done this myself, where you are serving code from a serverless function that returns the code as text because for some reason you thought it would be proxy that sort of thing. And then, that has a cold start time, you can cause yourself a lot of cascading problems. [ Laughter ]

OK. Cool. So this is pretty awesome. So we are coming up on the end here. So, let's spend the if we get any other questions, we'll answer those. But if not, where should somebody go if they want to learn more?

STEVE: is the URL. And sign up and play around is the the main recommended way to learn more. If you log out, incognito window, that's what it looks like. Log in GitHub or email and password. Docs are pretty good. We have very active and friendly Discord community. We like to shock people with how fast and responsive we are. On Discord and Twitter. We'll reply within minutes or hours and if you ask for a bug to fix, we'll fix it. Minutes or hours, we pay attention to feature requests very carefully. So, we're easy to get in touch with.

JASON: Got it. Got it. Let me throw a couple of these on the screen. This is the website,, Discord, go to the bottom because it's one of those hard to pronounce sorts of things. But then, there's also the website here. Of / Steve, this is fun, this is cool stuff. Like I said, I started this out by saying that I've always struggled with these sorts of things because it's hard to see how they fit into my workflow. Actually going through this today, I can see a lot of ways this would fit into my workflow. So consider me a believer.

STEVE: Love it. Thank you. It's so fun.

JASON: Let me throw one more link over toward you where if you want to go follow Steve, you know, harass him, ask him how long since that photo's been taken because his hair looks lot longer. [ Laughter ] And one more shout out to our sponsors. So this episode like every episode has been live captioned. We've had Diane with us all day. Let me get that link back up on the stream there. And, that's made possible through the support of our sponsors, NX and Netlify and some day I'm going to update my website to I mean, I love Vets Who Code, but they're not sponsoring anymore. Go check out NX, Netlify, give them some love, tell them I sent you. Steve, any parting words for the chat before we call this one done?

STEVE: Thanks. I just want to say thanks for spending time with us. This has been really fun.

JASON: I appreciate you taking the time. This has been an absolute blast. Chat, make sure that you are checking things out on the site. Next week, I'm in London. If you're in London, I'm going to be at City JS. I'll be there all week. If you're in the area, definitely hit me up. Otherwise, we will be back the following week with an episode, we're going to have senil on the show. I'm going to update this, I promise. There's more coming but we are having Senil Pai back on. We're going to learn about the new next run time on Netlify. We're going to learn about the astroDB on data stacks. Make sure you keep your eyes peeled, join the newsletter, join the Discord, like, subscribe, do all the things, you can join for a few bucks, I reinvest that into the content. And with that, we're going to call this one done. Thank you all very much, Steve, thank you for spending time with us today, and we will see you all next time.

Closed captioning and more are made possible by our sponsors: