Skip to content

Add configurable per-route-group request body size limits - #689

Merged
Chucks1093 merged 1 commit into
accesslayerorg:mainfrom
davedumto:feat/route-group-body-size-limits-146
Jul 28, 2026
Merged

Add configurable per-route-group request body size limits#689
Chucks1093 merged 1 commit into
accesslayerorg:mainfrom
davedumto:feat/route-group-body-size-limits-146

Conversation

@davedumto

Copy link
Copy Markdown
Contributor

Summary

Replaces the single, hardcoded express.json({ limit: '10mb' }) applied globally with a configurable, per-route-group body size ceiling — so a route group that genuinely needs a tighter (or looser) limit than the rest of the API can be tuned independently via env vars, without touching every other route.

closes #146

Changes

  • src/middlewares/body-size-limit.middleware.ts (new): exports getBodySizeLimit(group) — resolves a per-group override or falls back to BODY_SIZE_LIMIT_DEFAULT — and routeBodySizeLimit(group), which returns an express.json({ limit }) instance for that group. Groups: auth, admin, creators, default.
  • src/config.schema.ts: adds BODY_SIZE_LIMIT_DEFAULT (default '10mb') plus optional BODY_SIZE_LIMIT_AUTH / _ADMIN / _CREATORS overrides, validated the same way as the rest of envConfig (parsed once via envSchema.parse(process.env) at import time).
  • src/modules/index.ts: every router.use(...) call for a sub-router now also mounts routeBodySizeLimit(<group>) ahead of it. Mapping: auth→auth, admin→admin, the three creators routers→creators, everything else (health, config, metrics, ledger, activity, ownership, wallets, alerts)→default.
  • src/app.ts: removes the old global app.use(express.json({ limit: '10mb' })) + app.use(bodyParseErrorMiddleware) pair from before the router. bodyParseErrorMiddleware is re-mounted immediately after app.use('/api/v1', router) instead — Express error-handling middleware only catches errors from points later in the stack than where it's registered, and since JSON parsing now happens inside the router (per group) rather than before it, the error handler has to move down to still catch entity.too.large and other body-parse failures.
  • .env.example: documents BODY_SIZE_LIMIT_DEFAULT and the three optional overrides.
  • docs/body-size-limits.md (new): overview, the default/override table, a step-by-step guide for adding an override for a new route group, the exact 413 response shape and structured-logging behavior (no raw body ever logged), matching the style of the existing docs/rate-limiting.md.

No route currently needs a limit above the existing 10mb default (there's no base64 image upload anywhere in the codebase — avatarUrl etc. are plain URL strings) — only auth, admin, and creators get dedicated override knobs since those are the groups most likely to need one later; every other group shares the single configurable default rather than getting its own unused env var.

Test plan

  • src/middlewares/body-size-limit.middleware.test.ts (new, 7 tests): default resolution, fallback for unconfigured groups, group-specific override, multiple simultaneous overrides, non-default BODY_SIZE_LIMIT_DEFAULT propagation, routeBodySizeLimit returns a valid middleware function, distinct instances per call. Uses jest.resetModules() + jest.doMock per case since GROUP_OVERRIDES is captured once at module load (mirroring how envConfig itself is a one-time snapshot).
  • src/__tests__/integration/body-size-limit.integration.test.ts (new, 3 tests, real Express app + supertest): an oversized payload to POST /api/v1/auth/login under a tiny configured BODY_SIZE_LIMIT_AUTH returns exactly { status: 413, body: { success: false, code: 'BAD_REQUEST', message: 'Request payload too large' } }; a normal-sized payload is not rejected for size (falls through to real controller logic); GET /api/v1/health (default group) is unaffected by an unrelated group's tiny override.
  • Both new test files pass in isolation (10/10). Ran the full jest suite twice (once at full parallelism, once with --maxWorkers=2) — under heavy worker contention some unrelated suites intermittently time out, and one pre-existing suite (src/middlewares/deprecation.middleware.test.ts) fails to run because it has no actual it()/describe() blocks (confirmed pre-existing, no diff vs main) — neither is caused by this change.
  • npx tsc -b and npx eslint on all touched files are clean.

…ayerorg#146)

Adds a configurable request body size ceiling per route group instead
of one hardcoded 10mb limit applied globally. auth/admin/creators
routes can each override BODY_SIZE_LIMIT_DEFAULT via their own env var
(BODY_SIZE_LIMIT_AUTH/_ADMIN/_CREATORS); every other group falls back
to the default. Oversized requests get a structured 413 response
(no raw body logged) via bodyParseErrorMiddleware.

JSON parsing moves from a single global app.use() before the router
to per-group instances mounted inside modules/index.ts, so
bodyParseErrorMiddleware — which only catches errors from middleware
registered after it — is relocated to just after the router mount.

Documented in docs/body-size-limits.md alongside the existing
rate-limiting docs.
@drips-wave

drips-wave Bot commented Jul 28, 2026

Copy link
Copy Markdown

@davedumto Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Chucks1093
Chucks1093 merged commit 8c090d0 into accesslayerorg:main Jul 28, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add configurable request body size limits by route group

2 participants