Check out a free preview of the full Introduction to Node.js, v2 course:
The "Building a Reddit CLI" Lesson is part of the full, Introduction to Node.js, v2 course featured in this preview video. Here's what you'd learn in this lesson:

Scott creates a Reddit CLI tool that fetches a random post from the Reddit API and opens the post in a web browser. If a '--print' flag is passed to the CLI, the title and description will be printed to the command line and the CLI will not open the browser.

Get Unlimited Access Now

Transcript from the "Building a Reddit CLI" Lesson

[00:00:00]
>> Owing to the part of making this actually do something, we're gonna need some help. Because I said we wanna be able to hit the Reddit API and then we want to be able to process that information and then open up a random post from the Reddit API into our browsers.

[00:00:15] That's a lot of work that I'll probably not gonna reinvent from scratch. I'm definitely not gonna use the natives HTTP module and open up like socket connections and manage that and, no, I'm not gonna do that. I'm just gonna rely on some people smarter than me, who already created some really nice packages that I can install.

[00:00:31] And we're gonna do that, so I have the packages listed here. And what we're gonna do is, we're gonna install one code open, one code node fetch and one code yarks. So we talk about these very quick. So open literally takes a URL and it opens it up on your default browser on your computer.

[00:00:47] So that's what's going to open it for us. Really cool. Node fetch is exactly like window dot fetch, if you've ever used that before, it's just the nodes polyfill version of that, so it works the same way. And then yargs is basically a function that's going to interpret and in process, I don't use that word, somebody use it twice.

[00:01:10] It's gonna interpret the process objects for us. So we need to get access to things like flags and arguments to a Reddit CLI. Because I do wanna pass an argument, I'm sorry, I wanna pass a flag to it. That's gonna allow us to bypass opening the browser and instead just print it out on the terminal.

[00:01:29] Maybe I don't want my browser to be opened as my boss is over my shoulder. But I just wanna print it out on the terminal, so I can see it. So we can just pass the flag that says like print instead of open and that's what we wanna do.

[00:01:39] So we wanna be able to interpret that a little easier. So we'll use yargs for that. So follow along with me, but I also have all the code here that you can copy and paste, but I'm pretty much just gonna go through this, and then we'll figure it out.

[00:01:52] So first thing is, let's get our imports going. So we're gonna import, we're gonna say fetch. Well actually, before we import, let's actually do our install, right? So let's say npm install, and by the way, you can do I for short for install. So you can say install or you can just say in npm I, which is less characters.

[00:02:12] So npm I node fetch, we have open and then we have yargs. I'm gonna save those. And remember, save puts it in our dependencies, which we have here. Boom, we got our dependencies, we're good to go. And now I'm gonna import them, so I'm gonna say, fetch from, no fetch.

[00:02:34] I'm gonna say open from open, and then yargs from yargs. I think yargs, I did have a problem with the interrupt between common j s and yes six, I'm just go look to make sure I got that one right, I guess it was fine muslin Southern I was doing.

[00:02:55] Okay, the next thing we wanna do is, let's try to process any potential arguments we might pass on and like I said, I did wanna pass in a print flag that's gonna bypass the opening of the browser. And depending on what that, whether that's passed or not, that's gonna determine what other logic we have.

[00:03:12] So we should probably process that first because we need that information. So I'm going to do something called, say yargs. And that's a function and I can pass in process dot argv. And basically what this is, just to I wonder if I can log this. Yeah, I can log this, I'll try to think if there's gonna be anything sensitive on there.

[00:03:34] Yeah, I'm gonna just log this for you so you can see what it is. So process.argv, and then I think you'll get the idea. So we don't have to install a CLI again, It's already linked. It's a live file so we can just run the read command again.

[00:03:47] So you can see proces.argv, it returns an array. The first two things are always gonna be the path to the interpreter which is note, and then a path to the CLI, which is Reddit, and everything else after that it's gonna be like arguments and flags. So for instance, if I wanna say Reddit, then I wanna say print, like that.

[00:04:06] You can see it's passing as a third index, index number two into this array, or if I wanted to pass an argument like, hello, you can see that it literally goes in order from left to right, right? That's how it works. What yargs is gonna do, it's going to process this and put it in an object for us in a key value way, That way we can use it a lot easier.

[00:04:30] But there's nothing stopping us from just doing RGV Bracket, split everything before, split everything after these first two and just grabbed stuff here that works just as fine as well. I just wanna show you a really nice package that I use all the time. So we're going to process that, we're gonna get the RGV here.

