E-NO
Express API commands 7 Min Read

Express API basic commands with practical examples: an operations playbook

calendar_today Published: 2026-08-11
update Last Updated: 2026-08-12
analytics SEO Efficiency: 100%
Technical guide illustration for Express API basic commands with practical examples: an operations playbook.

Intro

This guide shows how to operate an Express API safely using concrete, minimal commands. You will move from observation to a verified change, with examples you can run locally or in production-like environments. The focus is operational safety: observe first, limit the blast radius, use placeholders instead of secrets, verify results, and document how to recover if the expected state is not reached.

Scope and audience: developers, DevOps engineers, and startup teams who run Node.js Express APIs. Examples target Express 4.x/5.x on Node.js LTS and work with common deployment setups (local node, PM2, systemd, Docker). Replace placeholders like <PORT> and <SERVICE_NAME> with your own values.

Version and Environment Inventory

Goal: capture what is running, where, and how, using read-only commands before you change anything.

Prerequisites:

  • Node.js LTS (v18 or later recommended) and npm
  • curl or httpie for HTTP checks
  • Access to your app directory (<PROJECT_DIR>) or container/orchestrator
  1. Record versions and timestamps
# Timestamp (record in your change notes)
date -u

# Node and npm versions
node -v
npm -v

# Express version in the current project
cd <PROJECT_DIR>
npm ls express --depth=0 || echo "Express not installed here"

# Application version (from package.json)
node -p "require('./package.json').version" 2>/dev/null || echo "No package.json version"
  1. Identify topology and runtime
  • Local node process:
ps aux | grep node | grep <PROJECT_DIR> | grep -v grep
lsof -i :<PORT> -sTCP:LISTEN || ss -lntp | grep :<PORT>
  • PM2:
pm2 status
pm2 describe <SERVICE_NAME>
pm2 logs <SERVICE_NAME> --lines 50
  • systemd:
systemctl status <SERVICE_NAME>.service
journalctl -u <SERVICE_NAME>.service -n 100 --no-pager
  • Docker:
docker ps --filter "name=<SERVICE_NAME>"
docker logs <CONTAINER_ID> --tail 100

docker inspect <CONTAINER_ID> --format '{{json .NetworkSettings.Ports}}' | jq
  1. Read-only API observations

Start with endpoints that do not change state. If you do not have health endpoints yet, add them later using the Safe Configuration Path.

# Replace with your host/port and route
curl -sS -D - http://localhost:<PORT>/health || echo "Health not reachable"

# View status code and timing
curl -sS -o /dev/null -w "status=%{http_code} time=%{time_total}\n" http://localhost:<PORT>/health

Define your expected result and a failure signal before acting. For example: expected 200 OK within 100 ms; failure is connection refused, timeout, or 5xx.

Safety notes:

  • Keep credentials, tokens, and service URLs out of terminal history. Use environment variables like $DB_URI and never paste real secrets into documentation or tickets.
  • Do not restart or redeploy during inventory. The goal is to learn, not to change.

Safe Configuration Path

Goal: make the smallest justified change, verify it, and have a tested path to undo it.

Example change A: add basic operational endpoints (/health, /ready, /version) without exposing secrets.

Prerequisites:

  • You control <PROJECT_DIR>
  • You can restart the process (PM2/systemd/Docker) with minimal impact
  1. Observe current state
# Baseline: latency and status
curl -sS -o /dev/null -w "status=%{http_code} time=%{time_total}\n" http://localhost:<PORT>/health
  1. Make the minimal change

app.js (or server.js):

const express = require('express');
const pkg = require('./package.json');

const app = express();
const PORT = process.env.PORT || 3000;

// Safe body size limit; adjust as needed
app.use(express.json({ limit: process.env.JSON_LIMIT || '1mb' }));

// Health endpoints: read-only, no secrets
app.get('/health', (req, res) => res.status(200).json({ status: 'ok' }));
app.get('/ready', (req, res) => {
  // Optionally check downstreams (DB ping, cache). Return 503 if not ready.
  res.status(200).json({ ready: true });
});
app.get('/version', (req, res) => res.json({ name: pkg.name, version: pkg.version }));

app.listen(PORT, () => {
  console.log(`API listening on :${PORT}`);
});
  1. Verify the outcome
# Restart via PM2
pm2 restart <SERVICE_NAME> && pm2 logs <SERVICE_NAME> --lines 20

# Or systemd
sudo systemctl restart <SERVICE_NAME>.service
sudo systemctl status <SERVICE_NAME>.service --no-pager

# Or Docker Compose
docker compose up -d --no-deps --build <SERVICE_NAME>

echo "HEALTH:";  curl -sS -D - http://localhost:<PORT>/health -o /dev/null | head -n 1
echo "READY :";  curl -sS -D - http://localhost:<PORT>/ready  -o /dev/null | head -n 1
echo "VER  :";  curl -sS http://localhost:<PORT>/version | jq

Expected result: /health and /ready return 200, /version returns name and version fields.

  1. Recovery path
  • If the process fails to start: revert the code change (git restore), redeploy, and confirm status returns to baseline.
  • If only one endpoint is failing (e.g., /ready due to a downstream check): return a static 200 temporarily, create a follow-up task to implement proper readiness checks.

Example change B: configure strict CORS for a single origin.

const cors = require('cors');
app.use(cors({ origin: process.env.CORS_ORIGIN || 'https://app.example.com', methods: ['GET','POST','PUT','DELETE','OPTIONS'] }));

Verification:

