Challenge Project: Quote API - Need help

Hello everyone! I’m currently working through the Quote API challenge project. I’ve tested my code in another sandbox and the basic syntax and functionality seems to be working there, but for some reason it’s not working at all in the codecademy environment. Note: in my test environment, i’ve set my own reqParams variable to a value that is included in the quotes array. I’ve also replaced res.send() with console.log() to check to see if my code was working. Could someone take a look and see if they see any problems?

Here’s my task via the challenge project:

Your API should have a GET /api/quotes route. This route should return all quotes from the data if the request has no query params.

If there is a query string with a person attribute, the route should return all quotes said by the same person. For instance, the data set has multiple quotes for Grace Hopper, so GET /api/quotes?person=Grace Hopper should return an array of only those quotes. If there are no quotes for the requested person , send back an empty array.

The response body should have the following shape for all GET /api/quotes requests:

{ quotes: [ /* Array of requested quotes */ ] }

Ok - and here’s my code, which again - works in another sandbox environment (developer.mozilla.org):

const express = require('express');
const morgan = require('morgan');
const app = express();

const { quotes } = require('./data'); //this imports a quotes array filled with objects that each have a person and a quote property

const PORT = process.env.PORT || 4001;

app.listen(PORT, () => {
  console.log(`Server is listening on port ${PORT}`)
});

app.use(express.static('public'));

//my code in question below:
app.get('/api/quotes', (req, res, next) => {
  const reqQuery = req.query;
  const reqPerson = req.query.person;
  
  if (reqPerson) {
    let quoteArr = [];
    for (let i = 0; i < quotes.length; i++) {
      if (quotes[i].person == reqPerson) {
        quoteArr.push(quotes[i].quote);
      } else if (quotes[i].person.includes(reqPerson) == false) {
        quoteArr.push();
    };  
  };
  const sendQuote = {
      quotes: [quoteArr]
        };
      res.send(sendQuote); 
  }
});

I haven’t tackled:

This route should return all quotes from the data if the request has no query params.

because i just can’t seem to get this thing to send any sort of response that isn’t undefined. Any ideas???

Thank you!!!

I have a question:

  1. Have you checked whether there is in fact anything in the ‘quotes’ array after you import it? And if so, is it actually an array? I think that the syntax you used:
const { quotes } = require('./data');

is for destructuring an object, and the key name in the object has to match the variable name you give it in the curly braces.

Also, you could use the array.filter() method to simplify your code.

1 Like

Quotes is indeed an array full of objects with properties person and quote

See below - located in data.js:

const quotes = [
  {
    quote: 'We build our computer (systems) the way we build our cities: over time, without a plan, on top of ruins.',
    person: 'Ellen Ullman'
  },
  {
    quote: 'The best thing about a boolean is even if you are wrong, you are only off by a bit.',
    person: 'Anonymous'
  },
  {
    quote: `If it's a good idea, go ahead and do it. It's much easier to apologize than it is to get permission.`,
    person: 'Grace Hopper'
  },
  {
    quote: 'The city’s central computer told you?  R2D2, you know better than to trust a strange computer!',
    person: 'C-3PO'
  },
  {
    quote: 'I have always wished for my computer to be as easy to use as my telephone; my wish has come true because I can no longer figure out how to use my telephone.',
    person: 'Bjarne Stroustrup'
  },
  {
    quote: 'Understand well as I may, my comprehension can only be an infinitesimal fraction of all I want to understand.',
    person: 'Ada Lovelace'
  },
  {
    quote: 'Java is to JavaScript as ham is to hamster.',
    person: 'Jeremy Keith'
  },
  {
    quote: `The most dangerous phrase in the language is, "We've always done it this way."`,
    person: 'Grace Hopper'
  },
  {
    quote: 'As soon as we started programming, we found to our surprise that it wasn’t as easy to get programs right as we had thought.  Debugging had to be discovered.  I can remember the exact instant when I realized that a large part of my life from then on was going to be spent in finding mistakes in my own programs.',
    person: 'Maurice Wilkes'
  },
  {
    quote: 'Learning to write programs stretches your mind, and helps you think better, creates a way of thinking about things that I think is helpful in all domains.',
    person: 'Bill Gates'
  },
  {
    quote: 'What one programmer can do in one month, two programmers can do in two months.',
    person: 'Fred Brooks'
  },
  {
    quote: 'The Internet? Is that thing still around?',
    person: 'Homer Simpson'
  },
  {
    quote: 'If you tell me precisely what it is a machine cannot do, then I can always make a machine which will do just that.',
    person: 'Jon von Neumann'
  },
];

module.exports = {
  quotes
};

After you import it with the curly braces into the file with the /api/quotes route, is it still an array?