[00:04:46] Like I said, this is going to be an object with whatever flags was passed in, so we got that. The next thing we wannna do is we want to make a call to Reddit. So if you go to Reddit.com and if you go to slash dot JSON, you actually get the JSON output of the entire front page of Reddit.

[00:05:09] Like that. It's really cool. So we should look at this and make this bigger. So look at this for a little bit because we need to understand the data structure because we're gonna query this. So we get back an object with a data property that has a children property, that's an array of children and each child has a data property.

[00:05:25] And on that data property, there should be a URL that we want and I wanna say it's called, have it somewhere, permalink, yeah. So I wanna get the permalink of whatever child we're gonna open, and that's what I wanna get and I'll pin that to reddit.com, slash that sub Reddit, slash whatever.

[00:05:53] So that's how we're going to get our random thing there. So let's make a call to the Reddit API. And the way we're gonna do that is using fetch. So I'm gonna say fetch, or I'm gonna say rez for response equals await fetch. And fetch is gonna take that URL here.

[00:06:14] So reddit.com/.Json. And if you've never used fetch in the browser before, it actually doesn't return the data, it returns a response object that has status codes, error messages, different things like that. And if we want the data from that we have to resolve the promise of turning it into JSON, which is permissified, so that we can get the data which will be data equals await res.json.

[00:06:43] So we'll get that, and just to make sure we are at closer, we will log this, so we do that and boom. What did I log? I logged res sorry, is log data. Okay, so you can see we got the same data that we had in the browser.

[00:07:04] Obviously, it's not gonna print all the objects here, but you can see it's hidden Reddit, it's good to go. And just to show you just how quickly we were able to do this, we imported three things and we're already hitting the Reddit API and getting data. That's really impressive because we were able to leverage the community and different things like that.

[00:07:22] We got to do all this ourselves, we'd be like close to 100 lines of code right now, especially hitting the API. I'm exaggerating a little bit, not that much, but still not as clean as this. Cool. So now we got the data. The next thing that we wanna do is we want to get a random posts.

[00:07:38] So we'll say posts, let's get a random index. And a random index would be, so data.data.children bracket. Okay, let's do this first let's save this in a variable, children equals that. And then now we can say let's get children. Was that math.randomchosen.length? Width? No, it's math.random and then math.floor.

[00:08:20] Children.length times, you know what, I already have this, why am I trying to do this math right now? Let's copy this. There we go. So this is what we wanna do. I do the random stuff all the time, I think I remember this but I don't. Okay, so we're gonna say, there it is, I was way wrong.

[00:08:39] We wanna, math.floor, math.random times children.length, there we go. So this will give us a random child and the child array. You could do ceiling if you want to, but floor is fine. So now we got our random index. And now what you wanna do is just, or actually this is a random post.

[00:09:03] Now what we wanna do is decide if we need to open this post in the browser, or if we just wanna print out something about it. So what we can do is we can say if(argv.print), so if someone passes into print flag they will be one of those who just wanna cancel that post.

[00:09:22] So we'll do something like this. We'll say, title is random posts.title, I'm assuming as a title there will look if it's not then link would be, let's make a link variable here. The link is gonna be HTTPS reddit.com slash. We're actually i think the permalink has a leading slash and I dont feel like cleaning all that up, so we'll just trust it, so be that.

[00:09:58] That'd be the link and then we'll just say, link like that. And then else, we'll say open the link, like that. So let's try it out. Let's see if we can get this to print with a random post and then we'll try to open it up. So we'll say hello, we don't need that, get rid of that.

[00:10:19] But I'll say print and boom, titles I did guess on that so that wasn't gonna work. And then obviously this needs to be permalink or its data, that's why, permalink, and this is data.title. So let's try that again. There we go. So we have title, you see there's a title of a random posts from the front page of Reddit and here is the URL that is messed up because it's not permalink, it must be something else.

[00:10:56] It's not camel case, okay. There we go. Let's try that again. There we go. So we got our link here, and then we got something about the dot lines pretending to be hurt. [LAUGH] Okay, that sounds pretty cute. And it's random every time, so if we do it again, we get another one.

[00:11:15] Now let's try to open this up in our browser. So, how do we do that? Just don't pass the print flag and we should be able to do that. So I'm gonna exclude the print flag, and I will do that, and bam, it just opened up in my default browser which for me is Firefox, don't judge me.

[00:11:31] And I'm not gonna scroll down and hit play on that but you get the point, it opened it up to it, and it works. So really good CLI, feel like Reddit, and you don't feel like gonna Reddit, you wanna see something random. There you go, you can just type in Reddit and get a random thing today and check it out.

