chalvien.eu
GuidesExpress

cURL Quick Guide for Daily API Work

A practical cURL reference for local development with Express APIs, JWT authentication, and Postgres

Introduction

This guide is a practical curl reference for local development with:

  • Express APIs
  • JWT authentication
  • PostgreSQL-backed endpoints

You can copy and run each command as-is (adjust host, port, and payloads).

1. Core cURL patterns

Most daily commands use these flags:

  • -X or --request: HTTP method (GET, POST, PATCH, DELETE)
  • -H or --header: request headers
  • -d or --data: JSON/form payload
  • -i: include response headers
  • -s: silent mode (useful in scripts)

Examples:

# GET (default method is GET, so -X GET is optional)
curl -i http://localhost:5000/health

# POST with JSON
curl -i -X POST http://localhost:5000/api/users \
  -H 'Content-Type: application/json' \
  -d '{"name":"Max","email":"max@example.com"}'

2. Helpful shell variables

Using variables makes commands shorter and repeatable.

API='http://localhost:5000'
EMAIL='admin@example.com'
PASS='StrongPassword123!'

3. JWT auth flow (bootstrap -> login -> protected routes)

These examples assume endpoints like:

  • POST /api/auth/bootstrap
  • POST /api/auth/login
  • GET /api/auth/me
  • POST /api/auth/refresh
  • POST /api/auth/logout

Create the first admin (dev setup):

curl -i -X POST "$API/api/auth/bootstrap" \
  -H 'Content-Type: application/json' \
  -d '{"email":"admin@example.com","password":"StrongPassword123!","name":"System Admin"}'

Login and capture access token with jq:

ACCESS_TOKEN=$(curl -s -X POST "$API/api/auth/login" \
  -H 'Content-Type: application/json' \
  -d "{\"email\":\"$EMAIL\",\"password\":\"$PASS\"}" \
  | jq -r '.accessToken')

echo "$ACCESS_TOKEN"

Use JWT for protected route:

curl -i "$API/api/auth/me" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

If refresh token is in an HttpOnly cookie, persist cookies with -c and -b.

Login and store cookies:

curl -i -X POST "$API/api/auth/login" \
  -H 'Content-Type: application/json' \
  -c cookies.txt \
  -d "{\"email\":\"$EMAIL\",\"password\":\"$PASS\"}"

Refresh access token using cookie:

curl -i -X POST "$API/api/auth/refresh" \
  -b cookies.txt

Logout and clear server-side refresh state:

curl -i -X POST "$API/api/auth/logout" \
  -b cookies.txt

5. Express + PostgreSQL daily CRUD examples

Assume a users table in PostgreSQL and these API routes:

  • GET /api/users
  • GET /api/users/:id
  • POST /api/users
  • PATCH /api/users/:id
  • DELETE /api/users/:id

Create user:

curl -i -X POST "$API/api/users" \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{"name":"Nnamdi","email":"nnamdi@example.com"}'

List users:

curl -i "$API/api/users" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Get one user:

curl -i "$API/api/users/1" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Update user:

curl -i -X PATCH "$API/api/users/1" \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{"name":"Nnamdi Okafor"}'

Delete user:

curl -i -X DELETE "$API/api/users/1" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

6. Minimal Express + pg endpoint example

If you need a tiny reference implementation:

const express = require("express")
const { Pool } = require("pg")

const app = express()
app.use(express.json())

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
})

app.get("/health", async (req, res) => {
  const { rows } = await pool.query("select now() as now")
  res.json({ ok: true, dbTime: rows[0].now })
})

app.get("/api/users", async (req, res) => {
  const { rows } = await pool.query(
    "select id, name, email from users order by id desc limit 50"
  )
  res.json({ users: rows })
})

app.post("/api/users", async (req, res) => {
  const { name, email } = req.body
  const { rows } = await pool.query(
    "insert into users(name, email) values($1, $2) returning id, name, email",
    [name, email]
  )
  res.status(201).json({ user: rows[0] })
})

app.listen(5000, () => {
  console.log("API running on http://localhost:5000")
})

7. PostgreSQL quick checks from API perspective

Check API health (includes DB check):

curl -i "$API/health"

Example filtered list endpoint:

curl -i "$API/api/users?limit=20&offset=0" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

8. Common troubleshooting

  • 401 Unauthorized: token missing, expired, or wrong secret.
  • 403 Forbidden: token valid but role not allowed.
  • 400 Bad Request: invalid JSON payload or missing required fields.
  • 500 Internal Server Error: backend query/runtime issue. Check API logs.

Use verbose mode when debugging:

curl -v -X GET "$API/api/users" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

9. Copy-paste daily sequence

