Appearance
Cheatsheet
Compact map for when you remember the idea but not the spelling.
Boot
ts
import express from 'express'
const app = express()
app.use(express.json())
app.listen(3000)Routing
ts
import { Router } from 'express'
const r = Router()
r.get('/', list)
r.get('/:id', getOne)
r.post('/', create)
app.use('/api/notes', r)| Piece | Access |
|---|---|
| Params | req.params.id |
| Query | req.query.q |
| Body | req.body (needs express.json()) |
| Header | req.get('Authorization') |
Responses
ts
res.json({ ok: true })
res.status(201).json({ id })
res.status(204).end()
res.status(400).json({ error: '…' })Middleware
ts
app.use(logger) // all routes
app.get('/x', requireAuth, h) // one route
app.use('/api/notes', requireAuth, notesRouter)Error middleware = 4 args, after routes:
ts
app.use((err, req, res, next) => {
res.status(err.status ?? 500).json({ error: err.message ?? 'server error' })
})Env + CORS
ts
import 'dotenv/config'
import cors from 'cors'
app.use(cors({ origin: process.env.CORS_ORIGIN }))SQLite (better-sqlite3)
ts
const row = db.prepare('SELECT * FROM users WHERE email = ?').get(email)
db.prepare('INSERT INTO users (email, password_hash) VALUES (?, ?)').run(email, hash)Passwords
ts
import bcrypt from 'bcryptjs'
const hash = await bcrypt.hash(password, 10)
const ok = await bcrypt.compare(password, hash)JWT
ts
import jwt from 'jsonwebtoken'
const token = jwt.sign({ sub: userId }, secret, { expiresIn: '7d' })
const payload = jwt.verify(token, secret) as { sub: number }
// Header: Authorization: Bearer <token>Auth routes (shape)
| Method | Path | Body |
|---|---|---|
| POST | /api/auth/register | { email, password } → { token, user } |
| POST | /api/auth/login | { email, password } → { token, user } |
| GET | /api/me | Bearer → { user } |
| POST | /api/auth/verify | { token } |
| POST | /api/auth/forgot | { email } |
| POST | /api/auth/reset | { token, password } |
Mail (Nodemailer)
ts
await transporter.sendMail({ from, to, subject, text, html })
// Ethereal: nodemailer.getTestMessageUrl(info)Status codes
| Code | Use |
|---|---|
| 201 | Created |
| 400 | Validation |
| 401 | AuthN failed |
| 403 | AuthZ failed |
| 404 | Missing |
| 409 | Conflict (duplicate email) |
| 500 | Server fault |
Security quick list
- Zod on inputs
helmet()- Rate limit
/api/auth - Bound SQL params
- Strong
JWT_SECRET - Never return
password_hash
Prisma (sketch)
ts
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
await prisma.note.create({ data: { title, body, userId } })
await prisma.note.findMany({ where: { userId }, include: { user: true } })bash
npx prisma migrate dev
npx prisma generateSessions
ts
import session from 'express-session'
app.use(cors({ origin, credentials: true }))
app.use(session({ secret, resave: false, saveUninitialized: false, cookie: { httpOnly: true } }))
req.session.userId = user.id
// SPA: fetch(url, { credentials: 'include' })Files (multer)
ts
import multer from 'multer'
const upload = multer({ dest: 'uploads/', limits: { fileSize: 5_000_000 } })
app.post('/api/files', requireAuth, upload.single('file'), handler)
// SPA: FormData + fetch without Content-Type header
res.download(absPath, originalName)WebSockets (ws)
ts
import http from 'node:http'
import { WebSocketServer } from 'ws'
const server = http.createServer(app)
const wss = new WebSocketServer({ server, path: '/ws' })
server.listen(3000)
// SPA: new WebSocket(`ws://localhost:3000/ws?token=${jwt}`)Caching
ts
res.set('Cache-Control', 'public, max-age=60')
res.set('Cache-Control', 'private, no-store')
cacheGet(key) / cacheSet(key, value, ttlMs) / cacheDel(key)
// key must include user id + filters; invalidate on writes
// Redis: SET key json EX secondsBest,
-- ł.