iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Node Exercises

Three short Node drills - HTTP server with routing, streamed CSV transform, and a typed shell helper.

Three short challenges

EXAMPLE
// 1. HTTP server with method-based routing - no framework
import { createServer } from 'http';
import { URL } from 'url';

type Handler = (req: any, res: any, params: Record<string, string>) => Promise<void> | void;
type Route = { method: string; pattern: RegExp; keys: string[]; handler: Handler };

const routes: Route[] = [];
const route = (method: string, path: string, handler: Handler) => {
  const keys: string[] = [];
  const pattern = new RegExp('^' + path.replace(/:([\w]+)/g, (_, k) => { keys.push(k); return '([^/]+)'; }) + '$');
  routes.push({ method, pattern, keys, handler });
};

route('GET', '/healthz', (_, res) => res.end('ok'));
route('GET', '/users/:id', async (_, res, params) => {
  res.writeHead(200, { 'content-type': 'application/json' });
  res.end(JSON.stringify({ id: params.id, name: 'Ada' }));
});

createServer(async (req, res) => {
  const url = new URL(req.url!, 'http://x');
  for (const r of routes) {
    if (r.method !== req.method) continue;
    const m = url.pathname.match(r.pattern);
    if (!m) continue;
    const params = Object.fromEntries(r.keys.map((k, i) => [k, decodeURIComponent(m[i + 1])]));
    return await r.handler(req, res, params);
  }
  res.writeHead(404); res.end('not found');
}).listen(3000);


// 2. Stream a CSV, transform, write a CSV
import { createReadStream, createWriteStream } from 'fs';
import { Transform } from 'stream';
import { pipeline } from 'stream/promises';

const upper = new Transform({
  transform(chunk, _, cb) {
    // chunk is a Buffer of partial CSV; for real CSVs use papaparse / csv-parse
    cb(null, chunk.toString().toUpperCase());
  },
});

await pipeline(
  createReadStream('in.csv', { encoding: 'utf8' }),
  upper,
  createWriteStream('out.csv')
);


// 3. Typed shell helper
import { spawn } from 'child_process';

type RunResult = { code: number; stdout: string; stderr: string };

function run(cmd: string, args: string[] = [], opts: { input?: string; cwd?: string } = {}): Promise<RunResult> {
  return new Promise((resolve, reject) => {
    const p = spawn(cmd, args, { cwd: opts.cwd, stdio: ['pipe', 'pipe', 'pipe'] });
    let stdout = '', stderr = '';
    p.stdout.on('data', (d) => stdout += d);
    p.stderr.on('data', (d) => stderr += d);
    p.on('error', reject);
    p.on('close', (code) => resolve({ code: code ?? -1, stdout, stderr }));
    if (opts.input != null) { p.stdin.end(opts.input); }
  });
}

const { stdout } = await run('node', ['-e', 'console.log(process.version)']);
console.log(stdout.trim());


// Stretch
// - Add timeout to the shell helper
// - Add gzip compression to the CSV pipeline
// - Add request-scoped logging to the HTTP server

Why it matters

These three drill the patterns most Node programs hit - HTTP routing without a framework, streams with backpressure, and shelling out safely. Together they unlock writing production-quality Node from scratch when you cannot reach for a library.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// Fill in the missing piece.
import { readFile } from 'node:____/promises';
Try it Yourself »

Discussion

Loading…