Episode 3 — NodeJS MongoDB Backend Architecture / 3.2 — Creating Server

3.2 — Exercise Questions: Creating a Server

40+ hands-on exercises covering server fundamentals, the HTTP module, responses, routing, status codes, and nodemon.


< Nodemon for Development | Interview Questions >


How to Use This Material

  1. Attempt every question before looking at the hints table. The learning happens in the struggle.
  2. Conceptual questions (Section A) should be answered in your own words, as if explaining to a study partner.
  3. Code-writing questions (Sections B-E) should be written in a real file and tested with node and curl.
  4. Debugging questions (Section F) contain intentional bugs. Find and fix every issue before running the code.
  5. Challenge questions (Section G) combine multiple subtopics. Attempt them only after completing the earlier sections.
  6. The Answer Hints Table at the bottom gives you a nudge if you are stuck, not a full solution. Use it sparingly.

Section A: Conceptual Questions (Server Basics)

1. Explain the client-server model in your own words. What initiates the communication, and what happens if the server is not running?

2. What is the difference between a physical server and a software server? Can a single physical server run multiple software servers? If so, how do they avoid conflicts?

3. Describe the full journey of an HTTP request from the moment a user types https://example.com/about in their browser until the page appears. Include DNS, TCP, TLS, and the request-response cycle.

4. Why is HTTP called a "stateless" protocol? Name three mechanisms developers use to maintain state across requests.

5. Explain the difference between localhost, 127.0.0.1, and 0.0.0.0. When would you use each in server.listen()?

6. What is the difference between server-side rendering (SSR) and client-side rendering (CSR)? Give one advantage and one disadvantage of each.

7. A port number is often compared to an apartment number in a building. Extend this analogy: what is the building, the mailroom, and the letter in this comparison?


Section B: The HTTP Module and Server Creation

8. Write a minimal Node.js server using the http module that responds with the plain text "Hello, World!" on port 3000. Every line should have a comment explaining what it does.

9. List all the properties and methods of the req object that you would use to log the following information about every incoming request: the HTTP method, the URL path, the client's user-agent, and the HTTP version. Write the console.log statement.

10. Explain the difference between res.writeHead(), res.setHeader(), and res.statusCode. When would you use each? Write a short code example demonstrating all three.

11. What happens if you call res.write() after res.end()? What happens if you never call res.end() at all? Write code demonstrating both mistakes and describe the result.

12. Create a server that responds with an HTML page containing a styled heading and a paragraph that shows the current date and time. Set the correct Content-Type header.

13. Create a server that responds with a JSON object containing { name, version, uptime } where uptime is the number of seconds the server has been running (use process.uptime()). Set the correct Content-Type header.

14. Using http.createServer() without passing a callback, register the 'request' event manually using server.on(). Also register handlers for the 'listening' and 'error' events.

15. Write a server that reads the request body from a POST request (collecting chunks with req.on('data') and req.on('end')). Parse the body as JSON and echo it back with a 201 status code. Handle the case where the body is not valid JSON.


Section C: Serving Responses and Understanding HTTP

16. List five common MIME types and the file extensions they correspond to. When would you use application/octet-stream?

17. Write a server that checks the Accept header from the client and responds with JSON if the client accepts application/json, or with HTML otherwise. Test with curl -H "Accept: application/json".

18. Create a static file server that reads .html, .css, .js, and .png files from a public/ directory. Map file extensions to MIME types using an object. Return 404 if the file does not exist.

19. Explain why you should use path.join(__dirname, 'public', req.url) instead of string concatenation like __dirname + '/public/' + req.url. What is a directory traversal attack and how does path.join help prevent it?

20. Write a sendJSON helper function that accepts res, a data object, and an optional status code. The function should stringify the data, set the Content-Type and Content-Length headers correctly, and send the response. Why should you use Buffer.byteLength() instead of string.length for Content-Length?