I assume so - how do I check that?

You could use Array.isArray(quotes) or just console.log(quotes)

So this project gives you the option to work within the codecademy environment or download files and work through locally. I chose the codecademy route, which does not allow me access to a console. I am only given a code editor, a terminal, and a localhost website to check the functionality of my code.

If all else fails, I can spin up the project locally and try it there. Do you know of a way to add a console to a project natively in codecademy?

If you have a terminal, the console.log() should show up there (I think).

1 Like

Another way to test it is to use the require statement without the curly braces to see if that fixes things, as in const quotes = require('./data');

Also check that there is an export statement in data.js.

I don’t know if this is what’s causing the problem but I wonder.

1 Like

Ok great I will try these things. Thanks for the help!

1 Like

Update here. I console.log(quotes) and it’s indeed an array. Like I said earlier, my code worked in another environment. The only difference is that the environment wasn’t a routing framework and did not pull req.query or req.query.person in. I just set a variable to a string that matched any author in the array.

One thing I will say is that at one point, I had a bit of code that wasn’t completely finished, and when I searched “Grace Hopper” it returned two quotes, both undefined (Grace Hopper is the only author that appeared twice in my array of objects). I’m thinking that’s telling me that everything is working as it should internally, but there’s some sort of problem when I reference my new quoteArr array in my res.send() function, or when I push my output of the iterator to quoteArr
I’ll try your filter method to see if that fixes anything, but if not - I might have to give in and look at the solution code :confused:

@pkehr09 Thanks for the update. I don’t see a body parser included in your code. A body parser is what takes the incoming request urls and attaches them to req.query so you can reference them as such.

You can import it with const bodyParser = require('body-parser') and then before your routes put app.use(bodyParser.urlencoded())

Thank you for this I will definitely try it! It’s interesting because almost all of the challenge projects I’ve encountered are filled with concepts and ideas that weren’t previously covered in the lessons. I’m guessing this is probably by design. I will research body parser and see if that works.

One question: with my limited beginners knowledge of express, is this saying that I would need to have a body-parser.js file somewhere that is importing urlencoded() function? If that is the case, the native codecademy environment does not allow me to create new files like that. If not, I’ll do some research into body parser and go from there! Thank you!

body-parser is middleware that I believe is installed along with Express so the Codecademy interface will allow you to import and use it. You don’t need to install it separately, and you don’t need a separate file for it.

You have the server listening on port 4001, so when any requests come in, they will hit app.use(bodyParser.urlencoded()), which will look at the query string in the request url and parse it (pull it apart at the ‘&’ markers, format it into key-value pairs and attach it to req as req.query). Then the rest of your code should be able to make sense out of it.

JSYK for the future, body-parser has different methods for different types of requests. Your requests are coming as query strings on the url, so you call bodyParser.urlencoded(), but if you’re expecting JSON requests, you can call bodyParser.json(). You can look at the documentation to see the different kinds of requests it can parse.

Ah that makes a lot of sense actually. One thing I forgot is that this challenge was actually presented to me midway through a lesson, and that a course on middleware was coming next. So i’m sure it would have covered what you are talking about. Thank you so much for taking the time to explain this to me. I will be sure to check out the documentation!

You’re welcome! In looking at the documentation myself, I’m not 100% sure it will attach the info to req.query. It might be req.body.

Now that I heard you haven’t learned about middleware yet, I’m wondering if you’re supposed to get the info from the request using req.params…

So final update. The solution was alot easier than I thought. When the project asked me to

For instance, the data set has multiple quotes for Grace Hopper, so GET /api/quotes?person=Grace Hopper should return an array of only those quotes.

I took that as my code should search through each object in the quotes array, check that the req.query.person === quotes.person , and then deliver an array with only values from the quotes.quote property of the objects filtered.

What it really wanted is just to check that req.query.person === quotes.person and return the entire object that matched that criterion. So all it needed was something like:

app.get('/api/quotes', (req, res) => {
  const reqQuery = req.query;
  const reqPerson = req.query.person;
  
    if (reqPerson !== undefined) {
      const quoteFilter = quotes.filter(quote => quote.person === reqPerson)
      const sendQuote = {
        quotes: quoteFilter
      };
      res.send(sendQuote); 
    } else {
      const allQuotes = {
        quote: quotes
      };
      res.send(allQuotes);
    }
});

Bright side is I honed my understanding of for loops and got more familiar with the array.filter :slight_smile:

Thank you again!

Glad you solved it, and that array.filter() was handy. At least something I said was worthwhile! :slight_smile:

thanks all for your responses. i was having similar questions and your answers were helpful to me.

1 Like

hola =) como estan chicos ustedes son codeacademy premium?