Quote API Challenge Project (JavaScript)

Here is my solution. I decided to go with a modularized router and to write most of it in short form. It took me about 2 hours.

The last half hour or so was triaging to get the {quotes} object formed for the site to receive. The dev console showed it was working fine, but the site wasn’t rendering. There is good information earlier in this thread for resolving the issue by forming the object into an object like {quote:quoteObject}.

1 Like

This is my version of the required steps nothing more. I plan on adding the extra steps as soon as I can get what I have to start working. No matter which request I make on the Quote API site I get the same error. After I couldn’t figure it out I compared it to a couple other versions and even though I might have over complicated it, I don’t see why it isn’t working.

Error Message

Your request returned an error from the server:
Code: 404
Not Found

The isEmpty() function I required from the underscore module checks wether or not an object is empty and returns true or false.

Server.js

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

const { quotes } = require('./data');
const { getRandomElement } = require('./utils');
const underscore = require('underscore');
const { everyQuote } = require('./utils');

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

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

app.get('api/quotes/random', (req, res, next) => {
  const obj = {};
  const randomQuote = getRandomElement(quotes);
  obj[quote] = randomQuote;
  res.send(obj);
});

app.get('api/quotes', (req, res, next) => {
  const specificAuthor = req.query;
  const obj2 = {};
  const authorCheck = underscore.isEmpty(specificAuthor);
  if (authorCheck) {
    obj2[quotes] = everyQuote(quotes);
    res.send(obj2);
  } else {
    const specificAuthorQuotes = [];
    for (let i = 0; i < quotes.length; i++) {
      if (quotes[i].person === specificAuthor.person) {
        specificAuthorQuotes.push(quotes[i].quote);
      }
    }
    obj2[quotes] = specificAuthorQuotes;
    return obj2;
  }
});

app.post('api/quotes', (req, res, next) => {
  const newData = req.query;
  const obj3 = {};
  if (!Object.keys(newData).length < 1 || !newData.quote === undefined || !newData.person === undefined) {
    quotes.push(newData);
    obj3[quote] = {quote: newData.quote, person: newData.person};
    res.status(201).send(obj3);
  } else {
    res.status(400).send();
  }
})

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

Helper Function
Returns every quote in the Quotes array.

const everyQuote = arr => {
  let quotes = [];
  arr.forEach((obj) => {
    quotes.push(obj.quote);
    return quotes;
  });
};
1 Like

I’m not sure if this is the answer but I noticed your route parameters are written as such:

app.get('api/quotes', (req, res, next) => {...}

Try rewriting them is this format:

app.get('/api/quotes', (req,res,next) => {...}

I think it might be the missing backslash. Not sure, but it’s easy enough to give it a try.
Hope that helps. :slightly_smiling_face:

1 Like

This was a tough one for me, a lot of new concepts. Learned a lot. I only did the required steps as well. It really helped looking at others’ code in this thread.

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

const { quotes } = require('./data');
const { getRandomElement  } = require('./utils');

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

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

//RETURN RANDOM QUOTE
app.get('/api/quotes/random',(req,res,next)=>{  
  const random = getRandomElement(quotes);
  res.send(random);
});

//RETURN ALL QUOTES Or
//RETURN QUOTES FROM SPECIFIC PERSON
app.get('/api/quotes',(req,res,next)=>{
  const authorName = req.query.person;
  if(authorName){
    const authorArray = quotes.filter((quotes)=>{
     return quotes.person === authorName;       
    });      
    res.send({quotes: authorArray});
  } else {
    res.send({quotes:quotes});
  } 
});

//ADD NEW QUOTES
app.post('/api/quotes',(req,res,next)=>{
  const receivedQuote = req.query;
  if(receivedQuote.quote && receivedQuote.person){
    quotes.push(receivedQuote);
    res.status(201).send({quote: receivedQuote});
  } else{
    res.status(400).send();
  }
});

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

Thanks i’ll give that a try and see what happens! Its probably one of many obvious mistakes I made hah

1 Like

Cool solution code, one small thing though. The example code contains a Cross-site Scripting vulnerability in add-quote.js on lines 16 and 17.

You should use the DOM API to programmatically build the new DOM nodes, using document.createElement and friends instead of innerHTML.

Hi everyone!
Just completed the project.

const {includes} = require('lodash')
const express = require('express');
const app = express();

const { quotes } = require('./data');
const { getRandomElement } = require('./utils');


app.get("/api/quotes/random", (req, res, next) => {
    res.send(getRandomElement(quotes))
} )

app.get("/api/quotes", (req, res, next) => {
    res.send(quotes)
})

app.get("/api/quotes/:author", (req, res, next) => {
    const author = req.params.author
    const findPerson = quotes.filter(({person}) => includes(person, author));
    findPerson.length !== 0 ? res.send(findPerson) :res.send([])
})

app.post("/api/quotes", (req, res, next) =>{
    console.log(req.query)
    res.send(req.query).end()
})

// /api/quotes?person=Grace Hopper
const PORT = process.env.PORT || 4001;
app.use(express.static('public'));
app.listen(PORT, () => console.log(`Listening on port ${PORT}`))

Even with the solution, I’m still getting these errors when trying to run off-platform. Any ideas?

I’ve tried adding CORS. There seems to be a disconnect between the html button and the script. But I’m not sure how to fix. My route on postman returns all quotes (ie
GET http://localhost:4001/api/quotes)

When you run node server.js, why and how do the files in the ‘public’ folder get loaded in the browser? I get that it makes a request to the localhost + port that you set up, but I don’t get how it receives a response with the fronted data ( nothing is set up to work like that, only if it is a default behavior? )

Hey guys,
this is my solution for the Quote API challenge

Hello beautiful people.

Challenge completed.

Quote API

Keep coding. :heart:

Here’s my solution! Thanks guys!

Here’s my solution to the project. I also refactored the starting code to use async/await instead of chaining .then()