21. Write a server that sets the following response headers and explain what each one does:

  • Cache-Control: no-store
  • Access-Control-Allow-Origin: *
  • X-Content-Type-Options: nosniff
  • Set-Cookie: sessionId=abc123; HttpOnly; Secure

22. Create two helper functions, sendSuccess(res, data, statusCode) and sendError(res, message, statusCode), that enforce a consistent JSON response format across your entire API. Use them in a server with at least three routes.


Section D: Routing

23. Write a server with four routes (/, /about, /contact, /services) using if/else statements on req.url. Each route should return an HTML page. Include a 404 catch-all.

24. Extend the server from Q23 to handle both GET and POST on /contact. GET should return an HTML form; POST should read the form body and display a thank-you message.

25. Write a server that handles GET /api/users (list all) and GET /api/users/:id (get one by ID). Extract the ID from the URL using req.url.split('/'). Return 400 if the ID is not a number, and 404 if the user is not found.

26. Parse query strings from a URL using new URL(req.url, ...). Write a GET /api/products endpoint that supports ?page=1&limit=10&sort=price. Apply default values if parameters are missing.

27. Rewrite the if/else routing from Q23 using a route table object where keys are "METHOD /path" strings and values are handler functions. Include a 404 fallback.

28. Build the mini Router class from the subtopic notes from memory. It should support router.get(), router.post(), dynamic parameters (:id), and query string parsing. Test it with at least four routes.

29. Why does req.url for the path /about?ref=google equal "/about?ref=google" and not "/about"? Write code that extracts just the pathname, ignoring the query string, using both url.parse() and new URL().

30. Create a server with the following RESTful routes for a "tasks" resource stored in an array:

MethodURLAction
GET/api/tasksList all tasks
GET/api/tasks/:idGet a single task
POST/api/tasksCreate a new task
PUT/api/tasks/:idReplace a task
DELETE/api/tasks/:idDelete a task

Each task has: id, title, completed, createdAt.


Section E: HTTP Status Codes

31. Without looking at notes, list the correct status code for each scenario:

  • Successful GET request returning data
  • Resource created after a POST request
  • Successful DELETE with no response body
  • Client sent malformed JSON
  • Client is not authenticated
  • Client is authenticated but lacks permission
  • Requested resource does not exist
  • Client used the wrong HTTP method
  • Server crashed due to an unhandled exception
  • Server is under maintenance

32. What is the difference between 301 and 302 redirects? Write code that implements a 301 redirect from /old-page to /new-page. What header is required for redirects?

33. What is the difference between 400 and 422? Give a concrete example of when you would use each.

34. What is the difference between 401 and 403? A client sends a request to /admin/dashboard without a token. Which code do you return? The same client sends a valid token but their role is "viewer", not "admin". Which code now?

35. Write a server that returns every status code from the 4xx family covered in the notes (400, 401, 403, 404, 405, 409, 422, 429) for different routes. Test each with curl and verify the output.

36. Write a simple rate limiter using a Map that tracks request counts per IP address. Return 429 Too Many Requests with a Retry-After header when the limit is exceeded. Test by sending rapid requests with curl.


Section F: Debugging (Find and Fix the Bugs)

37. This server should respond with JSON, but the browser displays raw text. Find two bugs:

const http = require('http');

const server = http.createServer((req, res) => {
  const data = { message: 'Hello', status: 'ok' };
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end(data);
});

server.listen(3000);

38. This server should serve an HTML page, but it crashes on every request. Find the error:

const http = require('http');
const fs = require('fs');

const server = http.createServer((req, res) => {
  const content = fs.readFile('public/index.html', 'utf8');
  res.writeHead(200, { 'Content-Type': 'text/html' });
  res.end(content);
});

server.listen(3000);

39. This server is supposed to handle POST requests with JSON bodies, but it always returns "Invalid JSON". Find the issue:

const http = require('http');

const server = http.createServer((req, res) => {
  if (req.method === 'POST') {
    let body = '';
    req.on('data', (chunk) => {
      body += chunk;
    });

    const data = JSON.parse(body);
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ received: data }));
  }
});

