Databases for Jamstack Sites and Apps
with Tanmai Gopal
How can you add a database to your Jamstack app? In this episode, Tanmai Gopal will teach us how Hasura gets us up and running quickly with a powerful data layer in no time!
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: Hello, everyone. Welcome to another episode of learn With Jason. Today on the show, we're bringing on Tanmai Gopal. Thank you so much for joining us.
TANMAI: Thanks. Thanks a lot, Jason, for having me. And hello, everybody. Nice to see you.
JASON: So it is wonderful to have you on the show. You're the creator of one of my favorite tool, which we're going to be talking about today. For those of us who are not familiar with your work, do you want to give a little bit of a background on yourself?
TANMAI: Of course, of course. I'm Tanmai. I'm the CEO and co-founder of Hasura. It's an open source infrastructure start-up we started just about two and a half years ago, almost two years ago now. We open sourced Hasura about two years ago. Our crazy idea is, you know, what if accessing a database was kind of like working with a data API. What if all of your data in the world became data as a service. What would that be like? And towards that effect, we started by providing so you can get productive and bringing in a bunch of things and start using that. Over time, we've been evolving the product and adding more data sources and integration. A couple years on, it's been a fascinating journey with developers, and of course as a start-up as well, we've been steadily growing. So that's been great. Yeah, super excited to be here and kind of talk about Jamstack and Hasura and how it all fits together.
JASON: Yeah, so I kind of want to start with a little bit of scene setting here. I feel like this is something that has been a huge pain point for me and a huge pain point for a lot of developers trying to move to the Jamstack, which is that when you start working with Jamstack tools, you're using Gatsby, doing the static export, the experience is so, so, so good right until you need custom data. Then you kind of found yourself -- like, you went from this really, really pleasant developer experience of, okay, there's a tool, I have everything managed in Git. I haven't had to deal with dev ops. I haven't had to edit engine X or open docker. Then you need data and it's like, suddenly I have to log into AWS or I need to spin up docker or Kubernetes or configure something. It just got really confusing really fast. Like, it felt like the step from here to database was a big step. So Hasura, what I thought was really interesting about Hasura when I first saw it, was it took a lot of that out of the way. So you would kind of get your Hasura instance, and it would -- you know, it creates your database and adds all of these nice layers over the top of it. But I was still kind of only like -- I was like, oh, I love Hasura, I just wish it was easier to start. You still had to get this docker container. You had to deploy it somewhere. You had to host it. So there was still that big getting started step. But that all changed this year. This has been a big year for Hasura. So what's new on that front? How did y'all crack that problem?
TANMAI: That's a really good point. You know, as a start-up, it was easiest for us to focus on solving the hard problem that's required to kind of -- the reason why we've seen that jump from Jamstack and getting databases has a hard problem is because it is genuinely a hard problem.
JASON: Genuinely hard.
TANMAI: Yeah, like the APIs that you have there that are doing things, they're doing genuinely hard things. Two of those things are handling kind of a performance boundary, right, with Jamstack applications with 100,000 users, a million users. They're using the application at the same time. That's what's great about Jamstack. You go from building, development, to production for millions of users just instantly, right, without you doing excessive work as a developer. But then when you have this middle thing that needs to talk to a database, that thing is not great at dealing with, you know, scaling out to hundreds of thousands of millions of users without putting in any work. So there's this difference. Databases are used to handling hundreds long-living connections, whereas Jamstack or the HTTP layer is hundreds of thousands of millions of connections at the same time. So security is a hard problem because you don't want to just give your users direct access to data, right. We're like, well, this is great. We don't even need to get hacked. (Laughter) We're hack-proof now. So those are hard problems, right? And so, when we invented kind of this method of automating that at Hasura, that's the problem that we were focusing on. To say let's just take the work away here. The easiest way for us to deliver was that to say was you have your own databases already. You're going to get your APIs. You're going to get high-performance scalability, secure API. That was kind of phase one of the journey that we had so far. Earlier this year, we decided we should start working on the cloud version of the product as well for exactly those reasons you talked about, which is as a developer, it's great that Hasura is solving a hard problem, but I don't really care. I want it to be available now and easy to use. I want the whole story to kind of get repeated. So we started working on our cloud version and launched that just about like a month and a half ago. And that's kind of been amazing as well. Our dream has been to kind of think about our cloud service as kind of like what the CDN is, traditional CDN, Akamai. Hasura is that to your dynamic data. We were so tempted to say the Hasura DDN, the data delivery network, but that's kind of what Hasura cloud really is. It's this idea saying just like a CDN, it takes your static data and caches it for you and distributes it all over the world for you. Then the evolution of the CDN is you don't even need a host. What is that story like for dynamic data? And that's what we're doing with Hasura cloud. We're saying the hard problems of distribution, security, availability, caching, caching for dynamic data t right, those are the things that Hasura will take care of for you so you can go ahead and be productive and build things, which comes back to Jamstack.
JASON: Yeah, absolutely. That's the whole thing, right. That was the big leap that made Jamstack appealing. All of this complexity, these really hard problems kind of got turned into tools. When you see something like Netlify, there's a whole lot going on, but you as a developer never have to think about it. So you're not actually making a choice because you want -- like of course you want all of those feature, but really what I'm doing when I deploy on Netlify is I'm being lazy. I don't want to solve those problems because those problems are hard, and they're not new and they're not fun. I want to work on the thing I'm working on. I have a new idea, and I want to build it. And that was kind of where the lightbulb with Hasura cloud came on for me. It feels like Netlify for databases. I want to get my data stored and have a way to interact with it. I don't want to figure out how to shard a database or how to get it spread around the world or handle massive con currency because I don't actually know how those things work. That's going to be a nightmare for me. So being able to grab a tool that solves that problem is like, whoa, okay. So I could just talk about this forever, but we have a lot we want to cover. So I want to jump right into it. So let's switch over to this screen here. As always, keep in mind we have live captioning going. We have Rachel helping us out today. Thank you very much, Rachel. That's available at lwj.dev/live. And that is being made possible by our sponsors. We have Netlify, Fauna, Sanity, and Auth0 all chipping in to make this show more accessible to more people, which we really, really appreciate. Also, make sure you go and check out Tanmai on Twitter. Follow him, follow Hasura, check all that out. And this is Hasura. This is what we're going to be working with today. So there are some links for you. Tanmai, if I want to get started, how should I -- like, what should I do first?
TANMAI: You can scroll down and click the blue button.
JASON: Click the blue button. All right. I'm going to open this in a new window. Here we go. Cloud.Hasura.io. I already have an account. So I think I might actually -- let's see. I'm going to do it from my other -- I have another browser profile that has all my stuff set up so I don't have to do this again.
You hackers. You dirty hackers.
JASON: That's you, chat. That's you. So this is my current Hasura setup. You know, don't tell anybody I'm working on something new. So we want to create a new project. I'm just hitting this new project button. We're going to call this, let's see, Hasura Jamstack.
TANMAI: Perfect. Then you can scroll down.
JASON: I want to use the free tier.
TANMAI: Yep. Then just set the region to the first one, U.S. East. So that's creating Hasura. Now the second thing we need to do is connect that to a database. So if you have an existing database or you want to use Ivan or RDS or Google Cloud or whatever, all of these different vendors, which that ecosystem is becoming amazing as well, by the way, you can plug that host connection in. Or the easiest way is to use Heroku.
JASON: I'm logged into Heroku. Watch what happens. Boom. It's beautiful. So now we've got to -- is that it? We got a database?
TANMAI: Yeah, so we have a database. In two seconds, once that initializing thing happens. So what's happening in the background is that we did what you would have usually done. You would have set up a database somewhere on the cloud. You would have deployed an API somewhere on the cloud, connected them together. That's all happening in the background.
JASON: Right. So one thing that's worth noting, this, by default, is open. If the chat wanted to, they could jump in here and wreak havoc. So I need to lock this down. How do I do this?
TANMAI: So head to the environment table section
JASON: Okay. Then add a new one.
TANMAI: Yep and just type in secret or admin secret.
JASON: And this won't be visible, okay. So I'm going to set one.
You hackers. You dirty hackers.
JASON: So it's rebuilt here. You can't -- so once this gets done -- one thing. So check this out here. By default, when we're looking at this, we're in looking at our queries. We don't have anything to query yet. But these headers, so I want to show something because I have questions about how it works. When I relaunch this console, it's going to take me in. Now, I didn't have to enter that key, but look, now I've got what's called a collaborator token. Can you talk about what that is and what that does?
TANMAI: Yeah, yeah. So, what happens basically is that -- so on the cloud service, we have this notion of having collaborators. What you can essentially do is you can have -- you can basically invite other team members to access the console as well without having to share your admin secret. So you can kind of go into your cloud project and say add collaborators, then you don't have to share the admin secret, and they'll all be able to log into the console and use the GraphQL API. You can just use the admin secret as well that you just created.
JASON: And if I wanted to do that, I would do like X-Hasura admin secret. Then I can put the value in here, which I won't do. That's really cool.
TANMAI: But that should really help with the collaborator stuff. So you don't have to share this admin secret, but it's your major API toke than gives you superpower access to everything.
JASON: Like the admin secret is basically root access, right? You can do everything with an admin secret.
TANMAI: Yep, yep, yep.
JASON: Okay. So from here, we've got Hasura set up, but we don't have any data yet. Did you have something in mind you wanted to create? Or should we start making up what we want to store here?
TANMAI: We can make something up. Whatever you usually do. Maybe like a log thing, whatever you want to do.
JASON: So I have an idea. There's a few things that Hasura does that I want to show off. So one of the things that I think we could do is if we store like the ID or username of a person, because then I know later we can do some special stuff to go out and fetch extra data from external things.
TANMAI: Sounds good.
JASON: So what if we take -- you know, we've got my GitHub username. We'll start here. Maybe we want to store that. Then later we can try to go out and get the avatar or something like that.
TANMAI: Okay. That sounds fun. So what you can do is head to the data tab. Basically, the starting point here is what we want to do is create a data model, a table. The table to store the base data we want. And start enriching that data or adding authorizing conditions. We can start off by hitting create table. Let's create a table call users. You can use the frequently used columns there at the bottom.
JASON: Oh, nice.
TANMAI: ID would be like an auto ID. We only have the IDs and time stamps. Those are the common ones. Then you have name, that can be just text.
TANMAI: And that's pretty much it. Then you can hit create and you'll have a table. You can have maybe a GitHub username if you want.
JASON: Yeah, maybe let's do that.
TANMAI: We can go back to the table that's created and modify.
JASON: I'll add a new column. That one is also going to be text. And we'll save.
JASON: What were you going to say?
TANMAI: No, I was going to say you can choose whether it's nullable or not. Totally fine. Not a problem.
JASON: Which we probably don't want. And we probably want it to be unique. And we can make this decision later. Obviously later we probably wouldn't want that to happen, you know, once we have tons and tons of data in here. But in the early days, this is something I find myself doing a lot. When I am starting to build something, I usually know mostly what I wanted to do. As I start to build it, I realize, oh, I actually need to store data like this, or oh, I need to do this thing a little differently. Being able to just kind of click a couple things and solve it. Then this I also really like. I can change what the username is. So in GraphQL, I can make this more explicit.
TANMAI: Yeah, you can make it a GitHub username.
JASON: So now then, is that over?
TANMAI: So we can go in and add some data maybe.
JASON: Isn't that cool? So we have a couple ways to do this. If I go in here then, I can just add the data like this. And we'll put in my username. Okay. So save that. Then if I go back, browse rows, we can see the data. Then if I go out here, I can just click on some stuff to get it. Here's my user. So I want ID, name, GitHub. And now we've got -- like, I can copy/paste this into any GraphQL client. If I want to add data, I can go that with GraphQL too. So I want to insert a user. I do like a name.
TANMAI: Yeah, you can just put in a name.
JASON: What's your GitHub username?
JASON: So I can run this, and we'll run the mutation. Then if I rerun query, now we have two users. Hey, look at it go. So this is really, really nice. And if we wanted to build something with this -- well, actually, let's see. How do we want to do this? Do we want to build the site with this first, or do we want to kind of get some more data into it and go build something with it?
TANMAI: I'm fine doing whatever you are. If you like to integrate that with an app first, that's totally cool too.
JASON: Okay. Let's do this. This will be fun. I'm going to go to GitHub.com, Learn With Jason. I have a demo base. This will give us something to work with. I'm going to use this template, put it on here, and we'll say Jamstack databases Hasura. We'll make that public. And let's create it. Okay. So now I have this database. So I'm going to open up iTerm. And let's go into GitHub, Learn With Jason. We'll clone that. And NPM install. This is just a really simple Eleventy template that gives us a blank page we can work on. So what I do here is if I open this up, once it finishes -- good. So inside of it, we've got a lot of stuff that we can work with, but the most important part is just here, which is preform whatever we want. So I'm going to change this over to HTML so we get autocomplete. Then we can start it with Netlify dev. I'm going that for a very specific reason, which is that we are going to eventually want environment variables. So I'm just getting it set up for that to work. So there we go. We've got a basic site set up, ready to rock. Now if we make changes, they will show up pretty much in real-time. So we can do everything we need to do right inside of here, and that'll be wonderful. So the fist thing we want to do is we can just, like, send a fetch request. So let's do -- we'll call this async function, get users. And in here we can -- we'll do const result equals await fetch. Then our GraphQL API is this one, right?
JASON: Okay. So I'm just going to grab this. Then because it's GraphQL, we always have to send it as post. Then for our headers -- if I copy/paste this token -- yeah, tell me what I should do here.
TANMAI: Yeah, so in development, it's really easy to plug in your admin secret and just use that for development. But because we have hackasaurs on chat, evil, evil, naughty people, you, but we can also set up -- we can enable anonymous access. So we can say that we want to allow reads on -- we just want to allow reads, only reads. So we can set that up. If you go to data and users and permissions -- so right now because we're admin, that's why you can do everything. That's why you see the green tick. You can add something called anonymous.
JASON: If I can smell anonymous, geez.
TANMAI: And it can be anything, public, whatever. Now let's just select, without any checks. And we give them access to all the fields. So you can access everything. Then save these permissions.
JASON: Nice, okay.
TANMAI: So now what Hasura has done is it said, all right, cool, you have this new role called anonymous. If anybody with the anonymous role comes in, we'll give them access -- we let them query for stuff. So that's totally fine. Now, the next thing that we want to do is -- well, the question is, this role could have been called anonymous, it could have been called public. This idea of getting access could be anything. So we need to tell Hasura's environment variable that this is -- if somebody is not logged in, they don't have an off token, don't have admin secret, we want to use this public role. So we can head back to the cloud dashboard and go to env vars and create a new environment variable there. I think you can just search for unauthorized. There we go, unauthorized role. And you can call this anonymous. So now Hasura knows --
JASON: This is new to me. I thought I had to send a header. So this is great. I'm learning. I thought I was going to be pretending I didn't know things today because I use Hasura a lot. But I'm learning. This is great. That's amazing. Okay. So now when we send a request, it's automatically going to be sent as the anonymous user.
TANMAI: Exactly, exactly. So you can try this out by going back to the console where we have the GraphQL thing runs. So you can just uncheck those two, the first two, the client and collaborator token. So you still see you have users available in the explorer.
JASON: I do still have users. But look.
TANMAI: You don't have any mutations. You don't have to delete or insert anything. So Hasura also does this thing called role based where it generates a schema that's for a collection of roles. So you don't see the schema you don't want to.
JASON: And this is really important because one of the things that's a problem with security is someone can sniff around and try to find what is available so that they can attempt to attack it. So you're removing that attack surface entirely.
JASON: That's really nice.
TANMAI: And also from an API usage point, you don't -- if you have other users of your API, you don't want them to necessarily see your 20,000 APIs. You're this role. Just browse the API you want to see. So yeah, you can just have a content application and another query.
JASON: So we're going to stringify. Thank you for covering all of my typing. Then in GraphQL, if you've never seen this before, in GraphQL you can send a GraphQL query to any GraphQL API more or less using just fetch. You don't need to install Apollo or anything. If you get into anything advanced, you'll want it. But for one-off query, you just have to send a query. We're going to use a template string and variables. Since we're not using variables in this one, we'll make that an object. Then drop this in there. And now, once I run this, that will come back and end up here. No. Here. Then we'll get a result, and because we requested application json, we're going to get json back. Now all of that is stored in results. So let's start by just console logging that result.
JASON: Then down here we need to actually call this function. So let's call it get users. So now that we've done that, we can come back out here, look at our demo, open up the console, and we can see here is our data. Boom. We're jamming. (Laughter)
TANMAI: Good punnage there.
JASON: So, yeah. That's the whole thing. If I want to do this the Jamstack way, this is Eleventy, and we can put this in a file. All I have to do is export something. So in here, I can module.exports, and that's going to be a function. For now, I can return an array, and we'll say ID one, name Jason, and username. If I save that, then out here I can use Eleventy things. I can say for -- oh, boy. Can I remember liquid templating on the fly? For user in users, I'm going to end for. Then we'll say just, you know, user ID, user name, and user username. All of those need to be double quotes. Double curly, boys, as Cassie Evans would say. I think that's made it permanently into my -- oh, come on.
TANMAI: Working memory.
JASON: There we go. So that -- and that's no longer dynamic. So if I don't call this anymore, we still get that data. So what I can do then is take all of this over to here and just drop this in, I think. All of that should work as expected. So what I can do instead is get users and then because this is going to run in node, I need to make sure that I actually have node fetch, which I don't. So let me stop this. We'll NPM install node fetch. And up here we're just going to get fetch equals required node fetch. And this gives us the browser fetch API right in our node files. So I don't need this anymore. Instead, I'm going to return results.data, which will give us our array of users. Or wait. It was result.data.users.
TANMAI: Yeah, and I think in the templating, you called it username. But it's GitHub username.
JASON: Oh, that's right. It is GitHub username now. So we can fix that. I'm going to get GitHub username. And let's see if we did this right. Look at that. We did it. So this is great. Oh, hey, Cassidy. How you doing? Yes, we are cooking with gas. But this is the power. We are 30 minutes into this, including a lot of just talking about this stuff, and we've already set up a Jamstack site that is dynamically building from a database that we just created.
JASON: That is -- like, I've worked in web apps for a long time. Being able to do that is not normal. That is not a normal experience for trying to set up a database with an app. This is like a truly delightful way to get up and running. And that's kind of -- that's why I'm so excited about this technology in general. I think it's just such a -- it feels like a huge gap being bridged.
JASON: You know, I feel like that's such an important thing to bring up. One of the things that is difficult, especially when you start talking about bringing new technology into a company, is the pushback that you'll get, especially if it's a large company, is how do we know this is going to work? How do we know this isn't like great for the demo that you just built and it's not going to immediately fall over when we launch this to production?
JASON: What you just explained, like, this is built on post, running an enormous amount of truly global scale enterprise applications. It's using -- like the technology here is not novel. What you've done is you've made it really easy to use a lot of enterprise grade software. That, I think, is -- that's what I think is the differentiator. You're not inventing things. You're creating abstractions over established things. And I love that.
TANMAI: Exactly. Exactly.
JASON: Cool. So, okay. And I feel like we're just now scratching the surface. So now that we've got our data showing up, and we're not using this anymore right now, but I'm going to keep it in here because later we'll want to do some client-side stuff. But there's more that we can do with Hasura than just storing data in it. So for example, I've got our GitHub usernames. What kind of fun could we have with that?
TANMAI: I think we can do -- you know, we could have a thing where if you insert something new into the table, you can trigger off a function that does something. You could even think about maybe integrating that with the GitHub GraphQL API and fetching data that belongs to this user in a single GraphQL. You can kind of join that data. We can see how that goes.
JASON: Yeah, let's do that. We have GitHub username. We can start by getting the avatar. Then maybe we can get a couple repos or something. So if I want to do that, where should I start? What's my move here?
TANMAI: Yeah, so I think the first thing to do is to get -- to import the GitHub GraphQL API in.
JASON: If there's something you're more comfortable with, I can switch these out to something else.
TANMAI: Let me see what happens. Have you ever played around with the GitHub GraphQL API? The only thing we need to see is if we have a token or not. If we don't have a token, then it doesn't matter.
JASON: I think we need a token -- let's see. So api.github.com/users. Does it give us any data if we are not logged in? So we get data even if we're not logged in, it looks like. Or this is just the rest API.
TANMAI: I think the GraphQL API is more fun to use. Or if you have another -- maybe you can use a CMS.
JASON: Yeah, you know what I have is the Sanity set up. That's a GraphQL API we can use that I have access to.
TANMAI: Perfect. Let's do that.
JASON: This is how I run Learn With Jason, actually. So I have here my episodes and guests. So how about we look in here and see what we've got. We've got your Twitter username. So maybe what we can do is instead of the GitHub user name, we'll use the Twitter username. Then we can pull your episode.
TANMAI: Oh, yeah. That's awesome. To do that, I need to look up really quickly --
Ahem. What, what, what? I see you, Tony.
JASON: I think we're probably going to stick with this one because we have access to it. So I need the URL of this API, which I have to go look up. I'm going to do that off screen because I can't remember how well I locked it down, and I don't want to find out that I did it wrong by you messing with the site, chat. So, let's see here. Why can I never find -- like my one sad face about Sanity is they don't actually show you the GraphQL API. I have to look it up in my environment variables, which is a pain. I think they want you to use their -- they have their own language they want you to use. But I won't. I won't do it.
TANMAI: I refuse, I refuse.
JASON: Okay. Here's Learn With Jason.
And that's just not something I'm willing to do. (Laughter)
JASON: That is correct.
TANMAI: I love these interlude things that happen. It's insane.
JASON: It makes me so happy. I really love the silliness that's been able to happen in the chat. It makes my day. Oh, my god. I'm just going as slowly as possible over here. Somebody want to cue up some elevator music, because I'm taking my time.
TANMAI: Every time I think of like I wish my life had a soundtrack to it -- (Music)
JASON: Oh, my god. Why can't I find this? I've like buried everything far away from where it needs to be. Holy crap. Oh, Sanity. I'm sure that I could find this so fast if I wasn't trying to do it live. It is -- where's my -- come on. GraphQL end points. It is your project ID.api.sanity.io. GraphQL production. Then I need my data set. Couldn't be easy. Can never be easy. There we go. All right. What is the tag? I don't know what a tag is. Oh, my god. Does anybody know this? What is the tag in a Sanity thing? This is killing me.
TANMAI: I am seeing if it's possible for me to try.
JASON: Default. Oh, my goodness. Just link that in your dashboard. Pretty, please. So here is the Learn With Jason database. I have the ability to get all episodes, but I also have the ability to get -- actually, let's get guest, ID. Uh-oh, can't search by -- no, okay. So we'll get all guests. There's going to be a name in here. Name, Twitter. Is it equals? So that's working.
JASON: Don't tell me there's no reverse link here.
TANMAI: There's no link from guest episodes?
JASON: Apparently not. Ugh, killing me. Just killing me. Great. (Laughter) So, I guess what I can do is if we go to all episodes, then we can get the guests and Twitter. Then we can get the name or something. Then from here, we would be able to --
TANMAI: Can you do the guest filter on this? I'm not sure if Sanity has that.
JASON: I'm wondering.
TANMAI: No, yeah. Hasura has that nested thing. I'm not sure.
JASON: Yeah, I don't think --
TANMAI: We can try it out by just fetching the guest information and see. If you had that link, it's easy.
JASON: So yeah, we'll get what little we can get here. That's going to be fine. So I've got some data, and I am defeated by technology, which is no surprise to the chat, I assume. And now I'm ready to do something with it.
TANMAI: So then we can go to remote schemas. And we can add in that API so you can call it just Sanity or LWJ API or whatever. So click on add, then just call it whatever you want. Then plug in the GraphQL end point. Do you have a token?
JASON: For this one, no.
TANMAI: Okay, perfect. Then just add the remote schema.
JASON: So now I have a remote schema.
TANMAI: Exactly. So if you go back to GraphQL, you should be able to start querying your guests.
JASON: Wow, look at that! Holy -- wow. Okay. I did not know that was possible. So that is really, really cool. So now we've got not only our custom data with users, but now I can actually query my Learn With Jason episodes.
TANMAI: Correct. Exactly. You can remove -- you'll have to remove the user thing. Then run this.
JASON: There we go. Dang, that's cool. That is so cool. Okay. So then --
TANMAI: So now what we'll try to do is build this relationship between our user entity and the guest entity that you have in your own API.
JASON: Yeah. And just to recap, because somebody asked, all that we had to do to get this to work was we end to this remote schemas tab, clicked add, then I dropped in my Learn With Jason GraphQL end point for the read-only GraphQL API. That is unbelievably cool. So to ask a next-level question on this, if I had an API that did have a token, like read/write permissions, by stitching it in here, I can use Hasura's permission management to control access to that API?
TANMAI: Exactly, exactly. So then you can -- so you can provide admin access, right. You can embed -- so Hasura will connect to your GraphQL, the other remote schema you're bringing in, in admin mode. But when you expose that to the rest of the world, you can still sub-graph that. You can say, well, anonymous only gets access to these parts of the schema. Anonymous doesn't get access to the Sanity.
JASON: Yeah, okay. So if I want to stitch these together -- and actually, maybe a way we can stitch these together is I can do a search for all episodes, and I will do a query. Thank goodness we have this. Now I don't have to guess anymore. I can search for title down here. If I want to do a fuzzy search, it matches, right?
TANMAI: So this is the Sanity piece. I'm not sure. But I think that should probably be it.
JASON: Oh, right. Yeah, of course. Asking you questions. So yeah, that gives us what we want. If I get the ID, now what I can do is I've got this ID. So I could go into our database, and I can modify it. And what I will do is add a new column and spell it right. Episode ID. Oops. And that's going to be text. I'm going to drop this in, and we'll leave it nullable, otherwise it's going to yell at me. I didn't mean to set that as a default, but it is what it is.
TANMAI: That's fine. Everybody has this episode.
JASON: Yeah, that'll be okay. But so what we've just done now is we've got this episode ID. So now we can stitch this in the episode details.
TANMAI: Exactly. So you can do that by going to -- so you have basically a reference. It's like what you would imagine in a database world. You have a table here. You have a table there. And some kind of reference that's joining these two tables together. You kind of now go and set up a relationship. So if you go to the relationships tab there and head to remote relationships at the bottom. So remote relationships are across. What we're doing is adding a new field. You can call it episode. Then Sanity. You know, however we're filtering that.
JASON: What? Oh, my god. This is amazing.
TANMAI: So that's like the joint condition. That's it. Now just go down and hit -- ignore all of that and just hit save.
JASON: Users cannot validate remote relationship because of expected type ID.
TANMAI: Oh, we don't support ID types in joining yet. Yeah, so that's a bummer.
JASON: We can do it on title. That's fine. Let's switch it up.
TANMAI: Yeah, we can do it on title as well. Yeah, sure.
JASON: So let's go to users, and instead of -- let's see. What's the episode today called?
TANMAI: I think the episode ID is --
JASON: Let's just grab this one here. So I'm going to grab this, and we're going to go back in and instead of the episode ID, we'll join on -- oh, I just need to rename this. I need to modify, and I'm going to edit this.
TANMAI: Just edit that to title or something. Yeah.
JASON: And I'm going to take that default out, actually. Save.
No, this will work. This will work.
JASON: It will work. Okay. So then here I've got my title set up. We have our rows.
TANMAI: Yeah, we can change that to our title. Just edit that. And then you can head back to relationships.
JASON: Putting it through its paces today. Then this one. Remote relationship. We're going to call this LWJ episode. Boy, that is a hard word to spell. We'll go by title this time.
TANMAI: You should use all episodes. So all episodes and then title or matches or whatever.
JASON: Title is episode title. And that should work. Okay. So let's save that. Good. Now I'm going back, and instead of this one -- I'm going to turn this off. I'm going to go back to users, and I'm going to get your ID, your username, your name, and your episode.
TANMAI: Which now has all those fields.
JASON: Yes. So I'm going to get the title. I don't know, we'll get the guest, right? Name and Twitter.
TANMAI: Yeah, that works as well.
JASON: Okay. So that didn't work.
TANMAI: That might not be matching exactly.
JASON: Okay. So let's go fix that.
TANMAI: You can change that to title or title matches maybe. I don't know, whatever.
JASON: Relationship. Oops, edit this one. And instead of title, we'll do title matches, worked before, so let's do that again.
TANMAI: Yeah, you can do matches. You might want to -- yeah, you can hit save. You might want to change the episode title to be just database, for example. I don't know if the whole thing will match, you know what I mean?
JASON: Yeah, if this doesn't work, we'll do that. It matches everything now.
TANMAI: Yeah, it matches a lot of other things.
TANMAI: Yeah, title matches is -- I think the way the Sanity table works is it gives you the full -- I think it matches a bunch of those, right?
JASON: I got you. This is me just not understanding how database matches work.
TANMAI: Yeah, you still might get --
JASON: Look at it go. Damn it, that's cool. If you have control over your APIs, we could also do things like change that ID to a text, and that would be it. Then it would have matched right up immediately. So part of it is going to be, you know, how much you control. Sanity's made some decisions. We're working with Sanity instead of going to try to fight it. And we're still able to get the same outcome that we wanted. And that is just extremely cool that we were able to do that. And now that data is available to us, which means that if I take this and bring it out to my query out here, then now I have access to all of that information. So back in here, you know, I can -- I'm not going to do much with it, but I'll just dump the whole episode. Let's see what happens. I believe what will happen is we'll get a big JSON object. Yeah, there it is. So now we've got access to our data. So we could build out -- you know, we have the ability here to -- we can build out -- like, I have my central user table, and all I'm really going to do with that is store my name and my user IDs on other services. Then we can stitch all that together. I can get my latest repos, get the episodes, pull stuff from my blog.
TANMAI: Exactly, exactly.
JASON: And Hasura is going to manage access and control to all of that. That is incredible. That is so nice. So what else can we do here? I know there's a lot we can do, but we've got about 30 minutes left to actually demo. What else do you want to show off in our next 30 minutes?
TANMAI: I think we can try the event, show you the event getting fired up.
JASON: Yeah, let's do it.
TANMAI: Again, it's very interesting because it's kind of the same idea of you have databases and databases have database triggers. And what does that look like in a Jamstack world, right? And that's kind of the starting point. Whenever database events happen, you can go trigger several functions and do things. So that should be fun to try out.
JASON: So I'm just going to get this deployed because for serverless functions, we need to have -- well, we don't need to, but it's easier if we have something live. So let's get commit and say load data from Hasura and we'll get that pushed. Then to get it on the interwebs, let's do Netlify init. Create and configure a new site. We're going to put this on my team, and we're going to call this -- what did I call it? Jamstack databases Hasura. So now this is going to go live here. I'll drop that in the chat. My build command is going to be NPM run build. We want it to deploy site. And we're off to the races. So that site will go live here in a moment. I'm just going to open it up. We can watch that build in the background. Opened in the wrong window, fine. Supposed to open over here. Now that we have this site building, and this is Eleventy, so it should build fast, and while we're waiting for that, we can set up a serverless function. I'm going to create a new folder called functions. In this, we will call this -- we'll just call it trigger. The basic set up for a serverless function is to return an object with a status code, and we'll say 200, which is the HPPT status for okay. That's basically what you'll get most of the time when you're loading a document. Then we send back a body, and in this case we can just say okay. Then what we're going to do in here is we'll respond to Hasura. So if I then -- let me make sure I have this configured. Got our function set up here. So then if I want to test this locally, I can set it up and run Netlify dev, okay. Then once that gets up and running, I can -- I'm at local host 8888. So I'm going to go to Netlify functions trigger. What did I screw up here? Oh, I just did node. It's exports.handler. You have to export a named function called handler. That's me being in node default mode. But there you go. So we listened for something. We returned a status code 200 and some text. Whatever text we respond is what will be delivered. We can also send JSON or whatever. But while we're doing that, the site has deployed in the background. It is now live. So we can go and actually look at the site. Here's our site. It's building with data from Hasura. But if you look under the hood, and this is the part that -- well, let me actually do the actual view source. If you look under the hood, there's no connection to Hasura here. So that means several things. First, you are not burning any server resources. Second, there's no attack vector from your site to Hasura. The only reason that anyone would know we're using Hasura at all is because we've made this client side call that we're not even actually using. So all the data is written in, and we are -- you know, we can safely say, hey, look at this data that we've got. And you don't need to know where it came from. So again, we're an hour into, this and we've built and deployed a full site, including stitching to a third-party API. We have custom data. We have remote data.
Holy buckets, did that just work?
JASON: This is really remarkable. Ten years ago me is looking at this and just thinking, how? Like, how is this even possible? But so, there's even more we can do. Let's look at these event triggers. I've got -- so how do you recommend testing this, right? We need to be able to reach this from Hasura. So --
TANMAI: So you'll have to deploy that to like a reachable end point.
JASON: Okay. So we're going to get back an event. That's whatever is sent to the function. And for debugging, this is my usual approach.
JASON: We just console log that event. Then we can deploy this, which I'll do by adding the functions directory. And we'll say work in progress, deploy function. Push. And in about 30 seconds to a minute, we'll have that pushed. Because we hooked it up to Git, it's automatically building as soon as we push something to Git. Then that function will go live for us here in -- you know, I'm hoping 30 seconds. That's my goal. Oh, even faster. How long was that? 17 seconds. Record time. Okay. So now we have Netlify functions trigger. There we go. So I have a function. It's reachable and logging. We can see if I go and look in my logs, functions, trigger. We can see our log. This is the event that gets sent. This is all of the headers and all of that stuff. So knowing that, I'm ready. We can hook this up.
TANMAI: So now we can just attach this trigger. So if you head to events, then you can go to create. And call this whatever. Like on user create or something.
JASON: Okay. Schema table.
TANMAI: Yeah, insert.
JASON: So what we're doing, the name is pretty clear here. When we insert a user -- or when we insert an entry into the user's table, we're going to call this function.
JASON: Okay, perfect. Do I need to think about any of these?
TANMAI: No, not yet. I mean, when you go into production, you probably want to have some default and exponential back-off and stuff like that.
JASON: Oh, yeah. So hold up. You just do that?
TANMAI: Yep. So Hasura basically queues that up internally.
JASON: Oh, my god. That's amazing. Then I can send some custom headers and stuff like that.
JASON: Oh, that's so cool.
TANMAI: Then you have some kind of token exchange between Hasura and your event.
JASON: Dang it, that's so cool.
TANMAI: So whenever you go do an insert, you can use a mutation to insert. You might have to switch back.
JASON: Okay. So now I should have, I think, my mutation still down here. So let's add a new person. Let's see. I saw Cassidy in here earlier. Let's put her in. So I'm going to -- oh, wait. Can we even -- I think we can even add an episode because Cassidy has been on the show. So let's find a word. That's probably be the only time I've used that word. Then her episode title would be improv. So let's insert. Done, great. Then I can run the query. Databases, databases, improv. Oh, it's so cool this just works. Like, I am very, very happy this just works. So that is really cool. And I just realized there's something else I want to show here. But we can do that in just a second. So what happened in the meantime is we got the body. I'm realizing now I should have just logged the body, but we get an event. How about I actually take all of this -- can I just copy/paste it all? I'm going to do this. And I'm going to take it out to a new file. Let's delete that and delete that. Set it to JSON and format. Okay. So this is our document. This is what we get back. So we've got the event. We've got the role, the operation. Here's the data. Oh, this is cool. So we get the old data and the -- so if we had changed something, you would be able to -- we would be able to determine what changed.
TANMAI: Exactly. You'd see the old and the new. So if you did an update, for example, you'd see the old and the new.
JASON: That's so nice. Hey, any mods want to bounce whatever that is? Thank you. So we get created at, ID, more information about it, which trigger was used. This is slick. This is so nice. So another thing that I just realized that we would want is like when we use this data -- I'm not going to save this. Whenever I make changes in my Hasura database, I want to rebuild my site. So another thing I can do is I'm going to go out here, and I'm going to say let's go to site settings, build and deploy. I want a hook. So I'm going to create a build hook, and we'll say Hasura data update and save. And now I have this. So I'm going to copy it and come over here. Let's create a new event, and we'll say on data change. And also users. Now I can just boop, boop any of those. What's console?
TANMAI: That allows you to trigger this deliberately from the data browser, you know, where you're browsing the data and delete rows. You can keep triggering or test it. Otherwise, you have to clear the mutation or do something again and again. You can just force it.
JASON: That seems like a reasonable thing. So we'll keep that. Then I'm going to create an event trigger. So now that this is set, if I go out here and I say, let's change my episode, we're going to change this to, let's see -- this was a fun one. I'm going to use this, text to play. And I will come out to my user, and I'm just going to edit this. So I'm going to save this. Now a couple things are going to happen. First of all, if I run my query, I get -- here's Tanmai, here's Cassidy, here's me. And it looks like I got a lot of stuff because that's a fuzzier filter than I thought. I'm not going to worry about it. But what's really cool is now the site is already building and building from a Hasura data update. Now we have a two-way link. Whenever I change my data, the site rebuilds. And it pulls that data in. That is really, really powerful stuff. Let me quit Slack because that just got noisy. So that is super powerful stuff. And you can do a lot with this. Another thing that we could do, if we wanted to, is we could notify a Slack channel. So this trigger, if we go into our Slack app, we could create an end point -- like, I'm not going to do that on a stream because those end points, somebody could spam them. It's just not worth it. We could go in here and create a Slack notification channel and post the change. We could grab the event body and take -- like, hey, someone just updated username. Now their episode title it this. We just put that right into our Slack channel. So that could be a publishing stream. So-and-so just published this to the blog. That's so cool. Like, so cool that works. Cassidy -- (Laughter)
TANMAI: Was that actually Cassidy?
JASON: It was. She was Slacking me. I hope it wasn't important, Cassidy, because I'm definitely not going to read it until after the stream. (Laughter) It was definitely not important. Okay, good deal. She's going to be like, how dare you use my name in this stream. And I'm sorry if that was the thing. Memes, now I want to read it. Okay. So -- man, I am just so happy with everything that we've been able to get done. And I feel like sometimes I vamp a little bit, but I swear to god this is mind blowing to me how much we're able to get done in such a short time. That's one of the reasons that Hasura has quickly become where I reach early on. I see Jason Brown is in the chat as well. He was actually the one who got me interested in Hasura. He gave me a similarly like, you're not going to believe this, you've got to try this. So it's wonderful, wonderful stuff that you're doing over there. So what else should we look at?
TANMAI: Yeah, I think, you know, we could look at things like actions where you're kind of bringing in rest APIs and connecting rest APIs to the overall schema.
JASON: I like that.
TANMAI: We can try that out if you'd like. If you head to actions --
JASON: Okay. So I'm going to actions.
TANMAI: And create new action. So here what you can do is basically what we're doing is creating a custom result we want to add into our overall GraphQL schema. This would be backed by a serverless function rest API. So this is not like an event trigger that's happening after a database event. This is just getting added to the overall schema. So suppose you wanted to do something super custom like add a bunch of numbers, which has nothing to do with the database, but it's still got to do with your API, right. Or maybe you want to place like an order, which runs a serverless function. Or maybe a payment, which then goes to contact Stripe or does something, right.
TANMAI: Then what you can do is you can specify the contractor and put in a rest end point. So we can try that out. You can have type mutation and change that to add or something.
TANMAI: Then add you can change to numbers. The next arg1 itself, you can change that to numbers.
JASON: Okay. That makes more sense. That would be valid. Got it.
TANMAI: Exactly. Then you can just say sum or sum output or add result.
JASON: Add result, yeah, that make sense. Okay. So here --
TANMAI: Then you can have a type, add result. And that can just be sum, which is, again, an int.
JASON: Then the input we don't need anymore.
TANMAI: Yeah, you can just remove that, exactly. And now you can back that up by whatever other serverless function you have. So you can just put in a handle there, which can be any rest API. So you can put in the same thing that we used.
JASON: Okay, cool. Let's do it. Got this one. Okay.
TANMAI: And that's it. Then just hit create.
JASON: So this -- this here, the synchronous or asynchronous, if I click synchronous, Hasura will make sure this succeeds before it continues? If it's asynchronous, it's going to say fire off this function, and I don't care what happens, I'm going to move on.
TANMAI: Exactly. And whenever the function returns, there's a result you can do a subscription. So you can do mutation plus subscription. You can say mutation, return and respond immediately, and subscribe to the result whenever it's ready. Maybe it's something like convert to PDF. Something, something. You don't want the user to wait for it. You want the user to have this mutation and it goes in the back end. Then you can subscribe to the result.
JASON: Nice. For now, we don't need that, so I'm going to create.
TANMAI: We can just do sync.
JASON: All right.
TANMAI: Now if you go to GraphQL, you'll see that this has kind of been added to the GraphQL schema. So mutation. And here's add. Okay. So let me collapse this one and get rid of this one as well. And this needs to be an array. And that's supposed to bring me back a sum.
TANMAI: Exactly. So this won't work because we haven't written the mutation itself yet. So we get an arrow that says we expected you to have a JSON response that contains something, but your response is just okay.
JASON: That's perfect. So we can go and look at this. If I go look at the functions, we have our trigger. We've got a body. It's our session variables.
TANMAI: And that contains the input.
JASON: Excellent. So let's go code against this. So in our trigger, I'm going to get back this. So if I say body equals -- we'll parse event.body. What that's going to give us back is we'll get our numbers out of body.input. Yep, okay. Then, if I can spell, what we can return -- and I'm supposed to return what now?
TANMAI: You're supposed to return the JSON that contains the sum.
JASON: So let's just simplify this. Now you can only add two numbers. So we will return sum equals num1 plus num2. And I know there are a million ways I could have done that. That was the first one that popped into my brain. So that's what we're doing. Oh, I screwed that up. It needs to be like this. Thank you for the heads up. So let's try that again. All right. So now we're deploying something that'll actually work. That will show up over here. Let's see, maybe we can get another 17-second deploy. Then while we're doing that -- actually, we don't need to do anything over here because this is already ready to go.
TANMAI: Yeah. Another useful thing that's sometimes useful is subscriptions in general for some kinds of applications where you have something dynamic. It might not be the case.
JASON: I mean, that's actually like a really good use case, I think. One of the things that I've noticed is that, like, when we have, say, a like button or something like that, that starts to feel like something you can't do on the Jamstack. And you end up writing polling or things like that. But it's actually pretty approachable. So maybe what we can do is -- let's see. We have 13 minutes before a hard stop. What should we do here? How do you want to tackle that?
TANMAI: Umm, I think -- I mean, if you want to add like a dynamic element to the Jamstack, we can just add a subscription that is just live updating on your app. Something like that might be interesting.
JASON: Okay. Yeah, maybe -- let's see.
TANMAI: Totally up to you.
JASON: What do you recommend for setting up subscriptions quickly on the front end? What's your go-to?
TANMAI: I think Apollo has something. But you're right, that is true.
JASON: Jason Brown had a good point. Maybe we can just show them in the console here.
TANMAI: On GraphQL itself. That makes sense.
JASON: So let's do that. Let's add a subscription. The subscription we can add will be for --
TANMAI: And you can just say subscription users, ID name.
JASON: Yeah, let me close these down. We'll say for our subscription, we want to subscribe to -- yeah, user, ID, name. So when I run this, got my subscription, and it's just running. I'm going to copy this over here so that I can make more changes. And I'm going to run a mutation.
TANMAI: You can run a mutation. You can edit that directly. It doesn't need you to go through a mutation. It can be anything. It can be a direct change of the database. It can be whatever you want.
JASON: Right, right, right. So let's just add another one here. I'm going to skip the ID. For the GitHub username, let's add -- wait, why can't I -- I want to type in here. We're just going to edit over here because I can't seem to get my mouse in there. Let's do Sarah. Sarah Drasner. And her episode title is animation.
TANMAI: I think it has to be just one word. If it's hyphenated or has multiple words, the fuzzy match does something weird.
JASON: Gotcha. So we're just going to return back the ID. I don't care. What we're interested in is over here, our subscription is going to update. Look at that. Isn't that slick? So what that means is if we've got, you know, Apollo or something that handles subscriptions set up on our client, then as soon as something is editable or is edited -- and that doesn't matter where we change it -- as you said, I can go in here and update this data from anywhere. So let's edit my name. As soon as this changes, the data updates, right? So we now have a way to kind of keep our front end synced with the data in the database. And this is data from all over the place, right? This is really, really powerful stuff. And would this work with -- like, this isn't going to work with remote schemas. That seems like --
TANMAI: Not yet, no. Because we don't understand what the remote schema does and how it handles events and how you can create action queries. It's not yet possible to do that. But you never know.
JASON: A way we could make that work is we could set up an action -- or wait, an event, right?
TANMAI: Yeah, you could set up some kind of event, yeah. Exactly.
JASON: Well, I was thinking if we know that our remote schema, like the Learn With Jason database, I have ability to fire web hooks from that. So I could go back to Sanity -- or from Sanity to Hasura and say, like, this changed. Then Hasura, you know, maybe I just increment a remote Sanity edit field. And that triggers a subscription, which would cause the data to update.
TANMAI: Exactly, yes.
JASON: So there are a lot of ways, even now -- oh, update. Yeah, Jason Brown, updated at. We could just change the field and that will trigger the whole subscription. It's just really nice. It's a really nice workflow. And with that, I think we're probably to the point where anything else we try to do is going to be a mad dash. So maybe instead of doing that, we can quit while we're ahead. (Laughter)
TANMAI: Makes sense.
JASON: So where should people go if they want to do more with this? What do you recommend as a next step for somebody who's excited?
TANMAI: So head to Hasura. You can always just click on get started and play around with things and muck around and see what that's like and drop in and ask questions.
JASON: You have a discord. Where's the link to that?
JASON: If you scroll to the bottom -- there should be one on the top as well.
JASON: Here we go. Bunch of links here.
TANMAI: So you can join the Discord community or whatever. If you do have like half an hour or an hour, two hours and you just kind of want to go through a slightly structured course, we've been collecting a bunch of community courses at Hasura.io/learn. There's a bunch of amazing courses out there that people have built. We're going to put that together on a resource page, but for now if you go to Hasura.io/learn, you'll see a bunch of courses as well. So you can start off with a specific front-end frame work type thing as well, depending on what you're doing.
JASON: Very, very cool.
TANMAI: And that goes through a nice example that has queries, mutations, subscriptions, a simple but complete example that covers a bunch of things. It's a real-time, collaborative app, which is just what the world needs right now. So that's a good place to get started as well.
JASON: That's really, really nice. Well, cool. This has been a lot of fun. I feel like I learned a lot. Would this work with Gatsby? Absolutely. What we just did with Eleventy -- and let me just pull that up one more time so we can look at it. This is the site we built. There's not a ton going on with it, but it is very cool. We are able to pull in -- you know, here's our data. Because we've got that web hook, it's rebuilt with everything that we changed. So Sarah is here, my name change is here. All this data, that's all built in. So we could rebuild a Gatsby site like that. Gatsby's got the Gatsby source GraphQL, so you could just stitch your Hasura instance right into Gatsby and use it in the data layer. This would work with Next. This would work with pretty much any -- not pretty much -- with any static site framework during your build step. You can load data so you'd be able to use this with that. Chat, if you have other questions, fire them off right now. In the meantime, Tanmai, is there anywhere else that you want people to go to check you out or to check out Hasura stuff?
TANMAI: No, that's good. Hasura.io, on Twitter, my Twitter, Discord. Just reach out however you manage to get in touch with us, and we'll route you to the right things. That should be totally fine.
JASON: Hasura HQ, give that a follow. lots of good information there. And let's do one more shoutout to the sponsors. We've had Rachel giving us live captioning all day today. Thank you so much. That's done by White Coat Captioning. And that's made possible by Netlify, Fauna, Sanity, and Auth0 who all kick in to make this show more accessible to all people, which I very much appreciate. YouTube and community call, that another place people should go?
TANMAI: Yes, thank you. Wow. Thank you, Jason. Also, hello, Jason. It's been a while. So we do these monthly community calls for the community with updates on the open source project, updates on cloud, stuff like that. Every month you'll see a community call, and you'll see that getting published on YouTube. So we often talk about what's on the road map, what's like a quarter ahead or a month or two ahead. So if you want to get exciting previews of what's happening, be a part of the feedback, and try out the early previews and stuff like that, you should definitely come hang out there.
JASON: Where would we find that information? About when those calls happen.
TANMAI: So if you scroll up on the website, on the homepage, you'll see -- a little more.
JASON: Community call.
TANMAI: Hasura community call. There you go.
JASON: Beautiful. That is super, super cool. I love that you do that. That was something that I used to -- yeah, I think that's a really good move. All right. Well, I think we're happy here. I'm happy. I hope you're happy. Chat, I hope you had a good time. I hope you're excited to go out and build some stuff. If you build things with this, please, please, please, send it on Twitter. Tag Tanmai, tag me. I want to see what you build. There's so much possibility here. You can do anything. And you can do it fast, and you don't have to be a database expert. So go give this a try. With that being said, I think we're going to give this one the official boop of approval, right?
TANMAI: Thank you, thank you.
JASON: Make sure you go check the schedule. We have some fun stuff coming on. We have John Lundqvist on next week. We have Anthony Campolo. We're going to talk about Redwood JS. All things happening on the stream. Definitely go check that schedule. On that note, Tanmai, thank you so much for hanging out with us today. Chat, stay tuned. We are going to raid. We'll see you next time.