Study notes · 10% of the exam

APIs, Data Access and Service Architecture

Production Node.js services succeed or fail on the boring parts: clear layers, validated config, correctly used connection pools, short transactions, idempotent jobs, sound auth and a shutdown that drains before it exits.

Key points

  1. 1

    Layer the code: routes and controllers handle HTTP, services hold business rules, repositories own data access, so logic can be reused from jobs and tested with fakes.

  2. 2

    Validate process.env at startup (values are always strings, so coerce numbers) and fail fast on bad config.

  3. 3

    Use pool.query() for single statements; for transactions, check out one client, run BEGIN to COMMIT or ROLLBACK on it, and release() it in finally. Inside ORM transactions, always use the tx object.

  4. 4

    Total connections = instances × pool size. Size pools with Little's Law (rate × hold time) and put a pooler in front of Postgres for serverless or many instances.

  5. 5

    Queues give at-least-once delivery: make jobs idempotent, pass idempotency keys to external systems, and claim keys atomically with a unique constraint.

  6. 6

    Verify JWTs (never just decode them), keep access tokens short-lived, rotate refresh tokens with reuse detection, and prefer httpOnly cookies on the web.

  7. 7

    Shut down from the outside in: fail readiness, stop accepting, drain in-flight requests, close pools and queues, then exit within the grace period.

Common traps

  • An unreleased pool client on an error path slowly exhausts the pool, and with the default connectionTimeoutMillis: 0, requests then wait forever.

  • In-process cron libraries run once per replica; schedule outside the replicas or deduplicate through the queue.

  • Without pool.on('error'), an error on an idle client during a database failover crashes the whole process.

Test yourself on APIs, Data Access and Service Architecture

Ten questions, with the answer and explanation after each one.