CodeBlanks Logo Icon CodeBlanks

Putting it together

Combine the Quiz class with an Express API.

Combining the quiz with an Express API

The final lesson: we combine the Quiz class with an Express API. The API serves questions as JSON. The previous lessons' Question and Quiz classes are ready; now we add the Express route.

The flow is: set up the Express app, create a Quiz object, add questions, serve them as JSON with a GET /quiz route. With quiz.questions.map(function(q) { return { id: q.id, text: q.text }; }) we take only the id and text properties; we do not send answer because the user should not see it. We send the JSON response with res.json. This is the skeleton of a real API: data is managed in a class, served as JSON over HTTP.

Selecting properties with map

quiz.questions.map(function(q) { return { id: q.id, text: q.text }; }) turns each question into a new object with only id and text. The answer property is removed; the user should not see the correct answer.

map transforms each item of an array and returns a new array. Here we turn each Question object into an { id, text } object. The original array is not changed; only a new view is created. This is the basic way to hide sensitive data in API responses: the data model holds the full object, the API shows only the needed properties. This pattern is also used to strip fields like password or email from a response.

Practice Add the GET /quiz route

Take the previous lessons' solution (Express and Quiz class are ready). Add the route app.get("/quiz", (req, res) => { res.json(quiz.questions.map(function(q) { return { id: q.id, text: q.text }; })); }). The server requests /quiz.

Starter code

index.js
class Question {
  constructor(id, text, answer) {
    this.id = id;
    this.text = text;
    this.answer = answer;
  }
}
class Quiz {
  constructor() {
    this.questions = [];
  }

  addQuestion(text, answer) {
    const id = this.questions.length + 1;
    this.questions.push(new Question(id, text, answer));
  }

  run() {
    for (let i = 0; i < this.questions.length; i++) {
      console.log("Question " + this.questions[i].id + ": " + this.questions[i].text);
    }
  }

  score(answers) {
    let correct = 0;
    for (let i = 0; i < this.questions.length; i++) {
      if (answers[i] === this.questions[i].answer) {
        correct++;
      }
    }
    const total = this.questions.length;
    const percentage = Math.round((correct / total) * 100);
    return { correct: correct, total: total, percentage: percentage };
  }
}
const express = require("express");
const app = express();
app.use(express.json());

const quiz = new Quiz();
quiz.addQuestion("Capital?", "Ankara");
quiz.addQuestion("Largest city?", "Istanbul");

// Add a GET /quiz route: send id and text properties as JSON
// write here

const server = app.listen(3000, () => {
  const http = require("http");
  http.get("http://localhost:3000/quiz", (res) => {
    let body = "";
    res.on("data", (c) => body += c);
    res.on("end", () => { console.log("Reply: " + body); server.close(); });
  });
});

Sample solution

index.js
class Question {
  constructor(id, text, answer) {
    this.id = id;
    this.text = text;
    this.answer = answer;
  }
}
class Quiz {
  constructor() {
    this.questions = [];
  }

  addQuestion(text, answer) {
    const id = this.questions.length + 1;
    this.questions.push(new Question(id, text, answer));
  }

  run() {
    for (let i = 0; i < this.questions.length; i++) {
      console.log("Question " + this.questions[i].id + ": " + this.questions[i].text);
    }
  }

  score(answers) {
    let correct = 0;
    for (let i = 0; i < this.questions.length; i++) {
      if (answers[i] === this.questions[i].answer) {
        correct++;
      }
    }
    const total = this.questions.length;
    const percentage = Math.round((correct / total) * 100);
    return { correct: correct, total: total, percentage: percentage };
  }
}
const express = require("express");
const app = express();
app.use(express.json());

const quiz = new Quiz();
quiz.addQuestion("Capital?", "Ankara");
quiz.addQuestion("Largest city?", "Istanbul");

app.get("/quiz", (req, res) => {
  res.json(quiz.questions.map(function(q) { return { id: q.id, text: q.text }; }));
});

const server = app.listen(3000, () => {
  const http = require("http");
  http.get("http://localhost:3000/quiz", (res) => {
    let body = "";
    res.on("data", (c) => body += c);
    res.on("end", () => { console.log("Reply: " + body); server.close(); });
  });
});

Expected output

Yanıt: [{"id":1,"text":"Başkent?"},{"id":2,"text":"En büyük şehir?"}]

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 Match each piece to its role

Term Meaning
app.get('/quiz') Serves questions as JSON
quiz.questions.map Takes id and text
res.json Sends a JSON response
express.json() Parses the body

2 What does the GET /quiz route return?

index.js
app.get("/quiz", (req, res) => res.json(quiz.questions.map(...)))
  • All Question objects (including answer)
  • Objects containing only id and text Correct answer
  • An empty array
  • Skor sonucunu

Explanation: map takes only id and text; answer is hidden.

3 Complete the map call

Question
res.json(quiz.questions.____(function(q) { return { id: q.id, text: q.text }; }));
Answer
res.json(quiz.questions.map(function(q) { return { id: q.id, text: q.text }; }));

Explanation: map transforms each item.

All lessons in Intermediate