with Anthony Campolo
RedwoodJS calls itself "the JS app framework for startups" — and it's officially hitting v1.0.0! Anthony Campolo will show us what's new and how to get started.
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. And welcome to another episode of Learn with Jason! Today on the show we're bringing back Anthony Campolo. How you doing, Anthony?
ANTHONY: Hey, I'm doing great. Thanks so much for having me back.
JASON: Thanks for coming back. And I think the last time you were here, you had a different job.
ANTHONY: I didn't have a job at all.
JASON: All right, then. All right. Let's talk about what's changed. You want to give folks who aren't familiar with your work a bit of a background?
ANTHONY: Sure. I was a music teacher who switched careers into tech via the bootcamp route/kind of contributing to open source route. When I was on the show last time, it was December 2020. It was actually the day I got on to the Redwood Core Team. So, that was basically how I was breaking into the industry was by becoming kind of the defacto developer advocate for Redwood. And then the month after that is when I actually got my first tech job, working for StepZen. You had Carlos on quite a few months ago now. That was awesome. And just like I'm a very big proponent of open source and leveraging it to both learn things and make connections and possibly get a job. I'm definitely lucky in how it all worked out. But I think it's a path that others can take if they really want to.
JASON: Yeah, yeah. For sure. I love the story of the career switcher, right? Being able to kind of see some potential and decide to go to a bootcamp. And, you know, within a year in a lot of cases you can be from I don't know anything about tech to being gainfully employed as a developer or somewhere else in tech. So, yeah, I love that story. You said one of the first things you did was kind of get into Redwood as the defacto DevRel.
JASON: What drew you to Redwood?
JASON: So, it's -- yeah, I think the appeal of something like Rails is it's batteries included and Redwood has a lot of parallels with that, as you said. So, you know, for somebody who is kind of evaluating frameworks, what would you say are the big tradeoffs of Redwood? Like what do you gain and what do you lose by choosing Redwood versus other tools?
ANTHONY: Yep. Definitely. The main things are going to be you're going to have a more opinionated backend than you will with than with a framework like Next. Framework gives you the ability to hook into frameworks like Prisma. With Redwood, Prisma is in the Prisma CLI. They're really alias in Prisma. Or install with Prisma, you set is it up yourself. You can set up auth very easily in Remix. But with Redwood, you can write a command that will write your auth code for you for the most part.
ANTHONY: You have to be more bought into the solutions they give you. They have more home-rolled and third party versions. Like auth, today we're going to do self-hosted manage your own auth. But if you want to use a third party thing, you can do that. That's the things you gain. And the tradeoff is you have to be bought into whatever tech you hope to use. You hope they have selected the right libraries and given you the right path to have something that works and functions. That comes from the experience of the team and the community and the startups building it on. There's a lot of startups on it and a lot of Flywheel effect. It's in a good place and it's good to learn and wrap your mind around it because we are approaching v1 now.
JASON: Yeah, approaching. It sounds like you're at v1, right? Like we're gonna be working with v1 today. It's just a release candidate instead of the final, final. But really, a release candidate usually means we're within days or a week or two of seeing something go live, right?
ANTHONY: Yeah. With a release candidate, the idea is that it's a guaranteed contract that there are not going to be breaking changes from here. That whatever you're writing on the release candidate, you should be able to bump the number to what we do have available and it's just going to work. So, it's upcoming within say like the next month or so. We're gonna have actually like kind of a launch week type thing where we have our partners and coming together to talk about just like how you integrate Redwood with different things. Just like there's a lot of people who built a lot of stuff, a lot of different pockets and niches and things. So, that's coming up. That hasn't been announced yet. There's no hard date. But the hard date for that is coming up very, very soon. I don't want to jump the gun on that.
JASON: Sure, sure.
ANTHONY: Now we're setting up a big release for v1. It's just last minute bug fixes and stuff like that.
JASON: Gotcha, gotcha. I'm not sure how this happened. It lined up really well, we're getting a lot of sneak previews on Learn with Jason this past few weeks. I'm excited to get a sneak peek with what we're getting into with 1.0. We did a Redwood episode before. So, I will pull that up. Let's see. When did that one happen? It happened --
ANTHONY: It was December 2020.
JASON: December? Okay. So, about a year and a half ago now? And so, what's -- like what's new from that episode that's particularly notable in 1.0?
ANTHONY: Yeah. The things -- there's a lot but the things we're gonna kind of focus on today is being able to manage your own auths. Whether it was first set up, it was set up with Netlify Identity as sort of the auth solution. People don't necessarily want to have to buy into like a specific service to do like an auth.
ANTHONY: Lots of people like using it, it's very, very simple. But it's the kind of thing you wanted to be more portable than that. That's the main thing is you have your own kind of -- so, you have passwords that you can solve in hash and Redwood does that for you.
ANTHONY: And the big thing is you can actually run it on a server. This is kind of funny.
JASON: Oh, okay.
ANTHONY: Redwood was proposed as a serverless-first framework. Doing everything from lambdas up. You weren't able to run a real server. You were able to do that, but Redwood is a serverless antipattern. It's a land-o-lith. It's a monolith, you shove it to a single lambda. That doesn't scale. If you actually end up pushing the boundaries of what you want to do in production, then at a certain point, you just kind of want to run it on a server. We gave people the ability to run it on server.
JASON: Nice, nice. Chat, we now have an excellent idea for some fan art here. We need to know what the lambdalith looks like. Okay. So, yeah. So, and I get that. Like it's always a little like serverless is great, but if you're trying to shoe horn a full server into serverless functions, are you getting any benefit out of it, right? I think the -- so, then being able to have a server-full version makes sense. Okay. So, you can host it on a server. It's got different auth solutions in it. Any -- any other notable features that we should call out here?
ANTHONY: It's less -- so, there's little things like meta tags and like more kind of stuff for like SEO. But there's also a lot more integrations just with other providers. So, the amount of ways you can host it is just like insane now. Because you can do Netlify, Vercel, Render, Fly, LayerZero, Flightcontrol and I think those are the main ones. That's like six different ways you can kind of deploy it.
JASON: And that's before you start looking at roll your own solutions like AWS or GCP.
ANTHONY: Serverless framework.
JASON: Oh, yeah. Serverless framework.
ANTHONY: That deploys it straight to AWS. And flight control does that too. Give you actual AWS kind of stuff. There's the whole spectrum of totally managed to, oh, you manage almost everything yourself. And everything along that spectrum. There's kind of something for everyone at this point which is really cool. And the great thing about it, it was kind of proposed as this universal deployment machine. It was a term that Tom used a lot.
ANTHONY: This is like a fruition of that. Once you actually find all these different ways to deploy it, it's really interesting.
JASON: Yeah. And so, you just said something that I thought was interesting. You called out like meta tags and SEO as being a feature of the framework. And this might be something that's worth calling out because when I think frameworks, I'm usually thinking, oh, I'm gonna need to know a plugin or get a third-party tool or roll my own when I get to SEO tags and I need to add whatever meta tags. I'm always opening up, you know, the boilerplate HTML file and I got to drop in my own Twitter cards and OG data and stuff like to. You're saying Redwood bakes that into the framework for you?
ANTHONY: Yeah. There's a meta tag where you can pass in name description. Anything like that. Yeah. This geez along with there's pre-render too for the front endoscopy. There's stuff to kind of alleviate some of the challenges that come with single page President Clintons.
JASON: Yeah, yeah. That's really cool. So, are there other built-ins like that? Like SEO and meta that might surprise Devs who are used to working with things like, you know, Next or those -- the solutions where you kind of have to roll your own?
ANTHONY: Definitely. Another one is accessibility. And this is something that Dom has worked a lot on. Things like when you try and navigate in a single page app, it can confuse the screen reader's navigation. It doesn't necessarily know whether the page has changed or not. There was a route announcement component that got baked in. When you're switching between pages your screen reader doesn't break. Things like that. If you were using frameworks. I think now things like Gatsby and Next do have this kind of stuff. But a couple years ago, this was an a huge unsolved problem. Dom was looking at Gatsby and next and now that's baked into the framework.
JASON: That's really cool. That's excellent. Do you have a -- I guess a core set of use cases that Redwood really excels at? Like what are the best use cases for Redwood? And conversely, like when are some cases where you might not want to look at Redwood?
ANTHONY: Yeah. What's funny is we use a blog as the main example in the tutorial. And usually when I'm spinning up simple versions of it, you'll have a post model and whatnot. But a blog is not really a good thing to build with it. It's more for dashboards, data-intensive apps, apps with users, apps that just have a lot of interactivity. And a database-backed crud app. That kind of thing. That's really what it's aimed although. And especially having users is something that I emphasize a lot just because of how much auth is baked into it.
JASON: Nice, nice, nice. Cool, cool, cool. So, I guess there's a lot that we could dig into in the abstract here. But it's feeling like maybe the right thing to do here is to actually just dig in and get our hands dirty. So, why don't we switch over to camera 2. Camera 2! We just got booped! Oh. Okay. This is a fun thing that just happened. All the boops that got dropped earlier queued and then dropped as we opened up this. That's fun. That's a thing that I have never seen happen before. All right. So, lots and lots of boops happening. Thank you, Ben, for all of those. This episode, like all episodes, is being captioned by White Coat Captioning, we've got Amanda here with us today. Thank you very much, Amanda. And that is made possible through the support of our sponsors, Netlify, NX, and Backlight all kicking in to make this show more accessible and do fun things like build a boop-drop. So, thank you all very much for that. We are talking to Anthony today. You can find Anthony on Twitter here. Make sure you go and give a follow. And we are talking about RedwoodJS. There's a link there. With that, I think that's all the things that I know. So, what should I do next if I'm ready to start here?
ANTHONY: Yeah. So, I have a repo set up for you that you can fork. And then just start working off of --
JASON: This one that you send me ahead of time.
JASON: I will drop this into the chat if anyone wants to follow along. And hit the fork button.
ANTHONY: This is pretty much what you would get from running create Redwood app. But updated to the release candidate. In the README, it says if you want to run from scratch, that will bump up to the release candidate.
JASON: I got it, the RC. Cool, cool.
ANTHONY: And pone it down and run and install. And get the dependencies going. One thing noted for people seeing this for the first time. Yarn is required for Redwood. It was before work spaces. That's the main thing for all our commands, yarn, space, and RW for Redwood and then what the command is.
JASON: All right. So, there's -- there it is.
JASON: Forgot that I switched to Volta on this.
ANTHONY: I love Volta.
JASON: It's great. I like it.
JASON: So, yeah. Here's yarn. We're installing our packages. And I did a quick LS over here so we could see what's going on. So, we've got like a Node version. Prettier config. Redwood TOML, we'll have to peek at that. A lock file. Testing setup, a GraphQL setup. And looks like environment variables over here, API folder, web folder, scripts folder. All right. And -- there it is.
ANTHONY: And the config you don't really need to mess with at all. The main thing is going to be the web folders and the API folders where all the code is going.
JASON: Okay. So, here's our API folder and this has server config. It's got source. So, there's a bunch of stuff over here. Database, we've got a Prisma schema. Seen Prisma show up as a built-in to more and more frameworks which is interesting.
ANTHONY: Oh, yeah. Prisma's amazing.
JASON: Cool to see them grow.
JASON: So, here's source. App, routes, all right. Okay. So, in the abstract, I understand what's going on here. What -- what should I do if I want to get started? Like should we just start this thing up and roll?
ANTHONY: Yeah. So, start by just starting your development server. So, it will be yarn, space, RW, space, D-e-v. And that's gonna kick off the development server. Since we don't center any pages, it has a default splash page it will show us. Last time I was on here we did a page and worked backwards to the database. This time we're gonna start with the database with just the API because that's going to be factoring in a lot nor what we're doing today.
ANTHONY: The first thing we want to do is go to our schema.prisma file so we can create our schema.
JASON: All right.
ANTHONY: Change SQLite, and we're defining our database, you could do SQLite, postgres, MongoDB -- which is really interesting -- or like Microsoft SQL, something like that. And then we're gonna define a model. And so, the model will be a post model instead of --
JASON: Am I keeping this user example?
ANTHONY: Yeah. Keep pretty much all that for now.
ANTHONY: And then change -- sorry. So, like rename user example to post.
JASON: Oh, gotcha.
ANTHONY: Yeah. Because you want to keep the ID exactly the same. So, that's just like giving you an auto-incrementing ID.
ANTHONY: And change email to title. And then get rid of the unique constraint. Yeah. And then yeah. Then make that say body instead of name and then string. And then --
JASON: We probably want that to be required, right? We don't want an optional body?
JASON: And the question mark for folks who haven't seen a Prison that schema file before, that's what would make it optional. So, we've got basic post.
ANTHONY: Will be created at, which will be a date, time.
JASON: Created at. Look.
ANTHONY: That's the whole thing.
ANTHONY: Copilot knows how to do it. Thanks. And we're defaulting it to now. When you create the post, it will pull a timestamp of the current moment, which is great.
ANTHONY: Great. And that's it. So, that's gonna be the whole schema that we'll be working with.
ANTHONY: And then now create a .env file. If you just started by and do it in the whole route of your whole project. And this is something that if you did a generate project from the beginning, you would have a .env. But you cloned it down, it's in your get ignore, you don't want to clone the whole file. This is where the important stuff goes.
JASON: Great. This is the .env.
ANTHONY: The very top one, database URL, that's the one we're going it use. But we're going to spin up a database. This is where we're going to use Railway. Railway is a really nice kind of hosting service for databases or servers or just any kind of thing you want to host. So, we're gonna just spin up like a postgres database. That's all we're gonna use this for. So, create a new project.
JASON: New project.
ANTHONY: Yeah. And then just select the postgres one. Yeah.
ANTHONY: You've never heard of Railway?
JASON: I've never used Railway before, no.
ANTHONY: Yeah. It's been the way we've had the tutorial do the database part because it's just like a really, really easy way to spin up and get going. Click, postgres. Then you'll be able to go to connect and connect to your database. And this will blur out your password. But you're gonna want to make sure to manage that offscreen when you do that.
ANTHONY: Grab that and put it in your database URL.
JASON: Great. Got it. So, do I -- I want the connection URL, right?
ANTHONY: Also gives a -- command which is great.
JASON: So, I'll move this off screen. Let's see... there it is. Postgres. Username and password and a URL. Do I need to put anything else in this .env?
ANTHONY: Nope. That's it.
JASON: Okay. I'm gonna close .env and coming back over. Are we gonna be in Railway anymore?
ANTHONY: No. We might want to pop back when we have data in it. But for flow, leave it off screen.
JASON: I've cleared the sensitive data, we're back over here now. We'll have that ready if we need it. Otherwise I am -- we don't need that anymore. I'm ready.
ANTHONY: Go back to the terminal. We can run commands. And since we're adding environment variables, we will stop the server.
ANTHONY: And then we're gonna run Yarn RW Prisma and then migrate. And then D-e-v. And this is a useful trick. Then do dash, dash name. And then posts. So, this way if you just run this it will just do the migration. Otherwise, ask you like what do you want to name your migrations?
JASON: gotcha. Okay.
ANTHONY: And this is going to set up our database. It basically writes some SQL to credit like a table for the model and then just applies it to the database. And then it also gives you like the actual SQL that it generated as well if you want to kind of look at that.
JASON: Yeah. If we want to look. This is a cool thing that I like about Prisma is it's not -- it's not giving you like secrets here. It's just if you need to see what happened, you can go over here and if I as someone who is not a DB admin go in and make some changes. The changes I made can be reviewed by a DB admin who can say, you shouldn't have done that. As opposed to a command, I have to run through source code to figure out what the command does under the hood. I like that you can actually see the SQL that was run.
ANTHONY: Right. Okay.
JASON: I've run it. Looks like our database is now in sync with our schema. That's very cool. That one command that we just ran by defining our schema in Prisma, that set up Railway for us because we put that connection string in?
ANTHONY: Yeah. Exactly. And then --
ANTHONY: It basically creates a table that is your migrations. And so, that is like so it creates a table, yeah. So, go into here in the data. So, you see the Prisma migration and then the actual post table.
JASON: Wow. That was -- okay. This is incredible because, you know, I come from like -- I was building websites before jQuery existed. And so, a lot of what I was doing was opening up these old tools that like I remember being in phpMyAdmin when I was trying to use like the LAMP stack together and managing tables like this, I would inevitably, I was on a production box, SSH in, and start MySQL in the SSH boxes. I don't know what's going on, I don't know where I am, thought I was going to take down the whole system -- definitely did take the whole system a couple times -- this is a lot nicer. I can't believe how far --
ANTHONY: This is not the only one. Supabase is good. There's if you want to do MySQL. This is one of a plethora of awesome options now.
JASON: Absolutely. Yeah. Okay. So, we got a database. What happens next?
ANTHONY: All right. Now we're going to scaffold like what you were just kind of saying. An actual admin UI in Redwood. So, we're gonna do another command which is gonna be Yarn RW. And then just letter G. And that's short for generate. And then scaffold. And then post. Yep. That's it. And then that's going to take the model and basically create like this whole crud UI to -- to do the stuff. Yeah. So, you got an SDL and services. So, if you can go to post. Yeah, this is where these are like Prisma commands essentially. So, that's, you know, create post, update post, delete post. And that maps to if you go post.sdl.js, that's your GraphQL schema that generates.
JASON: Okay. All right. I see what's going on here.
ANTHONY: And there's a whole bunch of React components and stuff too. But before we look at that code, let's see what this does first. Server back on again, so, Yarn, Redwood Dev.
JASON: That little moment there brought to by being willing to press up a thousand times rather than type another command.
ANTHONY: And now go forward slash posts. It created a post.
JASON: No kidding. All right.
ANTHONY: This is the part that got you last time too.
JASON: Yeah. This is my goldfish memory really coming into play here because I have no memory of doing this before. Then we can edit it. Hot diggity dog, y'all. This is pretty incredible.
ANTHONY: Yeah. Pretty sweet. And this is just kind of like us reaching into the API right now. And we didn't have to like write any frontend code at all. But now what we're gonna do is we're actually gonna generate a page and use a cell to query the page. So --
**ANTHONY:**Ly explain what that is once we have the code in front of us. Sorry, there's a very loud --
JASON: Sorry, is that a leaf blower?
JASON: The bane of video existence. All right. So, I'm assuming I start with Yarn Redwood.
ANTHONY: Yep. Now we're gonna generate. But a page this time instead of scaffold. Yep. And then do the word home and then space forward slash. What this is going to do is this is going to create a home page that is mapped to just our forward slash. So, if you're on example.com, that would be what would come up.
JASON: Okay. And so, going back here, then, if I look at my web. That just change -- like what did that change?
ANTHONY: So, pages.
ANTHONY: And then home page, and home page.js. You have a story file and a test file as well.
JASON: All right. [Heavy leaf blowing] Special guest today, the leaf blower. So, we have now with two -- well, what? Three commands so far and one definition of a schema we've set up a database. We have configured that database with our schema. We built an admin dashboard for managing those posts and we've created a home page. I think the last dot to connect here is getting the posts we created on to the home page. I heard you say the word "Cell."
ANTHONY: Yep. We're gonna do one more generate command. Yarn RW generate. And now cell.
ANTHONY: And do capital B. And then blog and thens with a capital P.
JASON: Okay. Whole thing. Okay.
ANTHONY: Yep. And then what a cell is, it's a GraphQL query combined with different basically states that your data fetching can be in. So, loading, empty, failure, success. So, pretty standard stuff for people who have ever done this kind of stuff. But you don't have to write conditional logic to handle this yourself. You have error handling out of the box. You don't have to do it yourself.
JASON: Very nice.
ANTHONY: We have to change three things. In the three places it says blog posts for the query. Change all three of those to posts all lower case. Yep.
ANTHONY: Cool. And then in the query, title, body, and create the at. At the very top. Yes, that's the GraphQL query. You set the query at the top and then you can kind of have it come out in the success however you want. So, I think --
ANTHONY: That's good. Now it's just gonna spit out some JSON for us. And import that on to our home page.
JASON: Okay. So, I want to import. And...
ANTHONY: And no curlies. Just blog post cells. Or blog post cell -- yeah.
JASON: Wait. How does that work? Because it's not a default export?
ANTHONY: Yeah. Babel magic is how.
JASON: Babel magic. Okay. I'm going to go back here and get blog post cell.
ANTHONY: Yep. And then that will be from and that will be SRC because it does the mapping for you. And forward slash components, and forward slash -- yeah. Just like that. And then just drop it in there.
JASON: All right, all right.
ANTHONY: Cool. And you can also get rid of that top line as well.
JASON: Not using that anymore.
ANTHONY: And there's the meta tags thing I was talking about by the way.
JASON: Yeah. That's very cool. Very handy to just have that kind of like put in there for you as well.
ANTHONY: All right. There we go.
JASON: There's our post! Okay. So, then if I come back here... where was it? One of these. This one. And I create a new one. And I say, a second post. Save it. Come back out here. Now we got two posts. All right. So, this is, you know, in the -- in the simplest sense of the word, finished. Because we now have the ability to create posts and read posts and display them on a page. And we did all that -- I -- I lost count here, but I think we've written 15 lines of code or so.
ANTHONY: Not a lot. It's not done, though, because we don't have auth yet. If we put this online, anyone could go it that route and create posts. This is what happened when you built this the first time.
JASON: We have learned we cannot trust the chat. They will do the worst things. Because they're -- you know what, chat? I believe deep down that you're all good people. But you try to prove them wrong. You hackers, you, you dirty hackers. That's you. All right. So, let's add some auth.
ANTHONY: Okay. So, now we're gonna do a setup command. Setup commands are not quite like generator commands. They won't create as much code and files. It usually changes some things in your project. This will be Yarn, Redwood, setup auth. Yep. And then DB, both underscore, and then capital A, and then auth. So, that will be all one word. DB auth.
JASON: Oh, DB auth. Ah! Behold! My bucket! All right. So, this is the full command.
ANTHONY: Yes. That should do it.
JASON: Okay. Do you want to talk me through what this piece is?
ANTHONY: I have a better idea. First, can you initialize a Git repo -- you're already in a Git repo. Commit everything you have right now. And once this is on, we'll run the diff. This is a good way to see this changes.
JASON: I will commit. Posts are working, needs auth. Okay.
JASON: And now I'm gonna run Yarn Redwood setup auth DB, auth. Now, okay. So, I'm running a setup command. Auth is the setup command I'm running and this is the name.
ANTHONY: Yes. There's other setup commands which will be a deploy one. That will configure for like Netlify or render or something like that. There's setup for auth and then there's setup for deployment targets.
JASON: Okay. Am I overwriting?
ANTHONY: Yes, you want to overwrite. Yes.
ANTHONY: And now if we go back to our editor, as that's going, we'll start to see the diffs that are changing.
JASON: Okay. So, this blew the whole thing away. Let's make this a little bit bigger. And so, we get forget password options, login options, reset password, sign-up. There's a hash password. Okay. So, we're gonna hash passwords. All right. It's doing some stuff there. Let's look over here. We get the current user. Check if they're authenticated, check if they have a role. Oh! We're getting into role-based auth. That's cool.
ANTHONY: Yeah, this is your API, the final handler that it spits out. This is where you take it and map it all together and this is the frontend where you have the auth provider that is your routes and the your Apollo.
JASON: Okay. This did a lot without us having to do anything. And it did stuff that, you know, I think I've talked about this a lot. My beef with a lot of auto-generation stuff is that sometimes it does all the things that I care about and none of the stuff that I want it to care about. Like people will auto-generate these really complex UI components. Okay. But now I have to go and all of this UI. It's changing the owl, here's the auth. Implement auth here, and I'm like, well, that didn't implement auth. What I love about this, from what I'm seeing with this didn't really touch my UI. What it did was made it so that I needed to be logged in in order to do certain commands. But didn't build out a ton of UI or changed the way my app functions. It just wrapped in this auth handler, right?
ANTHONY: For now. This is one way to do it. You don't have to use that if you don't want to. It gives you hooks. It gives you a logged in look and like a sign in/sign out hook. You can use those hooks and build your UI totally from that. Or you can use the -- this is also something if you're using Netlify identity or using something like network, they come with the UIs as well. If you're using a third party one. This is a good one for people who want to manage their own auth and don't want to have to build forms and that kind of stuff that goes along with auth.
JASON: Right. Right. Didn't touch the UI yet, says the chat. That is true, that is true. All right. So, what's my next step here?
ANTHONY: Okay. Next step is -- this will be easier if you just grab this whole hunk of code from the README. So, we have a user model now. And this is going to the other model. We'll add to our Prisma.schema. Yeah. So, if you go down to -- keep going. This is all stuff we already did. Keep going, keep going. Yep. Keep going. Keep going. Yeah. Right there. There's user model.
JASON: Okay. So, I'm gonna get my user model. And so, let's talk through this. We have an ID, okay, that makes sense. We have a name, it's optional. Email needs to be unique, that makes sense. You only get one account per email, store your password, salt. Okay. So, early on in my career, I fully publicly humiliated myself by misunderstanding salts and passwords and how they work. I wrote about security and it was so bad and they had to take it down.
JASON: And part of that is I just got it wrong. And part of that is this stuff is really hard to understand.
ANTHONY: Oh, yeah. I know.
JASON: Can we talk through a little bit, what does this mean? What does it mean to salt a password. I'm so sorry if I'm putting you on the spot.
ANTHONY: No. It's -- once you get the concept I don't think it's really that complicated. The main thing is that we won't know the pass word. And we can look at this once we create this, look at Railway database. See what's in the database. It's not the password we used to create it. We can take the password, run it through an algorithm that does cryptography on it that spits out a key. And you can spit out basically multiple keys from keys and then that's how you end up having ways to verify the original one from the password without having to actually look at the password. It's basically cryptography stuff that is based on encryption. And how do you encrypt it and access it and verify the thing you think it's supposed to be without having to have it yourself? That's kind of the purpose of it and that's kind of what it allows you to have your data save in the database without being exposed if someone hacks your database and sees what's in it, they won't necessarily get the passwords.
JASON: Yeah. And the big thing too when you're looking at salts is you have -- so, I have a password, right? So, let's say my password is the word "secret." Shouldn't make that your password. But my password is the word secret and we're gonna put that in a database. If they get the database, they have my username and password. That's bad. Cleartext is bad. So, the next step is let's use some kind of an algorithm, MD5, one of the other ones, to turn that into a random spring. And then in order to check the password, every time I log in, we have to run the hash to generate the hash and compare that to the database to see if the hashes match and see if they're logged in. The problem with that, then if someone figures out the algorithm, they can brute force this, run every word in the dictionary, every combination of characters until they find the hashes and start guessing. I think your password is this or that. Then if they get the database or access to the hash table, they can do comparable matching. Once somebody generated a rainbow table, which is every possibly output hash. You can look if your hash is in the rainbow title. And you can log in and have access. What a salt does is you give your app, or this particular like password hashing thing a random string that's unique to your app so that even if I use the same password, secret, with two different salts, the hash that ends up in the database is different, right? And why this is important is it means that now someone would have to redo all of that work of guessing every possible password in order to get your set of hashes. Without that, anybody who cracked that one particular algorithm's like full set of hashes, those could be shared around. They could be applicable to any app. So, the salt basically breaks that sharing of rainbow tables. If any cryptographers are watching, I'm really sorry for the details I left out. A salt is one added level of extra annoyance to someone trying to crack your table that makes it take longer and makes it less likely to happen. So, I hope you pass your CS exam tomorrow. Diatribe aside. So, I have copied this now.
ANTHONY: And basically the great thing about that whole segue is that like you didn't have to code that yourself. Like we're getting that because the framework is doing this for us and already is salting and hashing in the passwords for you.
JASON: Yeah. And I mean, this is one of those things that I think is really important is like when I first was working on code, I remember building my own login and I had to do this stuff and I got a lot of it wrong. I don't run any that have code in production anymore. But there's a decent chance that if somebody has been motivated to, they could have cracked my security because I didn't know the difference between MD5 and Shaw 1. I didn't know how to salt properly. All these things. Oh, I just have to obfuscate what the plain text password is in my database. That makes sense. Nobody should be able to see the password. I didn't have the extra layers of context about attack vectors and ways people can get the original password. It's like pixelating text. You look at it, oh, that's secure. And you watch somebody actually into security immediately reverse engineer what was pixelated and tell you what it was said and you're like, oh, no.
ANTHONY: Yeah, that's very true.
JASON: Yeah. It's a rabbit hole, right? It's very nice to be able to trust proven methods that are kind of done for you rather than trying to roll your own. Unless this is a space that you want to be your career. Like crypto is such a good career. There's so much room to get into the security and the anti-hacking and all that stuff. There's a huge community that have if you are interested in that and want to learn more there are great people on Twitter to follow and can help you get started. But if you don't want to do that for your career, trust the experts and try to roll this on your own because you will be sad. Okay. So, I've copy-pasted this user model in here. It's going to do all the work for us so we don't have to be good at security.
ANTHONY: And now we need a run a migration to create the user table.
JASON: And that was Yarn Redwood Prisma migrate Dev?
ANTHONY: Yep. And then dash, dash name. And this time, users. Yep. Okay.
JASON: Off we go.
ANTHONY: All right. Now let's go to our routes file in the web folder. So, in web, SRC, there's a routes.js file.
JASON: SRC, routes JS.
ANTHONY: Yeah. And then in the top import, add the word "Private." So, we're gonna bring in the private component.
ANTHONY: And then that's going to wrap the set. And so, what's happening here is that we have our routes for our project. So, there's a home route right now that we created. And then there's what the scaffold created there which is all of our posts. Like new post and then post and post ID and all that kind of stuff. And then in private, the top private tag, add now unauthenticated equals home. Yeah.
JASON: Like that? Or like this?
ANTHONY: Like the word home, all lower case.
JASON: Home. Got it.
ANTHONY: Yeah. Just like that.
JASON: Oh, here, it's the name.
ANTHONY: Basically, what it does, it redirects you. If you try to go to any of those routes, it kicks you back to home.
JASON: Gotcha. All right. Theoretically speaking, if I start this right now when I do to try to hit my post route, it's gonna bounce me to the home page.
JASON: Okay. Let's try it. Keep hitting up. Up. There we go. There we go. Nope. I had it. There it is. And off we go. And here is my -- so, this is pre-loaded. So, let me reload the page and see if I can stay here. Get out of here! You don't have permission to do that! I like that it does that. Okay. So, it tells me that I'm not allowed. That's fun.
ANTHONY: First, let's do this. Let's make it so that we still do see the posts on the home page.
ANTHONY: Because we don't want those to be private. So, go to -- this is gonna be back in our SDL which is in our API folder. So, this is pretty cool.
JASON: API folder.
ANTHONY: This is also new and something that wasn't here before. So, under -- yeah, functions. There you go, GraphQL, that's the one.
ANTHONY: We have require auth. This is directives. This is because we're using GraphQL helix and envelope under the hood. We may actually be switching to yoga very soon. But point is, we're using like guild GraphQL API servers and there's a lot of built-in directives to give you auth. This is why we can't see it right now because require auth is on. Both our -- both our post queries and our mutations. So, we're gonna change require auth to skip auth.
JASON: Just on the query, right? Okay. So, we have the ability to read all posts in posts. And the ability to get one post by ID. And both of those will work without requiring authentication. And that makes sense because once you've published a post, it is public information. That's the idea. We want someone to be able to see our published posts. That's why we're comfortable skipping auth. But we don't want someone to be able to create, update or delete posts without auth, which is why we keep it required here.
ANTHONY: Yep. Exactly.
JASON: Okay. All right. I got you.
ANTHONY: Now let's run one more command. Which will be Yarn Redwood generate and then just DB auth with the same casing that we have been doing before.
ANTHONY: So, this will actually give you the login and sign in form.
JASON: Okay. Happy authenticating! Okay. So, yeah. Built some files for us.
ANTHONY: Okay. Let's go back to the README also. This is gonna be easier to just kind of grab a hunk of code. So, scroll down a little bit more. Past that. We just did that. Yeah. That right there. That's gonna be our whole kind of login deal.
ANTHONY: Yep. There you go. Also have a couple reports you're gonna need.
JASON: Drop this in here.
ANTHONY: And then there's a couple things we need to import also. You need to import use auth. Yep. And then that's from --
JASON: We auto-populated here, is that correct?
ANTHONY: Yeah. That's the one.
ANTHONY: And then also import a link and routes from Redwood router. And that's because we need to link to the login page on our login button.
JASON: Lower case routes.
JASON: Okay. And then we'll stack these properly. And then it looks like I need to --
ANTHONY: Yeah. So, const is authenticated, and current user and log out. Cool.
JASON: Boy do I love autocomplete.
ANTHONY: I know, right? I think that should be it.
JASON: All right. Let's give this a shot.
ANTHONY: Actually. Then we just got to set one other thing. So, go to our API SRC lib folder.
JASON: API SRC lib.
ANTHONY: Yeah. And then auth. Yeah. And then go down to current user. And where it says select ID true add in email true also. Yes. So -- yep.
JASON: And what we're saying here is this is Prisma. But we're able to -- we're saying which fields to include. So, we want the user's ID and their email.
ANTHONY: The reason we're doing that is we want to be able to show the email on the page when we're logged in.
JASON: Right. And so, we could also get like their name. And theoretically, you could get this stuff, but probably you shouldn't.
ANTHONY: Right. Yeah. Okay. That should be everything. Now let's do the thing and see what happens.
JASON: Do the thing. Okay. So, here's our home page. We can see the posts now because they skip auth. And we can log in. Yeah. Okay. I don't have an account so I'm gonna sign up. And we're gonna set a username. Password. I'm now logged in. Oh, and I set a username, not an email. So, that's -- that's okay for --
ANTHONY: That's one thing -- and that's a little confusing because we give you an email and it says username in the UI. That's a little naming thing we have to work out. But this is fine because we don't necessarily need an email to make this work. The whole point is the password and a username.
JASON: Yeah. What will break on this is all of our password reset flows are probably not gonna work anymore because they'll try to email it here. But otherwise, this is all fine. And that's a -- that's a thing that is relatively straightforward to fix. I would just need to go back and update this to say what? Like get in here and just make it say... where is my auth? Is that a thing I can touch? Or is that straight out of Redwood?
ANTHONY: What are you trying to find?
JASON: This sign up form that I just used. If we wanted to set that to be -- to say email?
ANTHONY: Yeah. So, that's in the frontend on one of the -- the pages. I think it's a sign-up page.
JASON: Sign-up page. Yeah. So, we would be able to say, sign-up. And we would say...week keep username, I guess. But we'll say email. And we'll make this validation required. We probably want to set to be something else. But can I set a type on here? No.
ANTHONY: Like a TypeScript type?
JASON: I was just gonna say type email because it's an input.
JASON: Because it's an email. It would yell at me if I put anything other than email.
ANTHONY: Yes. That is React hook form where the forms are coming from. You can just write regular HTML forms if you want or use your own libraries. So, by default, they use the hook --
JASON: Somewhere in this library if I go and research it, I will be able to find how that works.
JASON: I don't think I care about it right now. That's fine. We know. Now we know. All right. So, I'm logged in. And that should mean that I can go to posts now. And I can. Now I'm gonna create a new one. I can now edit. Okay. Very cool. And then when I go back... there it is.
ANTHONY: So, this is kind of a problem with this, though. Which is that right now anyone can go and sign up and get an account and start editing everything. So, there's two possible ways you can go here. The way you want to go long-term is you want to then build in authorization. And so, we have R back and rolls. That's already kind of built in. There's a very long doc on how to do that. But what we can do right now is we can just go into our auth function. So, this is in API SRC functions. Auth.
JASON: SRC functions. Got it.
ANTHONY: Yeah. And then we're gonna go down sign-up options. Yeah. And then basically make that return false instead of DB.user.create.
JASON: Okay. So, now that I've created my user.
ANTHONY: You will take the ability to take the user away. You can log in with the user you created, but no one else will create a user right now.
JASON: Okay. So, now if I go back out -- are we still running? We're still running. So, I'm going to log out, log in. Try to sign up. And then it's like, naw, you can't do that. And we would probably in a real app, we would obviously build more controls here. But... and I can still log in. So, here I am.
ANTHONY: Sweet. All right. Now we are at the deploy step. So, we'll do another setup command. But this time it will be setup deploy Netlify.
JASON: Okay. Hold on. I want to do one thing. Because I'm always curious how this step works. Which is if I go into this home page here. And we've got our blog post cell. So, let's go to the blog post cell. And this is returning one of these. Now what I'm gonna do is I'm going to make this into a pre. And I want to add a link and I want that link to be -- to do a post. And then I'm just gonna make it the item.id for these. And say, you know, view post. Right? So, I've -- I make this. I come out here. How do I make this work? Like what's the Redwood process for doing this sort of thing?
ANTHONY: Yes. So, there will be route parameters that you will have to add into the router or file. So, if you go look at the router right now, you can already see this with how the posts are set up.
JASON: Router, routes file.
ANTHONY: Yeah. If you look in the post layout, we have forward slash posts and then ID. You'll basically have something like that. So, this is something that is like in the -- the docs. I'll drop this in the -- in the chat.
JASON: Does that exist? That post show page?
ANTHONY: So, yeah, this is something that takes a couple steps to kind of do. And I don't really remember how to do -- that's right. So, you basically just add a forward slash ID in brackets after post.
JASON: Okay. So, I've got post, brackets, ID. And it looks like I can force it to be an integer here if I want to cast it like that. And then it will pull up a page and that page would need to be something like this. Which we're not gonna build right now. But what would end up happening is we would get this -- this page would then render. And the way that that page would render is would I get the params like in here?
ANTHONY: It's kind of like how you have the dot routes already. You have routes.login, that's where you would pass it in. If that was the for the -- for the post. So, you would have like routes.post and then in parentheses, ID, post. ID.
JASON: Got it. Project for another time covered in this doc here that is in the chat. And -- or, wait. This is --
ANTHONY: That's not the one.
JASON: That's not the one. Okay, this is the one. Let me pull this up. This is the one, routing params.
JASON: And that will show us how to do that.
ANTHONY: That's fine. You asked that last time I was on also. I was like, we don't really have time for that.
JASON: Okay. All right. So, we are ready to deploy.
ANTHONY: Yeah. So --
JASON: And you already told me what to do and I stopped paying attention. One more time.
ANTHONY: Yarn, Redwood, setup deploy Netlify.
JASON: Okay. Ready to deploy Netlify.
ANTHONY: And let's go back to looking at our Git diffs and look at your Redwood.TOML.
ANTHONY: So, here what's happening is we have the API URL. This is how the frontend and the backend, they know how to talk to each other. This is like a GraphQL lambda-lith. It's the function, it's a GraphQL endpoint. You can say whatever you want. You can say forward slash API if you're hosting it somewhere else. But this is the configuration, that's done for you with the setup deploy command.
ANTHONY: And also is the Netlify.TOML.
JASON: Build command, publish directory, where they live, redirects to sends everything through the main function. Okay. Cool. So, then what should then happen is like now if I run Netlify.dev, this should also pick up and run. Very exciting. Here it goes, here it goes.
ANTHONY: You have two environment variables. The database environment variable and it also generated a session secret for the DB auth. So, you need both of those in the Netlify project.
JASON: Where did it?
ANTHONY: In your .env file.
JASON: Okay. So, check this out. I'm gonna run Netlify init. And it's going to let me create and configure a new site. But on my team. And we'll call this RedwoodJS 1.0. Or I guess it will be 1 --
ANTHONY: Just v1.
JASON: Whatever. V1. That's so much better than what I was gonna do. Here we go. That's going to -- yeah. That's -- I'm just gonna let it import because it's already configured. Good. And then I'm gonna do Netlify env import.env. And hopefully it's not gonna show all these on screen. It did. Dang it. All right. I'll go have to roll that secret. So, that, then, is all now stored so that if I run Netlify Dev again, check this out. It pulls in the database URL and the session secret now from Netlify. But because they're in the environment variable, they -- the .env overrides. So, that is very nice. Okay. So, give me just a second to roll that.
ANTHONY: Actually, there's a command that will just spit out another key for you.
ANTHONY: Yarn Redwood generate secret. But also you don't want to do that onscreen. JASON. Right. So, I'm gonna run this one, auth, okay. There's my secret. I'm going to go over here -- you hackers! You, you dirty hackers. That one's already compromised so y'all can look at it. Let me change this one. And I need to go and get a new key for my database because I screwed that up.
ANTHONY: And Railway has a button called wipe plugin data in your settings and it will wipe the whole thing and also generate a new connection string for you.
JASON: Nice. Wipe plugin data. Actually, let me show this on screen. I went to settings. Wipe plugin data. Wipe data. Get out of here. Hold on to your hats. I really wish that said "Hold on to your butts." Okay. So, I am gonna have to rerun my data, right? But what I can do is go to my connect and then I can just copy this. Nobody can see my secrets.
ANTHONY: Copy at the bottom one, not the top one.
JASON: Oh, right.
ANTHONY: The top one is really cool. It's a whole command to set up PSQL.
JASON: Nice. Okay. So, that is saved. And now I need to run the command one more time. So, first, let me Netlify.env, import.env. And that will override those. Okay. Clearing my screen. And now I can come back over here. And then I need to run Yarn, Redwood, Prisma, migrate Dev.
ANTHONY: Yeah. And just like that. Because you don't give it a name at all.
ANTHONY: Because it already has the migrations in there. That's gonna rerun.
JASON: Okay. Cool. Cool, cool, cool.
ANTHONY: Okay. You have two migrations, I'm gonna apply those to your database. Boom, boom.
JASON: Nice. Oh, dang it. All right. Just props to the Prisma team. This is -- this is very well done and very nice to use. Okay. So, that's ready. And then what I can do is checking Git add everything, great. I'm going to Git commit M and we'll say feature ready to deploy. To push. And now if I -- if I open. Pop this open for us. There it is. It's going to be deploying. And if I go look at my site settings, and the environment, we can see that those values are set through that CLI command. But it didn't start building. Which makes me wonder... if something went wrong with... let me just check here if the Git setup is done. I didn't link a GitHub repository. So, that's -- I must have hit a button or something. Let me go back here. And we're going to -- it was Redwood.
ANTHONY: Yeah. It's still one of the things I always go through the UI to do. Copy-paste the keys. And so, there is where you put your keys in also.
JASON: Yeah. If you need them. I should have stayed there for a second. There's a button that will let you add environment variables. But I like feeling like a hacker. It makes me feel like I want to put my sunglasses on.
ANTHONY: It's better for tutorials if there's a way to do it with a command because it removes the room for error.
JASON: And so, now we are going to deploy. And let's play a memory game while we wait. It should take just a minute or so.
ANTHONY: That's funny. I've never seen this.
JASON: Yeah. All right. All right, all right. How good is my memory? Let's find out. Oh, boy. [Hold music...] Oh, no. Yeah! Did everybody see me nail that? All right. Is it done?
ANTHONY: Okay. So, there's something else we can do while this is going.
ANTHONY: Hopefully we'll be able to make it. If we go back to our project, we're gonna create another branch for the render deploy. Yeah.
ANTHONY: And then now we're going to run Yarn Redwood setup deploy render. But then with a dash lower case d and then none. Yeah. So, what that's doing is we can tell it to spin up a postgres database or a SQLite database like on render for us and connect it to our project. But since we already have a database, we don't want to do that. We're gonna set this up and then use our own database.
JASON: gotcha. What we're doing here, what we did before was the full serverless deploy. What we're doing here is the server-full deploy. It's similar to Netlify, you create a Git repo, and create it and deploy. But it's for a long running server. If you're building a microservice, or if you want the service to be running for a long time, you do it on something like Render. I actually use it for the chat bot and everything in the Twitch. The API is using a GraphQL subscription which requires a long-running server. And that is run in Render.
ANTHONY: And then that created a render.YAML file. This is the only thing we need to make sure that it knows how to do the rewrite. So, the route redirect for your functions.
JASON: Yeah. I just pulled everything offscreen. Let me make sure I close that. Yeah, okay. So, go into render.
ANTHONY: Yeah. And then where it says replace with API URL. Under next to destination.
JASON: Destination, replace with API URL.
ANTHONY: Yeah. Change that to HTTPS: //and then so, this is where hopefully it's going to be -- okay. Yeah. So, I think as long as we sync up these names it will be correct. Do Redwood, yeah, Redwood/LWJ. Sorry, dash, not slash. Yeah. And then dash API. Yep. Dot onRender.com. Yeah. So, basically what this is is when we spin up this project onRender, it's going to give us this URL for the API. You have to make sure your front end know what is it is. This is going to be different depending on what your project name is.
JASON: Okay. Gotcha.
ANTHONY: And then there's one thing to add, this is cores. This is a little obnoxious. But something you got to do. So, we're going to go to our API SRC functions folder.
JASON: API SRC functions.
ANTHONY: And then GraphQL.js. Yep. And then under services, add in cores. Yeah. And then colon and then make like an object. Yep. And then it will be origin. Yeah. And so, that's gonna be the exact thing you just wrote except web instead of API. Yeah. So --
JASON: I got you.
ANTHONY: Copy/paste the thing. Just copy/paste that whole thing.
JASON: Here. And web.
ANTHONY: Yeah. And get rid of the forward slash star. Yeah. Just like that. And then add credentials include. Yeah, so, the reason we need to configure this is we're doing the DB auth thing and we're passing this cookie back and forth. If we didn't have any auth, we need to do this and there wouldn't be any course issues.
JASON: We're moving it between the web and the API. So, these need to be able to talk. And these, you know, these become cross-origin because these are two different websites.
ANTHONY: Yep. And then now there's a auth file right next to GraphQL file in your functions folder.
JASON: Do I need to copy-paste this?
ANTHONY: Yeah. Sure. It's basically gonna be a similar thing. And then go to auth handler.
JASON: Auth handler.
ANTHONY: And it's that the whole thing. So, then just plop it in under auth fields. Yeah. And then make credentials say true. And without the -- yeah. Just like that.
ANTHONY: And then I think that's -- and then one other thing is under cookie. Change same site to none. Okay. I think that's everything on the backend. We just got to do one thing in our API.js file. Sorry, app.js. That's in web SRC. Yeah.
ANTHONY: And then where it says "Auth provider," you're gonna add in -- actually, go back to the README. Let's just grab this. Grab this whole thing from the README.
ANTHONY: Scroll almost all the way to the bottom. Yeah. That last thing.
JASON: This thing?
ANTHONY: Yeah. Just grab that whole app thing and replace it with your current app.
JASON: Okay. Is... ah, okay. So, let's go here. And then I'm gonna go to app. And what I'm changing --
ANTHONY: Yep. That whole guy. Yep. What happens is we're just adding in the config for the credentials. And then you also have to do a thing for Apollo to make Apollo happy.
JASON: Got it. Okay. So, basically, we're just saying because we're making cross-origin requests, we just have to update these two pieces. All right. That makes sense. And then I'm not gonna lie. I don't remember how to deploy to render.
ANTHONY: Yeah. Luckily we're all set up for the most part. So, just push this up.
ANTHONY: On to the render branch that you've got.
ANTHONY: Cool. And then that's probably done also.
JASON: This is done, yes. It's been done for a bit. It took -- let's see. How long did it take for the first deploy? 2.5 minutes for the first deploy. Follow-ups should be faster because things should be cached. Let's double check. Should all be running as expected. Okay. Login. Oh, this isn't gonna let me sign up, is it?
ANTHONY: Yeah. You can't sign up. You can just log in.
JASON: It's not looked up to my database anymore. Because I didn't --
ANTHONY: Go back. That's right. Because we had to wipe the database. That's funny.
JASON: We'll have to fix that later. For now this is doing what we want.
ANTHONY: And it shows empty so it knows there's a blank database there. Otherwise it would show --
JASON: Okay. And then I have render here. This is my actual Render account. This is the socket studio API. That's what powers the stream overlay. And I need to create new, right?
ANTHONY: So, you got to do new blueprint.
JASON: New blueprint.
ANTHONY: Yeah. This is because we have the render.YAML file. And depending on your permissions, might need to click GitHub and give it permissions to that specific repo.
JASON: Yeah. What's my -- I'm in too many -- at this point. Install... okay. Let me pull this off-screen for a second. And okay. I'm logged in. And I can choose this one now.
ANTHONY: And then give it the name Redwood-lwj. Yeah. And then --
ANTHONY: Yeah. Okay.
JASON: Okay. It's gonna create both of these.
JASON: Hit apply. And then now we each got to add in the environment variables. This is actually something they let you feed it like a .env file, which is kind of cool. But go to your dashboard.
JASON: Am I doing something --
JASON: Is it done?
ANTHONY: Yeah. This is weird. It started already and it doesn't give you a lot of good feedback. Just go back to dashboard.
JASON: Okay. All right.
ANTHONY: And go to API. And this is where we're going to put in the environment variables. So, under environment. Now you can do it through there. Or you can do secret. So, go down to secret files. Yeah. And just do that and copy-paste what's in your .env into that.
JASON: I just drop in the --
ANTHONY: You want to do that off-screen.
JASON: Okay. go to the --
ANTHONY: And we're doing a couple things we shouldn't did doing for the sake of the demo. You should generate a different session secret every time. This is what you do for the different deployment providers. Right now we're going to use the same one because it's quicker and easier to do.
JASON: And importantly, because it's not free, I'm probably not going to keep the render deployment up.
ANTHONY: That's actually not true. They have a free tier now.
JASON: Awesome. That's great news.
ANTHONY: It's a couple months old.
JASON: I've saved my secret file here.
ANTHONY: Cool. Just make sure the build re-ran. It should tell you. Go to events.
JASON: Deploy canceled, another deploy started.
ANTHONY: All right. Cool. So, that's gonna take a while. This thing, it takes like 10 minutes to build. Hopefully it will build before the hour is up. So, questions, reactions.
JASON: Yeah, yeah. So, chat, if you've got -- if you've got questions now is the time. What are you -- what are you feeling?
ANTHONY: And then is like have things been like coming back as you have been doing this? Or did it feel like learning Redwood a whole second time?
JASON: My experience with Redwood has actually been limited to the time that I've spent with you. I would say I remembered -- like I remembered the generate commands. I think this is what's interesting is Redwood embraces a school of thought that, you know, lines up with Rails, lines up with Angular which is the idea of convention over code. So, you don't write code. You tell the -- you tell the generator, the CLI, what you want to do. And it generates most of your code for you and then you do light customization for that. And that is something that I think is really interesting because what it leads to is when I go into an Angular codebase and presumably when I go into a Redwood codebase, things are gonna be in the same places. Files are gonna be organized in the same way. The router are gonna be set up the same way. I'm not gonna have to try to figure out like what is this web team's style to be able to start piecing together how their apps work? Because a lot of the generation just makes those decisions for you. It makes things very predictable in setup. And so, the good -- like the upside that have is just extreme portability of skill. If I become a Redwood Dev I can go to any team working with Redwood and be fairly familiar with the codebase because so much of that convention is handled by the CLI. I like that about generators. It gives the predictability and the safety. That's the things I like about the approach. The tradeoff is in a plain React codebase, somebody does whatever they want. They set up their own file folder structures, their own naming conventions. Everything is kind of organized a didn't way. That means that each React codebase is extremely flexible. You can build whatever you want in there. But also, each codebase is an extremely unique animal. And typically you're gonna find it takes a little bit longer to get familiar with that codebase. So, that tends to be my -- my general like the tradeoffs, right? If I'm working on a big team, especially if I'm working on a team that's people who don't necessarily want to be web Devs, like when I was at IBM, a lot of the people there were writing UIs, to the because it was their job, but it was a thing that had to happen because of other development duties. And having something that automatically sets them up with good practices and good code and conventions is good practice. I think that's why Angular is so popular in the enterprise. It provides that convention where things are predictable. You're not asking an engineer who is primarily working in Java and just got stuck with a ticket to build a UI to go out and figure out how to write a good UI. Angular generate this is and that. And Redwood look like it's solving that problem in a way that's more -- I guess more like batteries included. Because I think that's something Angular has struggled with a little bit. And I think they're working on solutions. I think there's -- I heard rumors that some cool stuff is coming with Angular. Stay tuned. Maybe we'll see you on the show. But the power of being able to go to your team and say, just use the Redwood generator. It's gonna look the way you want, it's gonna have accessibility built in, have best practices and set the meta tags. That's really powerful to a team that is, you know, like we're not talking about web artists here, right if we're talking about people who need to ship production code and they need to do it quickly and they've got 10 million thing on their plate. If you ask those people to hand -- to lovingly hand craft code, they're gonna take shortcuts and you're gonna end up with problems. If you give them a generator like this, they're gonna get to a good outcome. That's a big tradeoff to consider when you're weighing which tool to build something with. But we've got some good questions here. Let's see. The first is more of a meta question. Tony is asking, what is the generator that Redwood is using.
ANTHONY: I dropped a bunch of links in response. It's using yargs in the Redwood codebase, you can create your own generators. We were trying to create a generate generate command I think. You can generate your own generators. I don't think that ever worked out. But if you look at the code, you can see how we set up our generators. And you can modify them. If there's some sort of generator you want, it's very easy to contribute to. That's why there's all these case to generate all this stuff now.
JASON: Yeah. And chaotic good boy, which I have to imagine that avatar is a dog. Chaotic good boy, it's got to be a dog. Like a small dog. Yeah. mes. I think the -- chaotic good boy says it's funny that this criticism is levied by React by teams. I always chose to go with Angular. You can go wild with Angular too. That is true. With sufficient effort you can make any codebase utterly off the wall wild. But. I think the difference is where the defaults lie, right? I think Anthony, you and I have talked about this before. The importance here is where are the defaults, right? What are the -- which parts of the -- of the machine are you being handed right out of the gate that you have to consider? Right? And you know, you mentioned that with Redwood, with Rails, what you're getting is a lot of batters included, you don't have to make this decision type guidance. And I think that when that's the default, it leads to on average, you know, because code cowboys are always gonna be there, there's always somebody stoked to go in and customize everything completely. You're going to get a good outcome.
ANTHONY: Rob is correcting me in the chat. We do have the generate generator command, but it's set up command. He lost the battle on the generate generator space.
JASON: Generate generator. World of Warcraft corgi pet. We do have a generator generator. That is great. Okay. Cool, cool. Yeah. This is -- I don't even know if I have any other questions. How about this, while we're waiting for this to deploy, what resources should people be looking at?
ANTHONY: Yeah. RedwoodJS is gonna be a good place for revamping and consolidating docs and tutorials. We have two in-depth tutorials. One that will walk us through pretty much everything we did today along with a contact form and layouts which we kind of skipped those steps. But the first tutorial is kind of all that. And the second tutorial goes into testing and storybook and all the other files being generated. Because you're automatically configured to run tests and set up your storybook and do all that. And then we have the individual doc pages. Subjects and how to configure environment variables and do all the different deploys we have. And so, that is all now merged into one site, which is nice.
JASON: Nice. I see Rob is saying this is a Docusaurus site. That's very cool. So, we'll drop this in here. Anywhere else people should go check out?
ANTHONY: We have -- all of this would be on RedwoodJS.com. We have a Discord. We have a Discourse forum. We have a Twitter account where you can follow us. We have a newsletter. Let me grab the newsletter. That's actually something that is just picking back up.
JASON: Nice, nice. And let's go peek at render. Now is that going? No pending migrations. Okay. So, we got some links dropping in here. And copy this one. So, this is -- now, what is curated? Is that the newsletter system?
ANTHONY: Yeah. I'm shot how are exactly how they set that up.
JASON: Oh, notice.
ANTHONY: We had one over a year ago. And this is kind of like our new, newly put together one.
ANTHONY: If you share the first issue actually at the very end, we have this heroes of Redwood thing. So, that's Danny. A little bit further down. Yeah. So, someone on the team and they highlight them and kind of give them a chance to tell their story and talk about what they do. It's cool.
JASON: Nice. I love that. That's super-fun. Okay. Cool. So, this is a cool place to go get information. And I assume this is probably one of the first places that people are gonna hear about things unless they're in the GitHub actually watching development, right?
ANTHONY: Yeah. Here and the Twitter would be the main places.
JASON: gotcha. Cool. I think we are almost done here. Looks like it's -- oh, wait, does that mean done?
ANTHONY: Hopefully. I mean, check it out.
JASON: All right. Now to check it out -- so, it says it's still in progress. I'm going to reload the page. Okay.
ANTHONY: Yeah, yeah.
JASON: To see that --
ANTHONY: You want to see the web one, not the API one. So, go back to web. So, go to your dashboard. Yeah.
JASON: Dashboard, web.
ANTHONY: Separate services. One is a static frontend and one is actually a web service thing.
JASON: Got it. Looks like Redwood doesn't like something about that API response. Let's... peek at it and see if...
ANTHONY: We probably just messed something up.
JASON: We messed something up, it looks like. Response headers. It's a miss. Not sure. Yeah. It's just straight up 404. So, we did something wrong. But -- oh, is it because it's not a -- does it need to be like a prime URL? That would mean that API isn't working.
ANTHONY: Yeah, that's an issue, yeah.
JASON: Got it. Okay. We would have to go fix that. We don't have time to fix that right now.
ANTHONY: Yeah, try to compress it into a couple steps. Normally deploy it, get your link and -- but then I tried to jump the gun on that. The original repo that you forked from has the complete render project as well. I think the code is basically all good, just fix the domains.
JASON: Yeah, get the domains fixed. The problem is a 404. Not something else. That will clean it up. So, with that being said, we are going to jump back out here and remind everyone that this episode, like every episode, has been live captioned. We have had Amanda with White Coat Captioning here with us all day through support from our sponsors, Netlify, NX, and Backlight all kicking in to make this show accessible and I appreciate very much. Make sure to check out the schedule. We have got a bunch of stuff coming up, Hakon, teaching us how to get a page speed of 100. That's hard to do. We're going to talk about that using Remix and crystallize. And tRPC, a whole bunch of stuff. I have things in my email that I haven't posted up. Make sure to go and give Anthony a follow on Twitter. Anthony, any parting words for the chat before we call this one done?
ANTHONY: Just thank you for having me. I hope people will check out Redwood. I've gotten a lot of use out of it through the my time in it. And just have really enjoyed the community and just learning alongside everyone and getting to -- yeah, check that out.
JASON: Awesome. All right, y'all. We are going to -- oh, no. Nobody's live. Chat! Who should we raid? I'm gonna take us offline here and call this one over. But let me know who we should raid and we'll go find somebody to raid. Anthony, thank you so much for hanging out. We'll see you all next time.