# Preflight check
curl -sS -i -X OPTIONS \
  -H "Origin: https://app.example.com" \
  -H "Access-Control-Request-Method: GET" \
  http://localhost:<PORT>/health | sed -n '1,10p'

Rollback: remove the CORS middleware line and restart, or set CORS_ORIGIN to a safe value.

Verification and Diagnostics

Goal: confirm behavior objectively and isolate issues quickly using read-only tools first.

  1. HTTP-level checks
# Status + timing
curl -sS -o /dev/null -w "status=%{http_code} time=%{time_total}\n" http://localhost:<PORT>/health

# Headers and body preview
curl -sS -D - http://localhost:<PORT>/version | sed -n '1,20p'

# JSON correctness
curl -sS http://localhost:<PORT>/version | jq type
  1. Routing and content-type errors

Common signals:

  • 404 Not Found: wrong path or base URL mismatch. Verify route registration and mount path.
  • 415 Unsupported Media Type: client missed Content-Type header. Try:
curl -sS -X POST http://localhost:<PORT>/items \
  -H 'Content-Type: application/json' \
  -d '{"name":"demo"}' -i
  1. CORS diagnostics
# Preflight OPTIONS must return 204/200 and Access-Control-Allow-* headers
curl -sS -i -X OPTIONS \
  -H "Origin: https://app.example.com" \
  -H "Access-Control-Request-Method: POST" \
  http://localhost:<PORT>/items | sed -n '1,20p'
  1. Process and logs
# PM2
pm2 logs <SERVICE_NAME> --lines 50

# systemd
journalctl -u <SERVICE_NAME>.service -n 100 --no-pager

# Docker
docker logs <CONTAINER_ID> --tail 100
  1. Port conflicts and binding
# Check if the port is already used
lsof -i :<PORT> -sTCP:LISTEN || ss -lntp | grep :<PORT>

If the port is in use and you cannot stop the other service, set a new PORT in the environment and restart your API.

Failure Modes and Recovery

  1. EADDRINUSE: address already in use
  • Signal: startup error mentioning EADDRINUSE.
  • Fix: identify the conflicting process and pick a new port or stop the conflict.
lsof -i :<PORT>
# Safer recovery: change PORT
export PORT=<NEW_PORT>
pm2 restart <SERVICE_NAME>
  1. 503 on /ready but /health is 200
  • Signal: readiness depends on a downstream (database, cache) that is not reachable.
  • Fix: verify downstream connectivity separately, keep /health green.
# Example DB TCP reachability (replace host/port)
nc -zv <DB_HOST> <DB_PORT> || echo "DB not reachable"
  • Recovery: gate traffic at the load balancer on /ready until downstream is restored.
  1. 413 Payload Too Large on JSON POST
  • Signal: clients receive 413 for larger requests.
  • Fix: raise the body size limit cautiously.
app.use(express.json({ limit: process.env.JSON_LIMIT || '5mb' }));
  • Verify with a test payload; rollback by restoring the previous limit.
  1. Unhandled promise rejections causing crashes
  • Signal: process exits intermittently, logs mention unhandledRejection.
  • Fix: log and handle rejections; use a process manager to auto-restart.
process.on('unhandledRejection', (err) => {
  console.error('unhandledRejection', err);
});
  • Recovery: deploy the logging fix, monitor; if instability continues, rollback to the last known good build.
  1. Docker port not exposed
  • Signal: container healthy, host port not reachable.
  • Fix: correct port mapping.
# Wrong: container listens on 3000 but no mapping on host
# Right:
docker run -d --name <SERVICE_NAME> -p 3000:3000 <IMAGE_TAG>
  • Verify with curl to the host port; rollback by stopping the incorrect container and recreating with proper mapping.

Operations Checklist

Use this when proposing or executing a change to an Express API.

Before you change anything:

  • Confirm component and versions (Node, npm, Express, app version).
  • Capture current health: status codes and latency for /health and key routes.
  • Gather logs for the last 100 lines and note the timestamp.
  • Identify deployment topology (local, PM2, systemd, Docker) and access method.
  • Define success criteria (e.g., 200 on /health, p95 < 150 ms) and failure signals.
  • Define a rollback (git revert, previous image tag, env var reset).

During the change:

  • Touch one scoped item: a single env var, a single middleware, or a single port mapping.
  • Add comments or commit messages with the change ID and timestamp.
  • Avoid editing multiple unrelated files.

After the change:

  • Verify endpoints with curl, including timing output.
  • Check logs for errors or warnings introduced by the change.
  • Compare latency and error rate to pre-change baselines.
  • Document the outcome and whether rollback was needed.

Example verification block you can paste into a runbook:

set -e
BASE=http://localhost:<PORT>
for path in /health /ready /version; do
  echo "Checking $path";
  curl -sS -o /dev/null -w "$path status=%{http_code} time=%{time_total}\n" "$BASE$path";
done

Conclusion

Express API operations are reliable when every step is version-scoped, observable, and reversible. Start with inventory and read-only checks, make the smallest change that solves a clear problem, verify with concrete signals (status codes, headers, and timing), and keep a real rollback ready. Use placeholders instead of secrets, limit the blast radius to one scoped item at a time, and document expected outcomes and recovery steps. With this playbook, you can diagnose issues faster, implement safer changes, and keep your Express API stable in development and production.

Related Research

Article Quality Score

Reader usefulness 100%
  • check_circle Reader-ready guide
  • check_circle Practical examples included
  • check_circle Clean SEO article URL