API='http://localhost:5000'
EMAIL='admin@example.com'
PASS='StrongPassword123!'

curl -s -X POST "$API/api/auth/bootstrap" \
  -H 'Content-Type: application/json' \
  -d '{"email":"admin@example.com","password":"StrongPassword123!","name":"System Admin"}'

ACCESS_TOKEN=$(curl -s -X POST "$API/api/auth/login" \
  -H 'Content-Type: application/json' \
  -d "{\"email\":\"$EMAIL\",\"password\":\"$PASS\"}" | jq -r '.accessToken')

curl -s "$API/api/auth/me" -H "Authorization: Bearer $ACCESS_TOKEN"

curl -s -X POST "$API/api/users" \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{"name":"Max","email":"max@example.com"}'

curl -s "$API/api/users" -H "Authorization: Bearer $ACCESS_TOKEN"

10. Windows PowerShell equivalent commands

PowerShell ships built-in JSON parsing so you don't need jq. Use Invoke-RestMethod (aliased as irm) or Invoke-WebRequest (aliased as iwr).

Setup variables:

$API   = 'http://localhost:5000'
$EMAIL = 'admin@example.com'
$PASS  = 'StrongPassword123!'

Bootstrap first admin:

Invoke-RestMethod -Method Post "$API/api/auth/bootstrap" `
  -ContentType 'application/json' `
  -Body '{"email":"admin@example.com","password":"StrongPassword123!","name":"System Admin"}'

Login and capture access token (no jq needed):

$login = Invoke-RestMethod -Method Post "$API/api/auth/login" `
  -ContentType 'application/json' `
  -Body (ConvertTo-Json @{ email = $EMAIL; password = $PASS })

$TOKEN = $login.accessToken
Write-Host $TOKEN

Request a protected route:

Invoke-RestMethod "$API/api/auth/me" `
  -Headers @{ Authorization = "Bearer $TOKEN" }

Refresh token (cookie is stored automatically by the session):

$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession

Invoke-RestMethod -Method Post "$API/api/auth/login" `
  -ContentType 'application/json' `
  -Body (ConvertTo-Json @{ email = $EMAIL; password = $PASS }) `
  -SessionVariable session | Out-Null

$refresh = Invoke-RestMethod -Method Post "$API/api/auth/refresh" `
  -WebSession $session

$TOKEN = $refresh.accessToken

Logout:

Invoke-RestMethod -Method Post "$API/api/auth/logout" `
  -WebSession $session

Full CRUD against users:

$headers = @{ Authorization = "Bearer $TOKEN" }

# Create
Invoke-RestMethod -Method Post "$API/api/users" `
  -ContentType 'application/json' `
  -Headers $headers `
  -Body (ConvertTo-Json @{ name = 'Nnamdi'; email = 'nnamdi@example.com' })

# List
Invoke-RestMethod "$API/api/users" -Headers $headers

# Get one
Invoke-RestMethod "$API/api/users/1" -Headers $headers

# Update
Invoke-RestMethod -Method Patch "$API/api/users/1" `
  -ContentType 'application/json' `
  -Headers $headers `
  -Body (ConvertTo-Json @{ name = 'Nnamdi Okafor' })

# Delete
Invoke-RestMethod -Method Delete "$API/api/users/1" -Headers $headers

Verbose debugging (equivalent to curl -v):

Invoke-WebRequest "$API/api/users" `
  -Headers @{ Authorization = "Bearer $TOKEN" } `
  -Verbose

Copy-paste daily sequence:

$API   = 'http://localhost:5000'
$EMAIL = 'admin@example.com'
$PASS  = 'StrongPassword123!'

# Bootstrap (once)
Invoke-RestMethod -Method Post "$API/api/auth/bootstrap" `
  -ContentType 'application/json' `
  -Body '{"email":"admin@example.com","password":"StrongPassword123!","name":"System Admin"}'

# Login
$TOKEN = (Invoke-RestMethod -Method Post "$API/api/auth/login" `
  -ContentType 'application/json' `
  -Body (ConvertTo-Json @{ email = $EMAIL; password = $PASS })).accessToken

# Me
Invoke-RestMethod "$API/api/auth/me" -Headers @{ Authorization = "Bearer $TOKEN" }

# Create user
Invoke-RestMethod -Method Post "$API/api/users" `
  -ContentType 'application/json' `
  -Headers @{ Authorization = "Bearer $TOKEN" } `
  -Body (ConvertTo-Json @{ name = 'Max'; email = 'max@example.com' })

# List users
Invoke-RestMethod "$API/api/users" -Headers @{ Authorization = "Bearer $TOKEN" }

On this page