Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

JavaScript Build a Simple Dynamic Site with Node.js Handling Routes in Node.js Populating User Information

Greg Wienecke
Greg Wienecke
126 Points

The user route is always called, but the code in user route is only executed if the username.length > 0. Is this normal?

(I used the teacher's code from the downloads for this test, not my own)

I put a console.log("in home route"); line into the home route function and I put a console.log("in user route"); line into the user route function.

When I make a request to localhost:1337/ it outputs both of those lines ("in home route" and "in user route") to the console so user route is still getting called, it just doesn't execute the rest of the user route code.

When I make a request to localhost:1337/chalkers, the console outputs "in user route" twice. Has anyone else run into this or figured it out? Is this normal/expected?

I noticed one or two other questions where there was some confusion about how the user route request.url.replace("/", "") was working, and I'm wondering if this is really the best way to handle the routing?

Ok I just tried adding a console log before the if and after the if, and when I make a call to localhost:1337/, both of those lines get logged to the console twice. I wouldn't expect the conslole.log line after the if statement to get called if the username is not greater than 0 and I don't understand why they're getting called twice. What's going on here?

//Handle HTTP route GET /:username i.e. /chalkers
function user(request, response) {
  console.log("in user route before if");
  //if url == "/...."
  var username = request.url.replace("/", "");
  if(username.length > 0) {
    response.writeHead(200, {'Content-Type': 'text/plain'});  
    response.write("Header\n");

    console.log("in user route after if");

3 Answers

Hi Greg Wienecke,

Great question here. I did a little research, and I think I have some answers for you.

The reason both your Strings of "in home route" and "in user route" log to the console is because each request to the server leads to the callback function in http.createServer being called. And that callback function invokes both the router.home function and the router.user function. The conditionals inside these function are what's meant to determine what is sent back to the user. So that's working as expected.

The reason that the messages are logged twice is because behind the scenes the chrome browser is automatically sending a request to the server for a favicon.ico file. If you log the request.url to your console, you'll see what I mean.

Here's a link to a brief Q&A on browsers requesting favicon files: https://www.cisco.com/c/en/us/support/docs/security/web-security-appliance/117995-qna-wsa-00.html

The request.url.replace("/", " ") method/function isn't actually handling the routing. If you visit the url http://localhost:1337/chalkers, the url on the request object is '/chalkers'. In order to get just the username, this line of code is telling the JavaScript engine to set username equal to 'chalkers' and not '/chalkers'. This is then passed as an argument to new Profile() when trying to create a new instance of the Profile class. I'm sure there are other ways to get the information needed, but the method used by Andrew in the lesson is not ineffective/inefficient (in my opinion).

Finally, the reason a console.log placed before and after the if conditional will run each time is because the if block is not followed by and else if or else block. Every line of each function will run if the function is invoked/called, except for maybe the conditional. You can essentially read the home function like this (recognizing the console.logs you added):

  1. log message to console
  2. if condition evaluates to true, run code within code block
    • if condition evaluates to false, skip code block and continue running code in function
  3. log second message to console

Hope all this makes sense. If you need any more help, just give a shout.

JASON LEE
JASON LEE
15,451 Points

Even after Brandon White's clear response, this (only chrome?) browser action still boggles my mind and compiler behavior seems very "out-of-character".

Here is my code

var Profile = require("./profile.js");

function home(request, response) {
  console.log(`request.url is ${request.url}`) // CONSOLE LOG NodeJs OUTPUT HERE
  if (request.url === "/") {
    response.statusCode = 200;
    response.setHeader('Content-Type', 'text/plain');
    response.write("Header\n")
    response.write("Search\n")
    response.end('Footer\n')  
  } else {
    console.log("invalid uri or not the home page")  // CONSOLE LOG NodeJs OUTPUT HERE 
  }
}

And here is my node.js terminal output after the client refreshes the page on the "root" or / local host folder http://127.0.0.1:3000 (without a /username)

request.url is /

request.url is /favicon.ico

invalid uri or not the home page

Greg Wienecke
Greg Wienecke
126 Points

Thanks Brandon! That is a great answer.

The only thing I'm still confused about is the log message getting called in the user route if statement.

Maybe I shouldn't have said the replace("/", "") handles the routing, but that's kind of my point that this "route" actually gets called every time, replaces "/" with "" in the URL, and then checks the if statement, and that's the only thing that determines if the rest of the code in the user route gets run. Even without an else if or else, I don't understand how anything in the if can be called when the URL in the request was localhost:1337/ with nothing after the slash.

Here is the entire user route code block below. After it does the replace, everything else is inside the if statement.

function user(request, response) {
  //if url == "/...."
  var username = request.url.replace("/", "");
  if(username.length > 0) {
    response.writeHead(200, {'Content-Type': 'text/plain'});  
    response.write("Header\n");

    console.log("in user route after if");

    //get json from Treehouse
    var studentProfile = new Profile(username);
    //on "end"
    studentProfile.on("end", function(profileJSON){
      //show profile

      //Store the values which we need
      var values = {
        avatarUrl: profileJSON.gravatar_url, 
        username: profileJSON.profile_name,
        badges: profileJSON.badges.length,
        javascriptPoints: profileJSON.points.JavaScript
      }
      //Simple response
      response.write(values.username + " has " + values.badges + " badges\n");
      response.end('Footer\n');
    });

    //on "error"
    studentProfile.on("error", function(error){
      //show error
      response.write(error.message + "\n");
      response.end('Footer\n');
    });

  }
}

You're not wrong in your logic, Greg. But you'll remember how I wrote that the "chrome browser is automatically sending a request to the server for a favicon.ico file". This is why the code in the if block runs. Try adding the following line of code after the username variable declaration, but before the if statement:

console.log('This is username: ', username);

Start your server, then visit localhost:3000 or in your case localhost:1337.

You should see three lines log to the console. They will look like this:

This is username:  
This is username:  favicon.ico
in user route after if

You're not expecting the request to a localhost:1337/favicon.ico, and so the assumption is that the code in the if block is running even when the condition evaluates to false, but actually, the second request (a hidden/automated request) is causing the if condition to evaluate to true; this is why the code in the if block runs.

Hopefully that clears things up. Also, I appreciate you asking this question. It's an interesting bug to work through.

And I've learned something myself, because I did not realize that chrome will automatically send a request to the server for a favicon file. So thanks.

Greg Wienecke
Greg Wienecke
126 Points

Thank you, that clears it up.