[00:11:47] So let's just go back and reflect on the code that we wrote a little bit, just to try to understand it a little more. So we have this hash bang here that tells us to interpret this file in the node environment. We installed these three node modules. And then moving on we were able to use yargs which was able to process the options and arguments passed into whatever CLI has been executed, in this case, the Reddit CLI.

[00:12:13] We use the fetch function here to communicate with the Reddit API and get some data. We process that data, did some random indexing here that I struggled with, and we created a link to that random posts. And then we just did a check to see if someone passed in the print flag or not.

[00:12:31] If they did, just do a log, if they didn't, open it up in the browser. And that's it, and then the process was stopped, it exited down here with a process of exit of zero. There was no other code to run, there are no more background tasks, there's nothing scheduled.

[00:12:45] So it bottomed out and there was no more text to be ticked. And it just stopped and our code was done executing, even though the browser open. And that's basically what happened. So, as you can see, you can get pretty powerful here with a CLI, knowing what you know about file systems, and the fact that we did that interpolation on the HTML file.

[00:13:04] Knowing what you know about CLI's now, you can probably start putting together how some of the really good front end tools that you use work. Webpack as CLI also use the file system. You just did both. So you're really starting to see how these technologies work together, how powerful they can be.

[00:13:20] And this is just a glimpse, if you really wanna make a good CLI, you probably wanna use a CLI framework. Just like there's front end frameworks, there's like frameworks for everything else I'll know too. There's CLI frameworks, there's API frameworks, there's testing frameworks, just like react as a front end framework, there's frameworks for stuff here as well.

[00:13:38] So I would encourage you to see if there is something out there before you try to build something from scratch. I personally wouldn't build an API or a CLI like this. I would use a framework that has like way better support and handling and help message and automations all types of really nice stuff.

[00:13:54] But just let you know that even if you did do it, it's not so bad. So any questions on the CLI? The question was, if you have an object and it logs, object objects, how do you see that? Let's first talk about why it does that and and how we can get around it.

[00:14:08] So, I'm just gonna make a new file here called test a yes, and I'm gonna make an object and we'll make another object and I'm gonna make another object like this, and then we'll put something in here. Okay, and then what we'll do is we'll log this. So, node Test a yes.

[00:14:37] Okay. Wait, that logged all of it. Of course it did. Let me make another one. Okay, let's try that. There we go. Okay, I know how to get deep. So as you saw, I tried to log it the first time to get it to do the object object and it didn't, then I added one more layer and then it did.

[00:14:54] So at some point, the logging mechanism in node is like, okay, you're just going really deep on all these objects, so we're just not gonna log all of them, I'm just gonna paraphrase for you. That's basically what's happening when you have like a certain level of hierarchy of data.

[00:15:08] No GS tries to simplify the output of your logs by just paraphrasing the hey, there's an object here, there's a sub object. And it's actually really helpful, especially for like streaming these logs which you can. You can stream logs from node and to like some provider that you're paying for, a lot of big companies pay millions of dollars per year to have their logs stored, and some even per month like big budgets to store logs.

[00:15:33] So the less logs there are, the less things that are being logged, the less you're being charged and the faster that they are and also just less noisy. When you're really building an application and you have your development server up, you got a lot of stuff to streaming and piping in.

[00:15:47] And you're really only concerned about the thing that you logged and not all the sub things about it. So it's just a nice way to clean that up as well. But like you said, sometimes you do want to be able to see it, so how do you get around it?

[00:15:58] Well, there's two options. Well, you just log a little closer to what you want. So instead of logging O, I might log o dot u dot L, and then now I'm able to see that because I logged a little closer, so that's one way. The other ways you can do json.stringify and then pass in O, and then pass in no and then you can pass it like how many indent spaces you want.

[00:16:22] I like to indent by two, so I can do that, and then it'll print it out like that, the whole thing. It won't be nice and beautiful and colored, like the rest of the output is because you're technically just logging a string, but it'll be formatted and it'll show every single thing all the way down to the, closest child.

[00:16:39] So those are the two ways you can get around that.
>> You were passing flags, right? Like reducing double hyphens can be passed parameters choosing just one hyphen and does recognize that?
>> Absolutely. So we can do the same thing, so I can say, argv.prince, or argv.p right?

[00:17:03] So let's try that. So, if I say, do that. And I think maybe capital P. There we go. Yeah, so if it's a capital with a shorthand, then it will Reddit for you.