3.2 — Quick Revision: Creating a Server
A compact cheat sheet covering the http module, status codes, content types, request/response objects, routing patterns, and nodemon.
< Interview Questions | README
How to Use This Material
- Use this as a last-minute review before interviews or assessments.
- Read through the tables and code snippets. If anything looks unfamiliar, go back to the corresponding subtopic file and re-read that section.
- Cover the right column of each table and quiz yourself on the answers.
- This is a reference sheet, not a learning resource. Learn from 3.2.a through 3.2.f first.
Minimal Server (Copy-Paste Starter)
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, World!');
});
server.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
http Module API
| Method / Property | Purpose |
|---|
http.createServer(callback) | Creates an HTTP server; callback receives (req, res) |
server.listen(port, [host], [callback]) | Starts listening for connections on the given port |
server.close([callback]) | Stops the server from accepting new connections |
server.on('request', fn) | Same as passing callback to createServer |
server.on('error', fn) | Handles server errors (e.g., EADDRINUSE) |
server.on('listening', fn) | Fires when server begins listening |
server.on('connection', fn) | Fires on each new TCP connection |
server.on('close', fn) | Fires when server shuts down |
req Object (http.IncomingMessage)
| Property / Method | Returns | Example Value |
|---|
req.method | HTTP method string | "GET", "POST", "PUT", "DELETE" |
req.url | Full URL path + query string | "/api/users?page=2" |
req.headers | Object of all headers (keys lowercased) | { host: 'localhost:3000', 'user-agent': '...' } |
req.headers['content-type'] | Request body format | "application/json" |
req.headers['authorization'] | Auth credentials | "Bearer eyJ..." |
req.httpVersion | HTTP version string | "1.1" |
req.socket.remoteAddress | Client IP address | "127.0.0.1" |
req.on('data', fn) | Receive body chunk | Chunk is a Buffer |
req.on('end', fn) | Body fully received | Parse body here |
Reading a POST Body
let body = '';
req.on('data', (chunk) => { body += chunk.toString(); });
req.on('end', () => {
const data = JSON.parse(body);
});
res Object (http.ServerResponse)
| Method / Property | Purpose |
|---|
res.writeHead(statusCode, headers) | Set status code + headers in one call (call once) |
res.setHeader(name, value) | Set a single header (call multiple times) |
res.statusCode = 200 | Set status code separately |
res.write(data) | Write a chunk to the response body |
res.end([data]) | Finish the response (optionally send final data) |
res.getHeader(name) | Read a previously set header |
res.removeHeader(name) | Remove a previously set header |
writeHead vs setHeader
| Feature | res.writeHead() | res.setHeader() |
|---|
| Sets status code | Yes | No (use res.statusCode) |
| Sets multiple headers | Yes (object) | One at a time |
| Can call multiple times | No | Yes |
| Best for | All headers known upfront | Building headers incrementally |
HTTP Status Codes
2xx Success
| Code | Name | When to Use |
|---|
| 200 | OK | Successful GET, PUT, PATCH returning data |
| 201 | Created | Successful POST that created a resource |
| 204 | No Content | Successful DELETE or PUT with no response body |
3xx Redirection
| Code | Name | When to Use |
|---|
| 301 | Moved Permanently | URL permanently changed (SEO, domain change) |
| 302 | Found | Temporary redirect (maintenance, post-redirect-get) |
| 304 | Not Modified | Client cache is still valid |
4xx Client Errors
| Code | Name | When to Use |
|---|
| 400 | Bad Request | Malformed JSON, unparseable body |
| 401 | Unauthorized | No credentials or invalid credentials (authentication) |
| 403 | Forbidden | Valid credentials but insufficient permissions (authorization) |
| 404 | Not Found | Resource or route does not exist |
| 405 | Method Not Allowed | Wrong HTTP method for this route (include Allow header) |
| 409 | Conflict | Duplicate resource (e.g., email already registered) |
| 422 | Unprocessable Entity | Valid JSON but invalid data values |
| 429 | Too Many Requests | Rate limit exceeded (include Retry-After header) |
5xx Server Errors
| Code | Name | When to Use |
|---|
| 500 | Internal Server Error | Unhandled exception, server bug |
| 502 | Bad Gateway | Upstream server returned invalid response |
| 503 | Service Unavailable | Maintenance or overload (include Retry-After header) |
| 504 | Gateway Timeout | Upstream server did not respond in time |
Quick Decision Rule
2xx = "All good."
3xx = "Go somewhere else."
4xx = "You (client) messed up."
5xx = "I (server) messed up."
Content Types (MIME Types)
| Content-Type | Data Format | Use Case |
|---|
text/plain | Plain text | Simple text, debugging |
text/html | HTML markup | Web pages |
text/css | CSS stylesheet | Styles |
text/csv | Comma-separated values | Data exports |
application/json | JSON | API responses |
application/javascript | JavaScript | Script files |
application/xml | XML | Legacy APIs |
application/pdf | PDF | Documents |
application/octet-stream | Binary (generic) | File downloads |
image/png | PNG image | Graphics |
image/jpeg | JPEG image | Photos |
image/svg+xml | SVG image | Vector graphics |
multipart/form-data | Form with files | File uploads |
application/x-www-form-urlencoded | URL-encoded form | HTML form submissions |
HTTP Methods
| Method | Purpose | Has Body | Idempotent | Safe |
|---|
GET | Retrieve a resource | No | Yes | Yes |
POST | Create a new resource | Yes | No | No |
PUT | Replace entire resource | Yes | Yes | No |
PATCH | Partially update resource | Yes | No | No |
DELETE | Remove a resource | Optional | Yes | No |
HEAD | Same as GET, no body in response | No | Yes | Yes |
OPTIONS | Ask what methods are allowed | No | Yes | Yes |
Routing Patterns
Pattern 1: if/else on req.url
if (req.url === '/' && req.method === 'GET') {
res.end('Home');
} else if (req.url === '/about' && req.method === 'GET') {
res.end('About');
} else {
res.writeHead(404);
res.end('Not Found');
}
Pattern 2: Route table object
const routes = {
'GET /': (req, res) => res.end('Home'),
'GET /about': (req, res) => res.end('About'),
};
const handler = routes[`${req.method} ${req.url}`];
handler ? handler(req, res) : res.writeHead(404) && res.end('Not Found');
Pattern 3: Dynamic parameters with split
const parts = req.url.split('/');
const id = parseInt(parts[3]);
Pattern 4: Dynamic parameters with regex
const match = req.url.match(/^\/api\/users\/(\d+)$/);
if (match) {
const id = parseInt(match[1]);
}
Parsing Query Strings
const url = new URL(req.url, `http://${req.headers.host}`);
url.pathname;
url.searchParams.get('page');
url.searchParams.has('sort');
const parsed = require('url').parse(req.url, true);
parsed.pathname;
parsed.query.page;
Response Patterns
Plain text
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, World!');
HTML
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end('<h1>Hello</h1>');
JSON
const data = { message: 'Hello' };
const body = JSON.stringify(data);
res.writeHead(200, {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(body)
});
res.end(body);
Redirect
res.writeHead(301, { 'Location': '/new-page' });
res.end();
Error (JSON API)
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Not Found', message: 'User does not exist' }));
Static file
const fs = require('fs');
const path = require('path');
const filePath = path.join(__dirname, 'public', 'index.html');
fs.readFile(filePath, (err, content) => {
if (err) { res.writeHead(500); res.end('Error'); return; }
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(content);
});
Common Ports
| Port | Service |
|---|
| 80 | HTTP |
| 443 | HTTPS |
| 3000 | Node.js / React dev |
| 5173 | Vite dev |
| 8080 | Alternative HTTP / proxies |
| 5432 | PostgreSQL |
| 27017 | MongoDB |
| 6379 | Redis |
Networking Essentials
| Term | Meaning |
|---|
localhost | Hostname pointing to your own machine |
127.0.0.1 | IPv4 loopback address (same as localhost) |
0.0.0.0 | All network interfaces (accessible from other devices) |
| DNS | Translates domain names to IP addresses |
| TCP | Transport protocol; reliable, ordered delivery |
| TLS/SSL | Encryption layer for HTTPS |
| Stateless | Each HTTP request is independent; server does not remember previous requests |
Nodemon and Development Workflow
Install and configure
npm install -D nodemon
{
"start": "node server.js",
"dev": "nodemon server.js"
}
npm run dev
npm start
nodemon.json
{
"watch": ["src"],
"ext": "js,json",
"ignore": ["node_modules", "tests", "*.test.js"],
"delay": 500
}
Common CLI flags
| Flag | Purpose | Example |
|---|
--ext | File extensions to watch | nodemon --ext js,json |
--watch | Directories to watch | nodemon --watch src |
--ignore | Paths to ignore | nodemon --ignore logs/ |
--delay | Restart delay (ms) | nodemon --delay 1000 |
--exec | Alternate executor | nodemon --exec ts-node |
--inspect | Enable Node debugger | nodemon --inspect |
node --watch (Node 18.11+, built-in alternative)
node --watch server.js
node --watch-path=./src server.js
When to use which
| Scenario | Tool |
|---|
| Simple project, only .js, Node 18+ | node --watch |
| Need ignore paths, extensions, delay | nodemon |
| TypeScript project | tsx watch or nodemon --exec ts-node |
Common Mistakes Checklist
| Mistake | Consequence | Fix |
|---|
Forgetting res.end() | Client hangs forever | Always call res.end() |
res.write() after res.end() | Runtime error | Ensure end() is last |
Passing object to res.end() | TypeError | Use JSON.stringify() |
Wrong Content-Type | Garbled output in browser | Match header to actual data format |
| 200 for errors | Breaks client error handling | Use correct 4xx/5xx codes |
fs.readFile used synchronously | Returns undefined | Use callback or readFileSync |
| String concat for file paths | Breaks cross-OS, security risk | Use path.join() |
| Route order wrong | Greedy match hides specific routes | Check specific routes first |
| No 404 catch-all | Unknown routes hang or crash | Always add a fallback |
| Using 500 for client errors | Misleading; triggers wrong alerts | Use 400/422 for bad input |
Key Headers to Remember
Response headers
| Header | Purpose | Example |
|---|
Content-Type | Data format of response body | application/json |
Content-Length | Size of body in bytes | 256 |
Location | Redirect target URL | /new-page |
Set-Cookie | Send a cookie to the client | sessionId=abc; HttpOnly |
Cache-Control | Caching instructions | max-age=3600 |
Access-Control-Allow-Origin | CORS: which origins allowed | * |
Allow | Allowed methods (with 405) | GET, POST |
Retry-After | When to retry (with 429/503) | 60 |
WWW-Authenticate | Auth scheme (with 401) | Bearer |
Request headers
| Header | Purpose | Example |
|---|
Host | Target server | example.com |
Accept | Acceptable response formats | application/json |
Content-Type | Format of request body | application/json |
Authorization | Auth credentials | Bearer eyJ... |
User-Agent | Client software | Mozilla/5.0... |
Cookie | Cookies from previous responses | sessionId=abc123 |
Testing Commands
curl http://localhost:3000
curl -v http://localhost:3000
curl -I http://localhost:3000
curl -X POST http://localhost:3000/api/users \
-H "Content-Type: application/json" \
-d '{"name":"Alice"}'
curl -X POST http://localhost:3000/form \
-d "name=Alice&email=alice@example.com"
curl -X DELETE http://localhost:3000/api/users/1
curl http://localhost:3000/api/users | python3 -m json.tool
Navigation: < Interview Questions | README