server.listen(3000);

40. This server has a routing bug where /api/users/5 always matches the wrong route. Find and fix it:

const http = require('http');

const server = http.createServer((req, res) => {
  if (req.url.startsWith('/api/users')) {
    res.end('All users');
  } else if (req.url.startsWith('/api/users/')) {
    const id = req.url.split('/')[3];
    res.end(`User ${id}`);
  } else {
    res.writeHead(404);
    res.end('Not Found');
  }
});

server.listen(3000);

41. This server crashes with EADDRINUSE after a nodemon restart. The developer added a delay but it did not help. What is the proper fix?

const http = require('http');

const server = http.createServer((req, res) => {
  res.end('Hello');
});

server.listen(3000, () => {
  console.log('Running on 3000');
});

Section G: Integration Challenges

42. Build a complete "Mini API Server" that combines everything from this section:

  • At least five routes (mix of HTML pages and JSON API endpoints)
  • Proper Content-Type headers for each response type
  • Correct status codes for success (200, 201, 204) and errors (400, 404, 405, 500)
  • A 404 catch-all that returns JSON or HTML based on the Accept header
  • Request logging that prints METHOD /path STATUS_CODE for every request
  • A try/catch around the entire handler that returns 500 on unexpected errors

43. Create a development-ready project structure with:

  • A src/ directory containing server.js and a routes/ folder with separate handler files
  • A public/ directory with index.html, style.css, and 404.html
  • A package.json with start and dev scripts
  • A nodemon.json that watches src/ only, ignores test files, and has a 500ms delay
  • The server should serve static files from public/ and JSON from /api/* routes

44. Write a server that acts as a simple URL shortener:

  • POST /api/shorten accepts { url: "https://example.com" } and returns { shortCode: "abc123" }
  • GET /:shortCode redirects (302) to the original URL
  • GET /api/stats/:shortCode returns the number of times the short link was visited
  • Store everything in memory (an object or Map)
  • Use correct status codes: 201 for creation, 302 for redirect, 404 for unknown codes, 400 for invalid input

Answer Hints Table

Use this only after a genuine attempt. These are nudges, not full solutions.

Q#Hint
1The client always initiates. If the server is down, the client gets a connection refused error.
2Think about how one machine can listen on port 3000, 4000, and 8080 simultaneously.
3The journey has six stages: URL parsing, DNS, TCP, TLS, HTTP request, HTTP response.
50.0.0.0 listens on all network interfaces; 127.0.0.1 only on loopback.
8You need exactly three things: require('http'), createServer, and listen.
11The first causes Error: write after end. The second causes the browser to hang indefinitely.
15The body arrives in chunks. You must wait for the 'end' event before parsing.
18Use path.extname() to get the file extension and map it to a MIME type.
20Multi-byte characters (accents, emoji) make string.length differ from byte length.
25req.url.split('/') on /api/users/42 gives ['', 'api', 'users', '42']. Index 3 is the ID.
26new URL(req.url, 'http://' + req.headers.host) gives you .pathname and .searchParams.
29url.parse(req.url, true).pathname strips the query string. So does new URL(...).pathname.
31200, 201, 204, 400, 401, 403, 404, 405, 500, 503 — in that order.
34No token = 401 (who are you?). Valid token, wrong role = 403 (you cannot do this).
37Bug 1: Content-Type should be application/json. Bug 2: res.end(data) needs JSON.stringify(data).
38fs.readFile is asynchronous. You must use a callback or fs.readFileSync.
39JSON.parse(body) runs before the 'end' event fires. Move it inside the 'end' callback.
40Route order matters. /api/users matches before /api/users/ because startsWith is greedy. Check the more specific route first, or use an exact match (=== '/api/users').
41Handle SIGTERM / SIGINT with server.close() for graceful shutdown.
44Use Math.random().toString(36).substring(2, 8) for a simple short code generator.

Navigation: < Nodemon for Development | Interview Questions >