Vue 3, Hasura, and Serverless Functions
with Ben Hong
You can build "full stack" apps without becoming an expert in backend tech! In this episode, Ben Hong will teach us how Vue, Hasura, and Netlify Functions combine to powerful apps!
Resources & Links
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). 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 LENGSTORF: Hello, everyone, and welcome to another episode of "Learn with Jason." Today on the show, we're bringing back the one and only Ben Hong. Ben, how are you doing?
BEN HONG: Hello, doing good, glad to be back.
JASON LENGSTORF: Happy to have you back. You're looking sharp. You got a new camera?
BEN HONG: I've been using the Logitech for so long, now I got the cool angle down, working on that, looks like I'm slightly off center. There we go, this is better.
JASON LENGSTORF: This is like my forever problem. Should I scoot? Wait, which way, no, this is the right spot. I am also doing something new today. I trimmed my beard for the first time in like a year, so, as everyone can see, look, chat, I have a neck.
BEN HONG: Looking very sharp, looking very sharp.
JASON LENGSTORF: I also have something that I'm so excited, you're going to appreciate this. I got the most frivolous thing that I think we have in our house, Marissa for Christmas, got me a hot chocolate velvetizer.
BEN HONG: Get out.
JASON LENGSTORF: Which is a single-purpose, like, home appliance that lets me make very frothy hot chocolate.
BEN HONG: That is very Portland of you.
JASON LENGSTORF: It's absolutely delicious. You can just see -- can't really see it, but look at this beautiful froth, you see that? It's scrumptious.
BEN HONG: I expect some Instagram art of your hot chocolate art.
JASON LENGSTORF: Some day I'll learn it. Chat, what's the most ridiculous thing that you've ever purchased that brings you endless amounts of joy? Mine is a hot chocolate velvetizer. Ben, what's in your house that makes you happy?
BEN HONG: I have so many tech gadgets. Random things. I'm looking at my shelf here. Clearly, I have lots of random nerd gizmo behind me. Gosh, yeah, I can't think of the one -- you know, I am actually really happy, though, we did get a bidet for our apartment. I'm very happy with it.
JASON LENGSTORF: You know, I spent some time in Japan, and while we were there, every single apartment we stayed in had a robot toilet, and I'm honestly, we were going to get one right before the pandemic hit, and we're still not quite to the point where we want to do voluntary work on the house with external contractors, but as soon as it's safe, I'm getting that robot toilet. It's going to be wonderful.
BEN HONG: Yeah, we got it right before the pandemic hit. Perfect timing.
JASON LENGSTORF: Beautiful, beautiful. Moon lander, what's a moon lander? I wonder what that is. A keyboard. Yeah, I got a drop-alt because of Cassidy.
BEN HONG: Yep. Mine is in the other room.
JASON LENGSTORF: Lots of keyboards in the chat. Got ya. Okay, so, Ben, for those who are meeting you for the first time, do you want to give us a little bit of a background on yourself?
BEN HONG: Yeah, absolutely. For those who don't know, I work at Netlify with Jason as a senior developer, experienced engineer, so I get to do the fun things, particularly in the Vue area, for those who don't know, Vue core team, primarily do a lot of docs work with Sara, Natalia, along with other people that make the docs what they are, so shout-out to them for all the hard work that they do.
JASON LENGSTORF: Awesome. I see Cassidy, thank you so much for the sub, I see Angie is in the chat. We're about to get drowned in boops, so I guess get ready for that. Yeah, we said keyboards three times, and now Cassidy is here.
BEN HONG: Yes, that's how it works. Although the new thing might be walnuts warehouse, walnuts warehouse five times, maybe she'll appear in person, who knows.
JASON LENGSTORF: Appear in person, Cassidy is going to bust through my office door. All right. Thank you for the sub, I very much appreciate it. Make sure you spam those boops. It's a good old time. Okay, so, focusing up, so, you work on the Vue core team, we both work at Netlify, and one of the things that I feel like we get asked about a lot, like a lot, is how do I build app-like experiences in the jam stack, like the Netlify-dependent pipeline. So, I think maybe the first question would be where do you think that -- where do you think that line exists for maybe just in general, or kind of for you, what changes something from a website to an app, in your mind?
BEN HONG: I think when it comes from website to application, sounds like the data layer, because it you're just rendering static content, and there's nothing dynamic about it, I think that's where most of us grew up with the proverbial website, right, for reading and seeing things, but the moment you start to have to layer any sort of dynamic aspect to it, actually, maybe it's more of a static versus dynamic. If it's just a block post that you're reading, but, for example, even if you don't have a backend, if you have a website with a calculator application that calculates taxes based on what you input, at that point you're in application realm -- oh, my gosh, we're getting buried.
JASON LENGSTORF: We have what coordinated boop attack.
BEN HONG: Clearly.
JASON LENGSTORF: It's a de-DOS in the sense it's a denial of screen attack. Yes, thank you, all, for booping so hard that no one can find us.
BEN HONG: I can peek out over the edge. What about you, Jason, what do you think about apps and websites?
JASON LENGSTORF: For me, where the division starts to come in, is when people talk about websites, they are thinking about pages of content. (Laughing). It's so hard to be serious.
BEN HONG: I feel like a little kid in the ball playground. Joy yeah, like being in the ball pit when you're a kid, but having a serious conversation in the ball pit. Listen, you're floating, just your face above the balls. Hey, so, mom, I want to talk about bedtime, you know, like let's -- I'm a big kid now. That's how I feel whenever the screen is full of boops. Anyways, so, for me, I think the division really comes in when you move beyond displaying content and starting making things interactive. So, if we are looking at something where it's not just a form I submit, but a button I click that causes something else to happen and then that changes the state of the screen, then it starts -- at that point it starts to feel like an app.
BEN HONG: Yeah.
JASON LENGSTORF: I think for a lot of folks, that starts to -- you start to ask, well, can I do that with, like, create React app, or do I need a server at that point? When have I hit the point where I can't do what I want to do with just the front end like I'm talking about? And, so, maybe a good place to start there is what -- does that boundary exist? Is there a place where you go, you know what, I can't build this without a server?
BEN HONG: I mean, it gets to the point, especially when you're trying to scale, right, you want to share data between devices and there's no longer an isolated application, again, if you're just running some numbers on calculating the tip total for your bill between four friends, that's not something you need to necessarily share, but the moment you want to concurrently all four friends are logged into the app at the same time and enter in their order, I think that's where once you scale beyond the individual, that's where the server starts to step in.
JASON LENGSTORF: Yeah, I think, yeah, that's a good point, when you're now starting to coordinate things between multiple devices or multiple experiences. You have a mobile app and a web app and all that stuff. Now you're starting to look, but here's one thing that I find interesting, is a lot of times building a server does not mean that you have to change the way that you build your website, right, so when you're talking about the jam stack, you're building a front end, but really the only thing that makes a jam stack site jam stack is the front end is de-coupled. You're still making calls to APIs, still use serverless functions, client-side stuff, single-page app-style routing. So, if I build my only API, and the de-coupled front end calls to that API, am I still building a Jamstack site?
BEN HONG: The key thing is de-coupled. That's the key word that you mentioned. Cassidy had a great analogy. We think of mobile apps, the fact if we package things on the UI side, that's what you download, but when you're fetching the data, that's a separate piece, you're not downloading in advance when installing apps. If you think about Jamstack like that, the UI side versus the data layer.
JASON LENGSTORF: Yeah, and I feel like that was the light bulb moment for me when I started using this approach. I realized, at first I thought that Jamstack was only -- thank you for the host, most appreciated. So that means if I'm building a website, I can only talk to software as a service platforms, or third-party APIs. And then the light bulb moment was when I realized, wait, I can build my own API and call that the same way that I call, you know, the GitHub API or the Shopify API, or any of the other things that I'm using. We're building the same things, but through this de-coupling, I can still host my website as a static thing, but I can have this super dynamic API, and the API gets simpler, because now the API deals with data and not turning data into rendered markup. So, we're removing a lot of complexity, putting this strict de-coupled barrier between our front-end and back-end services, and we're able to do all the things we were doing before, but it's simpler to deploy and manage, and that's what we want to look at today. We're going to see how we can build one of these custom APIs and de-coupled front end on top of it.
BEN HONG: Absolutely.
JASON LENGSTORF: So, let's talk about what that looks like. You mentioned you're on the Vue core team. If you're going to build an app, where do you start? We'll start in the abstract and then build some code. So, what are you talking about when looking at a stack like this.
JASON LENGSTORF: Okay, cool. So, for today, I think what we're going to do, what did you want to build today?
BEN HONG: Yeah, so, I think we're going to take a look back, for those that follow along, we built this thing in Vue 3, where we had a wish list with sort of nostalgic toys. So, what we want to do is submit that up to the database and basically have a form where people can add sort of their nostalgic toys that they liked and if we have time, do up-voting and that kind of thing and create a shared experience. Right now, everything we have is a static local thing that we do just right on the machine.
JASON LENGSTORF: This emoji --
BEN HONG: That's what I'm looking at.
JASON LENGSTORF: Now I'm kind of thinking, how do I make one of those?
BEN HONG: I was going to say, where's that coming from?
JASON LENGSTORF: I love it. Very good stuff. Okay, cool. Let's do that then. So, I'm going to switch us over into pair programming mode, and before we get too far down the road, let's do a quick shout-out to the sponsors. We have live captioning today, like we do every day, and that is provided by White Coat Captioning. We've got Ashly with us today. Thank you so much, Ashly. And there it is. And, so, if you want to follow along, that is right on the home page of the site, it is there every week, and you can go and check that out. That is made possible through the generous support of our sponsors. We've got Netlify, Fauna, Auth0, and Hasura all kicking in to make this show more accessible to more people. It means a lot to me, and I'm really, really happy you are all here, so thank you so much for your support. All these on the home page are linked, you can click on one, give it a try. So, also, while you're clicking on things on the Internet, go and click on the follow button for Ben's Twitter, Bencodezen. Great information, a lot of Vue insights, and this just unbelievable Harry Potter stuff. This is so good. You are a, I believe, a nationally ranked quidditch player, right?
BEN HONG: That's right, actually. I do -- I'm a chaser, that's my role on the team.
JASON LENGSTORF: Nice, nice, nice. I don't know if you're joking, and I don't care. I'm so happy.
BEN HONG: Harry Potter fans know what I'm talking about.
JASON LENGSTORF: So, today we're going to be working with Vue 3, so, let's look at the Vue 3 docs.
BEN HONG: Yeah, haven't fully migrated yet.
JASON LENGSTORF: Nice, nice, and we're also going to be working with a little bit of Hasura, and we're going to be working with Netlify Functions. So, here's just some links, go and check those out, but don't worry about it too much. And then let's also find here on the site where we started from. So, I'm going to go here, and I'm going to search for Ben, so that we can learn. This is where we started, so let's go take a look at this demo. This is where we were, right, we've got -- we did some reactive things, then we also put this, like, search in. So, we can search now for things, and then we can wish for it, and all of that stuff, that's all good. But the problem is, if we refresh the page, they disappear. We don't keep our state.
BEN HONG: Yes.
JASON LENGSTORF: So, today, we want to turn this into an app and persist this state. So, let's -- what's our first step? I guess I should probably get the code first.
BEN HONG: We'll want to create a new one, that's been our policy thus far.
JASON LENGSTORF: Let's do it. I'm going to fork this -- no, I'm not. I'm going to clone this and create a new one. I'm breaking Git rules. Why would you do that? Don't do that. GitHub repo clone, and it's going to be this one, and we're going to put it into -- what did we call this episode?
BEN HONG: It's a long one. "Vue 3, Hasura, and Serverless Functions."
JASON LENGSTORF: How about that, Vue, Hasura, serverless.
BEN HONG: Sounds great to me.
JASON LENGSTORF: We're going to go into it, I'm going to remove the .Git folder, so we get a new history. And then let's open this thing up. Get this on the right screen. And we need to install everything. Npm install. Do we use npm?
BEN HONG: Yes, we did.
JASON LENGSTORF: All right. So, once this is up and running, we're going to be payable to just run.
BEN HONG: Yep.
JASON LENGSTORF: And we're using the Vue cli. Check this out, if you have not already tried this, it is so cool. The Vue cli is such a powerful tool. Go and check out this episode. Was it this episode or the other one?
BEN HONG: I think it was the other one I demoed to you, because it was like a mind-blown moment for you. I think it was the first one.
JASON LENGSTORF: I think this was the one, where we talk about the Vue 3cli, and it's like, holy crap, is that a cool setup. Here's the link to that, you can check that out. Make sure to check out all the episodes here, because it will show you how we got to where we are. Here's the composition API link, as well. This will all end up in the show notes, too, so you can stick that up. As a fan of the saga, yes, absolutely. I like this has become a saga, I'm into it.
BEN HONG: It really has.
JASON LENGSTORF: So, now that we have everything installed, I should be able to npm run serve.
BEN HONG: Yep.
JASON LENGSTORF: And let's get this thing up and running. I was going to multitask, but I realized I was prioritizing hot chocolate over opening the link.
BEN HONG: I can't fault you for that. I would have done the same thing.
JASON LENGSTORF: We're here, this is our app, this is running locally. So, let's look at the source code and refresh ourselves, mostly me, on what's actually happening. Okay, so, I have a main.js, and my main.js imports app, creates an app, and mounts it to this app, div, which is out here. There's our div. So, that's our React app. I got that. App.Vue has a countercomponent and wish list component, which we're importing from individual component files. And this just has some styles in it, okay, that all makes sense. Let's look at counter, that's the simpler one, heading, paragraph and button, and we set up a custom hook, which I like, or a hook feature, composition API.
BEN HONG: I call it a feature. People say composables, but features is cleaner.
JASON LENGSTORF: Similar to the custom React hook thing, so this will look familiar. Definitely looks approachable for me coming from that world. If we look at that feature, we've got a Reactive state. This is kind of a new thing to me. Reactive anything, we're registering something, but we're setting it up to be observable, so that it can notify other parts of our app if anything changes. That's correct? Then in our wish list, this is where we're going to be mostly working today. We have a list of our holiday items, our search filter, a list of the items themselves. We're using the reactive part again so we can do a list of our gifts, our gift list. And then we have the search text, and whenever someone changes the search text, we are filtering our gift list to include only what is in the search text.
BEN HONG: Yep.
JASON LENGSTORF: Okay. And then we have this add wish, which lets us update that count. That's what happens when we click the button here. Wish, wish, wish. Bump, bump, bump. And then we pull that out, we make all of that reactive, and we add this function to make this wishable, so we can then use it. So, here's where we add the wish, sort through the gifts in the gift list, and the gift here as a label, an image, and the number of wishes that belong to it. Okay, so, that all makes sense. So, the next thing then that we want to figure out -- did we actually do this part?
BEN HONG: So, we started scaffolding some of the add load votes, I believe. We opened up those serverless functions.
JASON LENGSTORF: Let's see, we said add votes. What up, chat? Page not found. Oh, no, my sound effects. Yeah, the sound effects are definitely busted. I have a to-do item to fix that, but in the meantime what you can do, these all run from code. So, if you go to GitHub.com, learnwithJason, there is a folder full of serverless functions, and almost all of these you can run. You know, here's the ahem that everybody was just reminding me to look at the thing. And the rest of these, you know, hey, what if we just want to add some code, right, we can run code. So, if you want to look at this, there's your whole list of sound effects. And if somebody remembers how to update the commands, I think, Tony, you might remember, you can change that link out to be just a link to the functions folder. But, yeah, I think they are all set up on serverless functions now, so maybe they don't actually do -- how does all that work? You know, it's been a long time since we built that. It was a long episode. Anyways, it will get fixed immediately, but for the meantime, snoop on the source code. In the meantime, fork one of these and troll the heck out of us, y'all. So, anyways, that's that. I guess I'll keep that up and link it in the notes. So, okay, so we started working on our functions. And this went to Hasura. Dang, did we get a whole Hasura thing set up even?
BEN HONG: No, we were in the midst of doing that, and then Hasura, it wasn't loading correctly.
JASON LENGSTORF: Okay.
BEN HONG: We were close, but, again, I still think it's probably worth sort of, yeah, making sure we walk through all that. At the time, yeah, Linda is saying Hasura was having issues that day. So, we never actually got to that point.
JASON LENGSTORF: Okay, cool. Where we are right now then is we have serverless function. So, chat, the way that serverless functions work is maybe we can kind of mock some of this out. If I want to write a basic serverless function, what should I do here? What's my format for a kind of baseline serverless function?
BEN HONG: Well, the first thing, it's going to be run in node, so we don't do the typical export default that I think we're used to in ES6, so this is where the modules.export comes from, because we have to write a handler function, if I'm not mistaken.
JASON LENGSTORF: Yeah, we have a named handler.
BEN HONG: Export.handler, uh-huh. That can be a function that receives, I believe, two parameters, which is I want to say event and context, but I might be slightly off.
JASON LENGSTORF: That's right. And does this need to be async or anything?
BEN HONG: I think usually I do find it, but I'm not -- yes, I believe it does.
JASON LENGSTORF: I'll jump in with a little more context. If we don't make it async, we have to use a call back, which comes in as the third parameter. Then you do call back, status code, a body of 200, and okay or whatever. And this is fine, and there are reasons this is the preferable way to go, because you can put it in a call back, nest it in a "promise but then," but in a lot of cases, it's nicer to not have to do that, and instead we make it async and return our status code.
BEN HONG: Yeah.
JASON LENGSTORF: So, what should our hello function say? If we give it an HTTP status code of 200, that's going to show it's okay, and the body is going to be what it says back.
BEN HONG: We could say, "I love hot chocolate."
JASON LENGSTORF: Yes, we do. So, now we have a serverless function. We're not really using the event or the context, so, in this particular function I'm going to leave them out entirely. And then I'm going to come back out here, and instead of running the npm command, because we're doing Netlify Functions now, I'm going to run Netlify dev.
BEN HONG: Yep.
JASON LENGSTORF: So, check this out. You see how it detected -- wait, go back. Okay, fine. Anyways, it's running and it's now booted at local host 8888. And if we look at what's down here, we can see that the Vue CLI built, and also way up above all of this, is an output about the serverless -- a serverless server, a lambda server. But if you notice, this, 8080, is what Vue is doing, and Netlify dev is running at local host 8888. And the reason for that is now we have access to local functions. So, we can run Netlify hello, and now it says, "I love hot chocolate," and if we change it, for local development, this is amazing. It's so, so --
BEN HONG: So good.
JASON LENGSTORF: But, yeah, now that we have that, kind of our basic setup here, we can look at what happens inside of one of these. So, if we're going to load votes, we have our exports.handler, and then we're going to send off a request. We need to set this up, so it's actually there. But then we're able to just kind of return some data. What do you want to do first? Should we mock data, or do you want to set up Hasura first, what seems like the right way to --
BEN HONG: You know what, I think to show people working A to B list, mock the data first to show them what that's like to call it, and then we can kind of go from there.
JASON LENGSTORF: Yeah. So, let's do, let's see, we can do it like this. We can get Hasura request -- how can we mock this in a way that would kind of make --
BEN HONG: I guess to your point, we would need to pass in -- still posting the ID anyways. Need a reference. So, maybe, you know what, maybe we should go to the Hasura part. That way it's at least --
JASON LENGSTORF: Yeah, yeah, we would spend a lot of time trying to --
BEN HONG: I think so.
JASON LENGSTORF: -- to mock the data. Okay, that's cool. Fine, fine. Let's do -- we're going to go to Hasura, get started for free. I'm not only their president, I'm also a member. I can start a new project here. Let's see if we can make -- actually --
BEN HONG: Oh, it's right there. We tried to set up.
JASON LENGSTORF: Let's look at what we've done here and see if maybe --
BEN HONG: I think the console crashed. I vaguely remember this.
JASON LENGSTORF: Okay, so, we're okay.
BEN HONG: We have votes.
JASON LENGSTORF: We have votes. Our votes have an ID and a number of votes. Hey, look, we did more than I thought we did.
BEN HONG: We tried. I guess it finally registered.
JASON LENGSTORF: So, in our source code here, we've got our wish list, and our wish list has our gifts. Where is our gift public data JSON? So, let's look in here. Here's our IDs. Good, and what we're doing is we're starting with zero and then throwing in a number of votes. So, when we load the votes, this is going to --
BEN HONG: Pass an ID and get the votes.
JASON LENGSTORF: Okay, so, the thing that we will need is we need that secret. So, I'm going to pull this off screen so I can grab it. Let's see if I can do this in a way that is -- can I copy/paste it like that? That would be great. I can. Check this out. This is handy, I think this is new. They have my admin secret right here. I can just copy it.
BEN HONG: I'm so glad more places are doing that.
JASON LENGSTORF: Really, really handy. The other thing I can do is I can go to -- and we'll start here with a new file. I'm going to call it .env. I'm going to -- what am I going to call this? Hasura Admin Secret, then another one for the Hasura URL. An Hasura URL is going to be the one that shows up here. So, this is our actual URL. So, I can just copy/paste that right in. And up here I'm going to get the admin secret, copy that, and I'm going to paste it here, so we'll be off screen so hooligans don't stop the magic. So, watch this, I'm going to stop the server, re-run it, and look, it's there! It immediately picked that up. This is my favorite thing. You can see the function server is running.
BEN HONG: Another thing I love about the Netlify CLI, Linda, you said your team is looking into it. If you have -- it will pull it down, so you don't have to manually copy/clone. So good to have that.
JASON LENGSTORF: Really, really nice. But, yeah, so what we're able to do here now is we're able to actually run live tests with adding votes. So, what we're looking at is pulling out the ID from the body. So, why don't we do one of my favorite things, fire up postman and send some requests and see if we can create some votes.
BEN HONG: Sounds great.
JASON LENGSTORF: While we're waiting for Postman, I'm going to the data JSON. Let's add votes, what do you think, chat, what's your favorite toy, what do you want to vote for? Tamagotchi, let's get it. And what we're going to do, I'll deal with that later. I'm going to create a new request and we're going right to our local host, 8888, and in this case, we'll change it to add votes. Add vote or add votes?
BEN HONG: Maybe should be singular.
JASON LENGSTORF: Probably should be singular.
BEN HONG: Feels like it should be singular.
JASON LENGSTORF: I'm going to change that. Because I changed the name of the file, I'm going to stop and restart. Then that means I can go here and add a vote. In my body, I'm going to send it as -- what are we expecting -- here then we can send body, raw, JSON, and then we can do ID like that. I think that's it, right? Don't want to do that. So, they should get our ID out, and what this should do under the hood is uses the Hasura request library, and we're going to send a GraphQL query and variables to it. So, the variables is the ID that we sent it. That's the only variable we need. And this particular setting here is going to use the primary key column of ID and increment the votes by one. Does that make sense to everybody? This is a little bit wild. You hackers, you dirty hackers.
JASON LENGSTORF: Who's hacking? Nobody's hacking. Okay. Actually, am I being hacked as that's happening right now?
BEN HONG: Everything looks normal.
JASON LENGSTORF: So, let's look at the Hasura thing, because I think it's kind of cool. All we really need is a fetch request. So, in here, we use the fetch API, which is the same in the browser, we're using node fetch for a serverless function. Send it as a post request, admin secret as a header, and pass in the query and variables as a JSON, and we get back a result. So, we can check whether or not there's an error, and if that's the case, return an empty array. Otherwise, we return some data. That's that, right, isn't that great? So, what I like about this, for a simple app like this, if I was setting up just this, I needed to track votes, then I don't have to get into a GraphQL library to run my one query. As soon as I get more advanced, though, then it starts to make sense to bring in Apollo or Urkel, because what will happen is these aren't being de-duplicated or anything, which I don't care about if I'm mutating, but if I was listing one product, modify a product, I want a local cache to I can make things fast, and Apollo and Urkel are, like, built for that. Yeah, this is a really nice, clean setup that is one dependency and node fetch is like a teeny tiny baby dependency with no dependencies of its own. So, it doesn't add very much to your bundle and the overhead to use it is super low. So, now that we've got this, what happens? We send off this request, everything is good. So, let's just try it.
BEN HONG: Try it.
JASON LENGSTORF: Here we go. I'm sending. I have sent the request, and nothing came back, which means something went wrong, which means -- I know what it was, I know what it was. We didn't send the header. Wait, it should have been there.
BEN HONG: That's what I thought. Hmmm.
JASON LENGSTORF: What cannot you like?
BEN HONG: Votes by PK. Is it the item doesn't exist yet?
JASON LENGSTORF: Was this the one, the Tamagotchi? That's actually a great question. Let's see if it needs to exist. So, I'm going to find in our data the Tamagotchi, and let's add it here. Actually, I think this is -- whoops, I think that's the case, we didn't actually add it. So, we're going to put in an ID and give it a default of zero. Okay, so then if I go look at my data, here it is. All good. So, let's run this one more time.
BEN HONG: Try again.
JASON LENGSTORF: Nothing. What have we done wrong?
BEN HONG: What do the headers say? What's up, Chris?
JASON LENGSTORF: Hey, Chris, how are you doing? What are we doing wrong, what's happening?
BEN HONG: Something funny.
JASON LENGSTORF: Sending the wrong stuff? No, this was all right. What don't you like? No such type exists in the schema, text.
BEN HONG: Oh.
JASON LENGSTORF: Oh, I wonder if we just screwed up our query. Text, sure did. So, what is our type? Let's go look here. Go to graphical, and then I'm going to click on this one, and we're going to look at ID, and does it say what type it is? String. That makes sense. Text isn't a real thing. Try one more time?
BEN HONG: Try that once more.
JASON LENGSTORF: Once more with feeling.
BEN HONG: Ba-tow, yes, very good!
JASON LENGSTORF: Okay, now that we've got this, if we go back to our data, actually, we can just query these. Let's get our data and our votes, query, and we can see here, there is our Tamagotchi, and it's got one vote. Hooray! If I run it again?
BEN HONG: Awesome. Bam, persistent data.
JASON LENGSTORF: All right, now we're persisting data. Then we need to query for data, which I think we may have already written.
BEN HONG: We did. Load the votes.
JASON LENGSTORF: Good. If I load this in the browser, we should be able to see it immediately. Netlify Functions -- Woofta, that's exciting.
BEN HONG: First time I've seen that one. Hold my bucket! (Laughing).
JASON LENGSTORF: I forgot that one existed.
BEN HONG: I need a copy of that one.
JASON LENGSTORF: Oh, man, I'm so glad we're digging into the archive of sound effects. I'm out of hot chocolate.
BEN HONG: That's very sad.
JASON LENGSTORF: Okay, out of hot chocolate, I guess I'll do code. Okay, so, we're able to load the votes, so now we need to get into the app. One more thing that I want to try, I want to see now that we've got the format set up properly, I want to see if we tried to vote for something --
BEN HONG: That's right. Will it automatically add it?
JASON LENGSTORF: Yeah, because I'm curious if that's going to do what we want. So, let's give it a shot.
BEN HONG: If we're thinking about, unless we set default to zero, would it actually?
JASON LENGSTORF: This means it's not going to work.
BEN HONG: If we refresh our Hasura instance --
JASON LENGSTORF: Yeah, nothing changes. So, we would need --
BEN HONG: -- can't increment.
JASON LENGSTORF: I wonder if we could just make that work. We could do like an insert votes one, and we could do like the ID. And then on conflict, can I -- oh, if I could make that happen. No, that's not going to work. Okay.
BEN HONG: Null? Tricky.
JASON LENGSTORF: I can't make it, okay, that's fine. We'll have to do a round of inserting all the votes. That's okay because to do that, we can do an array of votes and IDs here. Which means I can take all of these. And let's move over to a new file, so that I can delete everything. No, not like that. Like this. I can take my label --
BEN HONG: Multi-cursor for the win, magic.
JASON LENGSTORF: Okay, so, now I've got this, I can do this. Will you stop arguing for me? Oh, okay --
BEN HONG: Prefix it with ID? Oh, the underscore?
JASON LENGSTORF: I think I just need to not do the quotes. GraphQL query, not an other thingy. Not JSON is the word I was looking for.
BEN HONG: You mean not you, got it.
JASON LENGSTORF: Not me.
BEN HONG: That will never die.
JASON LENGSTORF: So, try that, there we go. That's happy now. Then what I can do, on conflict, I can say constraints, primary key, update the ID, and whatever, that's fine. So then we can run my mutation. Look at that.
BEN HONG: So cool.
JASON LENGSTORF: Kept our data, too, which is the most important thing that happened. We basically did a merge. But now we have all of our products in here. So, when we go to run these, we'll be able to load all of our data, and when we go to add a vote, it will just work. So, let's --
BEN HONG: Let's do it.
JASON LENGSTORF: Now let's go back into our code here, and I want to do a clean up -- let's map this out. In order to do this, we need to -- let's set up a new to do here. So, to do -- if I can type -- one, we need to load vote from Hasura, then we need to merge votes into the gift list, and then we need to update add wish list to Hasura. That's going to be the guts of our app, right, that's basically what we need?
BEN HONG: Yep, that sounds good to me.
JASON LENGSTORF: Okay. So, first and foremost, to load this, we know how to do that. We're going to call our function.
BEN HONG: That we are.
JASON LENGSTORF: So, if I have my function here, and I'm just going to use the relative, where would I actually request this?
BEN HONG: Yeah, so, let's talk about this. So, right now we're in the setup function, right, so this is what I think life cycle would make the most sense. I think something like before mount, right, before the component mounts, we want to fire off the API key. So, if we scroll up to the top where we're importing the things from Vue, we're going to import a life cycle hook, because we're in composition API. So, you'll see all the life cycle hooks in Vue are prefixed with the on, so that's clear that's what that is. So, now that we have that, we can go inside the setup function.
JASON LENGSTORF: Inside.
BEN HONG: Yep, because everything is in here. Declare state, leave that at the top, and right down here, add a new line, and go ahead and run the onBeforeMount, and it will take a callback function. So, in here is where whatever we want to run before the component mount is, so we can run the fetch on our relative, and then, yeah, we can either log or just do the things to make sure everything is good.
JASON LENGSTORF: This will be our votes, and for now we can console log our votes. Is it still running?
BEN HONG: I believe --
JASON LENGSTORF: I need to make this async. Is that okay, I can just do that?
BEN HONG: That should be fine, I don't think it will be a problem, but if it is, we will learn together. Why doesn't it like res?
JASON LENGSTORF: I screwed up the function.
BEN HONG: Got it, okay.
JASON LENGSTORF: Now that looks like this part is right at least, so assuming everything goes well, not complaining anymore I don't think, I think I made it happy, it's happy. Let's go back out here to the home page. And if we look at the console, we have our votes.
BEN HONG: Ha-za, very good.
JASON LENGSTORF: Beautiful, now we have votes.
BEN HONG: Now we want to override what we have, although that should be fine, yes.
JASON LENGSTORF: What I can do, actually, is I can just straight delete this.
BEN HONG: Yeah, delete them all, that's fine.
JASON LENGSTORF: This will be like our other database. And now we need to -- this is going to break our app, because now we don't have votes. We'll be merging these in, right, so they'll end up replacing it. So, how do I get data from here into here? Or do I put it somewhere else?
BEN HONG: Nope, right after that, we declared our votes that we've got, then we want to do votes -- dot for each, yeah, probably makes the most sense, for every vote. Then we're going to go ahead and do -- basically, we want to look inside of state.giftslist. Because that's what contains our source of truth, that's the reactive object. Basically, we need to for every vote basically update the thing. So -- might not everyone need to add the const.
JASON LENGSTORF: Like that?
BEN HONG: Gift list is an array.
JASON LENGSTORF: Yeah, gift list as an array. We could set --
BEN HONG: I was going to say, votes equals vote.vote. Plural. That's it actually. I think that's it.
JASON LENGSTORF: Do I return it?
BEN HONG: No, that's it. It's a reactive object. Every time you do that, you're going inside the reactive thing, finding it, and updating it.
JASON LENGSTORF: Okay. Doesn't like --
BEN HONG: Why is votes. Not a function?
JASON LENGSTORF: That was a mistake, whatever I just did. Let's console log this one more time.
BEN HONG: Yeah.
JASON LENGSTORF: That's an array. In here, for each of these we should get a vote.
BEN HONG: But why is it not -- function the returns true.
JASON LENGSTORF: It does the first one. Does on before mount have to do something?
BEN HONG: Maybe it just doesn't like this. Okay, in that case -- this is what I don't like about this. That's weird. It's complaining inside of here we've awaited the votes, got it.
JASON LENGSTORF: .ID is not a function. Oh, I'm such a doofas, hold on. Chat, you called this out. That's just me forgetting how code works. But it's not updating our -- it's defaulting to zero. Looks like whatever we're doing is not updating.
BEN HONG: Yep, but it doesn't even exist, though. Vote.votes. We've logged every single one, that's correct. No, the computed is already dependent on gift list.
JASON LENGSTORF: That's true, that's true.
BEN HONG: Why is it not -- we logged it, saw the different ones. We should see some twos, basically, right?
JASON LENGSTORF: What if I do this. Maybe find is making it functional or something.
BEN HONG: Oh, okay, yep, yes. Wait, wait, it's an array. Will that actually work?
JASON LENGSTORF: It should. No, it won't.
BEN HONG: It won't. I think find is correct. Wait a second, the find will return an item inside of an array, right? Let's do the thing where you did const gift.state list.find first, before you modify it. Yeah, Alex beat me to it. That's frustrating if that's the case. We found a proxy, which means we need to unpackage it. Now it's in its ref form. So, we go back to the code. We've unpackaged it. I think gift.value.votes might do the trick. Let's see if that works first. Gift.value.votes. That didn't do it either.
JASON LENGSTORF: Gift.value is undefined. We ran into this last time.
BEN HONG: We did. Yeah, Alex is saying to do the two ref, but then -- let me double check that helper method real quick.
JASON LENGSTORF: Two-ref state, it looked like.
BEN HONG: Yeah, that's when we broke it down. Let me double check real quick. Let's go to the V3 docs, so we can debug together. We're looking --
JASON LENGSTORF: Sounds like a jingle -- (singing) -- we're debugging together.
BEN HONG: K-command to go search. Oh, interesting. Firefox doesn't like it? There we go. ToRef. Yep, that's it, the first one. So, we have this reactive thing, then we want to pull out state Foo. Yeah, that means that we need to wrap our find method in toRef, because it still needs to be a reactive thing, otherwise we've broken the reactivity. Then we'll need to import that, unless yours automatically does that for you.
JASON LENGSTORF: I don't think it is for this one, so let's get toRef.
BEN HONG: Then we need the singular one, as well.
JASON LENGSTORF: Great. This made it look like we have to do the state object and then a key define. Do I need to get the gift list as refs?
BEN HONG: According toRef, we might need to do state.
JASON LENGSTORF: Like this? State gift list, like that?
BEN HONG: That should work. Yep, and then we can do from there, gifts.find.
JASON LENGSTORF: I'm in the absolutely wrong place. Okay. Let me copy/paste that. It was what we wanted. So, I'm going to copy/paste that and roll this out.
BEN HONG: All right, we'll have to take a look.
JASON LENGSTORF: You know what, we did this. This is how we did wish -- so, we can do exactly this.
BEN HONG: That's what I thought.
JASON LENGSTORF: I got a little up in my head about it. So, we're going to do this, but with vote.id. And then we can set, not the value, but the actual votes.
BEN HONG: Might need.value. Yep, uh-huh. Because it's now a ref. If we think of React, you have the U state with the two different ones. Must be --
JASON LENGSTORF: 62?
BEN HONG: Oh, wish list.Vue. Oh, got it.
JASON LENGSTORF: Did I change that code?
BEN HONG: Maybe. Linda is saying we had wishes instead of votes. Did we have wishes instead? Did we miss a naming thing?
JASON LENGSTORF: Well, we have wishes.
BEN HONG: Oh, gift.votes. Yeah, yeah, yeah, she's totally right, line 61. We call them votes now, don't call them wishes, right, because the property we're accessing here. Again, that shouldn't have broke everything.
JASON LENGSTORF: State.giftlist. Oh, we're redefining this. We're pulling it out up here. So, we're using the wishes.
BEN HONG: Yep, so, let's change that to votes. Let's swap it all out. Yeah, we overrode everything. We might have been right the whole time. Oh!
JASON LENGSTORF: That one doesn't like it. Gift.value is undefined, so let's make it not gift.value.
BEN HONG: Part of me wonders whether the simpler code was right to begin with. Can we just delete line 55 to 57? Because we don't need it. We don't need to reset all of that.
JASON LENGSTORF: Like that?
BEN HONG: Keep going, yep, yep. And then delete 53 to 54, though. We don't need this part. That was setting everything to zero.
JASON LENGSTORF: Yeah, this part is going to be --
BEN HONG: That will be broken, yep. Yes, make that votes. Now I think -- ha, ha, ha, ha! Linda for the win! I was going to say, that looks way too complicated for what we want to do.
JASON LENGSTORF: This is like the curse of trying to do anything live. Oh, remember how we completely aliased this property without thinking about later we're probably going to need to work with that.
BEN HONG: Oh, my gosh, Linda, thank you so much.
JASON LENGSTORF: Thank you, Linda.
BEN HONG: Yeah, it's that simple. We can see from line 42 --
BEN HONG: It is simple.
JASON LENGSTORF: It's supposed to be. PROFESSOR: So, we got the votes, looped through each, update each line, and Vue does the rest.
JASON LENGSTORF: But we haven't persisted yet.
BEN HONG: Yeah, we haven't persisted anything.
JASON LENGSTORF: Next, we want to persist this.
BEN HONG: So, when you say persist, you're saying more like --
JASON LENGSTORF: Here I think we need to send this off to Hasura.
BEN HONG: Oh, yes, absolutely, yes, we need to change that now.
JASON LENGSTORF: Okay. So, let's do this. We're going to get the ID -- well, we already have the ID. So, instead we can do -- I think we just do a call to load the votes, but we're going to do it as a post, so we can do a method post, send a body of JSON, stringify, ID equals gift.id. And this is going to be response, which I think is going to be array, we'll figure that out. No, add vote.
BEN HONG: Singular and make the function async.
JASON LENGSTORF: Yes, need to make the function async. And that should be fine. What are you complaining about?
BEN HONG: That makes sense.
JASON LENGSTORF: So, log that response, and figure out for now we'll do it kind of the Jaenke way, which is this is an interesting thing, because what we're doing here is what you'd call an optimistic update. We're telling the UI to update before we get the response back, that's fine, and before we load the page, this will have completed and you'll get the new amount. I think this might actually just work. Let's try it. Bump this to three, it works. Stayed at three. I think that's where this power kind of comes in. We've moved so much complexity out of this front end in that we are not tracking these details, you know, so let's look at the response here and see what came back. Let me run it again. Here's what comes back, update votes by PK. So, what we can do here, as well, we can do update, votes by PK. And we could clean this up, as well, in the function. Instead of responding with the full response --
BEN HONG: Refresh?
JASON LENGSTORF: Did I screw this part up? I might have screwed this part up. Did screw this up.
BEN HONG: Doesn't like it.
JASON LENGSTORF: I think I just did this part wrong. Let's figure out what it's reporting one more time. Update votes by PK.
BEN HONG: That's right. What did you type earlier? Doesn't exist yet?
JASON LENGSTORF: Definitely exists. Let's find out. There it is. Now we get back the actual object that we want. Then what we can do is instead of doing that, we can say we're going to get back the votes and say the votes, so now we got the -- we match the UI to what's in the database.
BEN HONG: Yep, no more optimistic updates.
JASON LENGSTORF: Cool. So, I mean, I find this to be such a nice approach and such kind of a cool way to do it. We're able to very quickly get this thing up and running. And then when we want to deploy it, what can we do? Let's echo.env to the gitignore. I think that worked. Sure didn't. Let's see what I did wrong. Get ignore. Oh --
JASON LENGSTORF: Didn't add an extra line. So, now that's better. So, let's go ahead and add this whole folder. Get everything in there, we've got our images and all that good stuff.
BEN HONG: Sounds good.
JASON LENGSTORF: So, then I'm going to get -- did I GitHub repo create, Jason Vue Hasura?
BEN HONG: I don't think you did.
JASON LENGSTORF: Hasura serverless. Public, yes. So, I've created the repo. Now I'm going to initialize that on Netlify. Create and configure a new site. Go here, and we'll call this one Vue Hasura serverless. All right, run npm run build. Functions is function, yes?
BEN HONG: Yep.
JASON LENGSTORF: There we go. And if I open this -- I'm going to show you something, chat, and I want you to appreciate how great this is, and I'm immediately going to have to edit things, because y'all are going to break it, but I'm going to show you how we can import our environment variables. Right now, the site is not going to build. So, if we look here, we're going to be missing environment variables. Well, the site is going to build, but the functions are going to be broken, because we haven't added --
BEN HONG: Did we push it? We haven't pushed yet.
JASON LENGSTORF: Nothing there. You're right, you're absolutely right. We'll set up stream to origin main. Okay, so that's live. This app is going to build, but we don't have our environment variables set. So, if we go to our build and deploy and look at environment, it's empty. So, what I could do is go in here and put these in. Check this out, if I run Netlify and import.env, and this is going to show it on screen, so please don't hack us. It exports these to Netlify. And now they are in the build. So, our build will actually work. So, this is a really, really powerful work flow. You hackers. You dirty hackers.
JASON LENGSTORF: We're immediately going to get all of our data -- You hackers, you dirty hackers.
JASON LENGSTORF: But, yeah, this is really powerful. We're missing that, I'm going to cancel this deploy, I'm going to start it again, now it will have the environment variables. While we're waiting for that to build, I'm going to change this to admin secret, here's our admin secrets. I want to edit it.
BEN HONG: Wait.
JASON LENGSTORF: How do I do that? There it is. I want to edit this one. I do need adult supervision here. I'm not going to update that, and then I'm going to come out to Netlify, and I'm going to go back to the deploy settings, into the environment, and I'm going to update this to match. Actually, I just forgot what I said, so I'm going to copy this. Save it, good. So, now that that's saved, I'm going to go back to the deploy page, come out here, and then I'm going to come out here and going to actually delete my environment file.
BEN HONG: My favorite part.
JASON LENGSTORF: Now that I don't have that, check this out, I can run Netlify dev and ta-da! Comes in from the build settings. This is really, really handy, nice to work with. I think I might have to rebuild this one more time, because I just changed that.
BEN HONG: Yeah.
JASON LENGSTORF: One more deploy. Here we go, deploying, getting the site out here. As soon as this finishes building, I expect you to vote for your favorite toys. It's going to be great. I know the scary thing is that we are the adults. I know, Linda. Woof.
BEN HONG: And we have money, oh, gosh.
JASON LENGSTORF: Sometimes I wake up and think about the fact when I was a kid, I remember being 16 and I worked in a restaurant and there was somebody there over 30, and I was like they are so wise. Now that I'm over 30, I'm like, oh, no.
BEN HONG: I think one of my big adult moments was walking -- the PlayStation 4 had been released for a couple of months, and I was walking by GameStop, and I had this moment, I can walk in and buy it, I don't have to ask for permission. That's exactly what I did.
JASON LENGSTORF: No one will tell me no if I go to Cold Stone for breakfast.
BEN HONG: I have money and kid passions. It's going to be great. (Laughing).
JASON LENGSTORF: Okay, so, now that we've done this, this is very, very cool, but I will note one thing. Chat, if you're out there voting for things, which I hope you are, we are not seeing updates.
BEN HONG: That's true.
JASON LENGSTORF: Let's get this load. Did we already rate limit?
BEN HONG: I would not be surprised. Immediately rate limits us. I love it. This is my favorite thing about this show.
JASON LENGSTORF: We hit our rate limit.
JASON LENGSTORF: In the database, it should be in there, right? That part is fine. I guess we don't see requests. It's a 60 requests per minute, right? We hit that request limit and it's going to put us on time-out. So, what's nice, and granted, this particular approach that we're taking is usually we're not sending people to spam a button. So, the requests would most likely not be an issue, but I'm going to run this locally. It's not running locally.
BEN HONG: Someone is getting undefined thing.
JASON LENGSTORF: Undefined, I think, makes sense because the -- oh, no.
BEN HONG: Some of these got updated.
JASON LENGSTORF: A couple of these fired.
BEN HONG: Yeah.
JASON LENGSTORF: Someone went all in on Rock 'Em Sock 'Em. That's probably our rate limit. So, we are getting some results. Let's go to the deploy app. That's the wrong one, that's the wrong one. That's the wrong one. One of these. There's the deployed one. So, it's back up. We passed our one-minute time-out. Don't spam it too hard, it will shut down.
BEN HONG: Yeah, don't have an error state for that.
JASON LENGSTORF: This is real quick and dirty. Nice thing about this -- I think we got rate limited again. We did. I agree, I am still scared of Furbys. But you can see we've been able to, very quickly, didn't have to write backend code. We had to play with the database setup over here. We set up a basic database, where we have a -- oops. Come on. Now that we've got this -- is it opening? Do I got the wrong key in here? Hold on.
BEN HONG: Might be the wrong key.
JASON LENGSTORF: How about this? How about we go back here and relaunch the console and it will put the key in for me.
BEN HONG: I think that sounds better.
JASON LENGSTORF: Or we got legit hacked. We were able to go in and with a little bit of setting up a table, ID with text, primary key, and we did all this by checking boxes, and then we were able to add a few rows. We end up with our products in here. This is tracking, and through this graphical front end, we can very quickly build queries for what we want. There we go, there's our query. Then on the front end side, we didn't have to learn how to deploy a server or do anything but send a request. We send a request off to Hasura the same way we'd hit anything, and we have a fully functional API. I love when the marquee tag makes it into the chat.
BEN HONG: Makes me so happy.
JASON LENGSTORF: I put together an HTML sanitizer for the chat. I just added marquee to the allow list.
BEN HONG: Well done. I approve of your choices.
JASON LENGSTORF: Makes me very happy. So, yeah, this is the part I think is really cool, we didn't have to write back end code, set up a server. We were able to, what, 24 lines of code here. 20 lines of code here, 20 lines of code there. So, in 60-ish lines of code, we were able to put together really like a full back end. Then a few clicks and a back end, like an admin API. I find that so empowering as a front end dev. Have you built a lot of back ends in your career? Has that been anything you've been thrown into?
BEN HONG: I've been in the rails world and that kind of thing, but, yeah, I really like the front end. This is why, this sort of de-coupled architecture in general, I think it's such a powerful thing. I'm so excited we're getting into these days.
JASON LENGSTORF: Yeah, I feel like I come from a back end, I built a lot of back end systems back in the day. Now, being able to not have to do that -- oh, my God, the chat. No, the attributes get stripped. I'm pretty sure the only thing you can do in chat right now is marquee, I think. So, the -- from my standpoint, I feel like one of the issues I've run into, when I was at IBM, and when I worked on other teams, is that we are front-end teams, and as part of front-end teams, we have to build these really cool and complex user experiences, but part of that ends up coming in with, well, we need a little bit of data, or we need to be able to store this thing, or we need to be able to reach out to this API. And when I was on bigger teams, it felt like that always was a big hurdle. We had to suddenly go talk to a bunch of teams and ask permission for that kind of stuff. We had to wait for the backend team to prioritize it. We had to get a bespoke API end point. There was always this kind of hurdle. So, what I find really exciting about this approach is now I don't have to wait. I can go prototype. The front-end team can go build these full stack experiences and proofs of concept to say, hey, we think it should work like this. Maybe you through it away, because it was a quick proof of concept, or maybe it can turn into a full-fledged production app. You're doing all sorts of stuff in Hasura now. Do you feel when you're working with Hasura or doing these kind of serverless flows, do you still feel like you're in your front-end comfort zone?
BEN HONG: It took some getting used to at first. Again, it's like this realm of new knowledge you have to get into. I think Linda had mentioned it, when you look at Hasura, where you play around with things, like the GraphQL interface, getting acclimated to it, especially while working on explorers, has been super pleasant. And I, again, to Jason's point, it's so empowering to know you can write your own APIs rather than waiting for a backend dev to do that for you. So, I love that when it comes to building my own things and that kind of stuff.
JASON LENGSTORF: Yeah, makes me really happy, like I have super powers, really. It's like that little bit of effort to get the hang of what serverless can do, and then you're suddenly like this whole new world without having to learn a whole new stack opens up. I think that's really, really magical. So, I saw -- thank you for the sub, I really appreciate it. Someone asked about doing nuks in fire store, if Netlify and Hasura would be a better option. I don't think it's a better option. I think it's an option.
BEN HONG: Yeah.
JASON LENGSTORF: Have you done a lot with fire store, fire-based stuff?
BEN HONG: I haven't done as much with it. I know it's super popular when it comes to the prototyping world, because they were the first to make this process as easy. I dropped a link in the chat for you. Sarah wrote a great post for GraphQL and Hasura. So, be sure to check that out. That will give you a better feel for is this the type of data I want to model, do I want to use the GraphQL layer, and if so, I think it could be a very happy marriage. If Fire Base is working well for you, too, keep going at it. To Jason's point, not necessarily a better thing.
JASON LENGSTORF: Yeah, and we've got a couple episodes in the backlog. Let's see, David East was on and teaching about this. Let's see if we can find those. I think we've had two with David. So, here's one we did a multi-player sound board. That one we were playing around. This one, though, is really, really helpful, if you want to get up and running on how it works. Chucky, that's good. Now that I can see it, good user name. Chat going all-in on the marquee. Really making me happy here.
BEN HONG: They really want those attributes, though.
JASON LENGSTORF: I know, everybody keeps trying. One of these days, somebody is going to find something that didn't escape and it's going to be a mess.
BEN HONG: Oh, that's eyeballs. So, emojis worked.
JASON LENGSTORF: Yeah, yeah, I didn't realize there was an HTML entity for eyeballs, which is also fun. I looked at Blink and I don't think it has support anymore. Only thing browser has ever broken is the Blink tab. No, we can get rid of that one. That was a bad idea. (Laughing).
BEN HONG: Oh, gosh.
JASON LENGSTORF: Chat, if you got -- can we compare Hasura with Prisma? They are different things. It's a layer you put over the top of a database to give you access control, and what it's really, really good at is Prisma generates your types and a bunch of auto-complete stuff. It's really, really good for coding. Here we go with a stampede. (Music) So, if you use Prisma for building an app, you're going to get auto-complete, you're going to get warnings if you're using something incorrectly, you're going to get the crud auto-generated as code. If you don't do that, then what Hasura is going to let you do is basically no code, you get a GraphQL query, let it rip and you're off to the races. They solve for different problems. Prisma to me is sort of like type script or reduction, where you're adding guardrails and protections for how to build a really long-term controlled, maintainable code base. Hasura is, I want a database that I can access. I heard they just launched rest end points, too. So, I want a database I can access over GraphQL or rest that is managed for me and has all of these benefits. It does a bunch of stuff with data relationships, too, so event triggers or actions to extend data. Oh, there's a question about where can I learn Vue JS. Funny you should ask. We have ideas.
BEN HONG: Yeah, there's a -- yeah, so, the docs is always a great place to get started, as a free resource, we pour a lot of time into it. So, there's an essentials section, and, again, I say for people who have never done Vue or are looking for that resource, if you go to Docs Essentials, if you read through that, one 30 minutes, you have the gist of Vue. But some people love video tutorials.
JASON LENGSTORF: Sorry, where's the essentials?
BEN HONG: Docs dropdown and then guide.
JASON LENGSTORF: Essentials, here we go.
BEN HONG: If you read that through, that's written and maintained heavily by the team. This is a great place to start. Again, I know that people love video courses. So, Linda did a great callout for intro courses. If you already have a Front-End Masters subscription, Sarah does a wonderful course on that. Check her out. Gosh, there's a lot more. Honestly, feel free to reach out to me if you have additional questions in getting started. Nowadays, the ecosystem is mature, so there are a lot of different options. Yeah, excited to share those with you. CCS Dude, I think, yeah, had a question for you, Jason. For Hasura, I need my own database for it, right?
JASON LENGSTORF: Not necessarily. So, with Hasura, you can fire it up, they will let you hook it up to a free Heroku account. So, for your best -- let's see, the first 10,000 records on Hasura are free. And your Hasura account -- sorry, I think I misquoted. Heroku will give you a database, which is one of the databases that Hasura can use. You can get up to 10,000 records in it for free. There's also a storage limit if you're trying to store a lot of data in the database, but typically speaking, unless you're doing something wild, you shouldn't run into that. You can get 10,000 records in Heroku, and then Hasura will give you quite a bit of bandwidth, I think 20 gigabytes of bandwidth, don't quote me on that. Maybe we should look at it. Usage, okay, one gigabyte of bandwidth for free, but remember that's data throughput. Just the JSON data you're sending back and forth. And you get 60 requests per minute on the free plan. So, if you have comments or a form that people are filling out, unless you intend to drive a ton of traffic to it all at once, like the way I told you to spam the buttons, you're probably not going to run into the rate limiting issues. But if you need to upgrade, they have paid plans that lift the limits and all that stuff. You can see here Hasura is $99 a month for the higher-limit plans, which probably by the time you hit those limits, you'll have an app that is making money, and then it makes sense to pay to not have to do extra work. And for a database, you can stand one up on Digital Ocean for like $10 a month or something. There's a lot of ways to keep your costs really low, while still using these platforms and not putting yourself in a position to have to manage all the infrastructure yourself, but you also get, you know, all the high limits that you need. Oh, what's up, New Relic, with a party of 11. You're coming in right at the end. We were able to build a full app. Pretty excited about it. Let's poke at this thing one more time before we call it done. Here's what we were able to do today. We took this app that was set up to be completely static, like the state didn't persist whenever you refreshed the page, it would go back to zero. Now we're able to persist these amounts, where however many people have wished for this, it actually sticks around. And when we refresh the page, we see that again. We were able to do that by using Vue, the composition API, we hooked that up to Hasura, and we used Netlify Functions functions to be able to make calls to Hasura that protect the API key. And, actually, we kind of glossed over that. This, we can't put that in client code, that's why we're using serverless functions at all. If we put this in client code, anybody could scrape it out and wreak havoc on our database by making a bunch of queries. None of this code is exposed. People only see the end point, so we don't have to worry about -- we can make these secure calls from a serverless function. That's another big power, I think, you can work around some of those limitations. If we needed to make a cores limited call, we can do it from a serverless function and it will just work. So, yeah. All right. What up, y'all? But, yeah, for everybody who just joined us, we actually ran out of time. Ben, where should people go if they want to learn more about you?
BEN HONG: You can find me on the Internet of things, Bencodezen, Twitter, YouTube, I'll be more active on Twitch in the future, but all the things, Bencodezen. I even have a TikTok, that's up and I'm working on that.
JASON LENGSTORF: Nice, nice, nice. That is where to go and find Ben. Definitely check him out. I'm not just saying this because he's one of my coworkers. He's really truly a wonderful person and a lot of fun to be around. So, you know, go and do that. Also, remember, we've had live captioning for this whole show, which it looks like the thing ticked over, so that's gone. Thank you very much to Ashly, who's been live captioning with us all day. That's provided by White Coat Captioning, that's a fun bug, and that is made possible through the support of our sponsors, Netlify, Fauna, Auth0, and Hasura. Make sure you go and check them out, and while you're here, check out the schedule. We have so much fun stuff. Later this week we'll learn esbuild and more after that. Make sure you check out the schedule and add it to your Google calendar, so you get notified when things are updated. You'll see that on your calendar, just shows up in your calendar list, so you can come to the show. With that, Ben, I think we're done. Chat, stay tuned, because we're going to raid somebody. Ben, any parting words before we call this over?
BEN HONG: No, it's been a lot of fun. Thanks, everyone.
JASON LENGSTORF: Thank you so much for hanging out with us, y'all. We will see you next time.