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
- Attempt every question before looking at the hints table. The learning happens in the struggle.
- Conceptual questions (Section A) should be answered in your own words, as if explaining to a study partner.
- Code-writing questions (Sections B-E) should be written in a real file and tested with
nodeandcurl. - Debugging questions (Section F) contain intentional bugs. Find and fix every issue before running the code.
- Challenge questions (Section G) combine multiple subtopics. Attempt them only after completing the earlier sections.
- 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-storeAccess-Control-Allow-Origin: *X-Content-Type-Options: nosniffSet-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:
| Method | URL | Action |
|---|---|---|
| GET | /api/tasks | List all tasks |
| GET | /api/tasks/:id | Get a single task |
| POST | /api/tasks | Create a new task |
| PUT | /api/tasks/:id | Replace a task |
| DELETE | /api/tasks/:id | Delete 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-Typeheaders 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
Acceptheader - Request logging that prints
METHOD /path STATUS_CODEfor 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 containingserver.jsand aroutes/folder with separate handler files - A
public/directory withindex.html,style.css, and404.html - A
package.jsonwithstartanddevscripts - A
nodemon.jsonthat watchessrc/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/shortenaccepts{ url: "https://example.com" }and returns{ shortCode: "abc123" }GET /:shortCoderedirects (302) to the original URLGET /api/stats/:shortCodereturns 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 |
|---|---|
| 1 | The client always initiates. If the server is down, the client gets a connection refused error. |
| 2 | Think about how one machine can listen on port 3000, 4000, and 8080 simultaneously. |
| 3 | The journey has six stages: URL parsing, DNS, TCP, TLS, HTTP request, HTTP response. |
| 5 | 0.0.0.0 listens on all network interfaces; 127.0.0.1 only on loopback. |
| 8 | You need exactly three things: require('http'), createServer, and listen. |
| 11 | The first causes Error: write after end. The second causes the browser to hang indefinitely. |
| 15 | The body arrives in chunks. You must wait for the 'end' event before parsing. |
| 18 | Use path.extname() to get the file extension and map it to a MIME type. |
| 20 | Multi-byte characters (accents, emoji) make string.length differ from byte length. |
| 25 | req.url.split('/') on /api/users/42 gives ['', 'api', 'users', '42']. Index 3 is the ID. |
| 26 | new URL(req.url, 'http://' + req.headers.host) gives you .pathname and .searchParams. |
| 29 | url.parse(req.url, true).pathname strips the query string. So does new URL(...).pathname. |
| 31 | 200, 201, 204, 400, 401, 403, 404, 405, 500, 503 — in that order. |
| 34 | No token = 401 (who are you?). Valid token, wrong role = 403 (you cannot do this). |
| 37 | Bug 1: Content-Type should be application/json. Bug 2: res.end(data) needs JSON.stringify(data). |
| 38 | fs.readFile is asynchronous. You must use a callback or fs.readFileSync. |
| 39 | JSON.parse(body) runs before the 'end' event fires. Move it inside the 'end' callback. |
| 40 | Route 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'). |
| 41 | Handle SIGTERM / SIGINT with server.close() for graceful shutdown. |
| 44 | Use Math.random().toString(36).substring(2, 8) for a simple short code generator. |
Navigation: < Nodemon for Development | Interview Questions >