Migrating from Express
StreetJS replaces the Express runtime entirely — there is no express() app and no
pg/body-parser/cors middleware stack to wire up. Routing is decorator-based,
JSON body parsing is built in, and security headers / CORS / auth ship as
first-class middleware. This guide maps the Express concepts you know onto StreetJS.
All snippets use the real public API:
streetApp,@Controller/@Get/@Post,@Injectable,StreetContext, and the built-in exception classes.
Mental-model mapping
| Express | StreetJS |
|---|---|
const app = express() |
const app = streetApp({ port: 3000 }) |
app.get('/x', handler) |
@Get('/x') method on a @Controller class |
app.use(express.json()) |
built in — JSON bodies parse automatically |
app.use(cors()) |
corsMiddleware(...) |
helmet() |
securityHeaders(...) |
req / res |
a single ctx: StreetContext |
res.json(obj) |
ctx.json(obj) |
res.status(404).json(...) |
throw new NotFoundException(...) |
next(err) |
throw a StreetException (centralized handler) |
| service singletons (manual) | @Injectable() + DI container |
Routing
Express
1
2
3
4
5
6
7
8
9
10
11
12
13
const express = require('express');
const app = express();
app.use(express.json());
app.get('/api/users/:id', (req, res) => {
res.json({ id: req.params.id });
});
app.post('/api/users', (req, res) => {
res.status(201).json({ created: req.body.name });
});
app.listen(3000);
StreetJS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import 'reflect-metadata';
import { streetApp, Controller, Get, Post } from 'streetjs';
import type { StreetContext } from 'streetjs';
@Controller('/api/users')
class UserController {
@Get('/:id')
async getOne(ctx: StreetContext) {
ctx.json({ id: ctx.params.id });
}
@Post('/')
async create(ctx: StreetContext) {
const body = ctx.body as { name: string };
ctx.status(201).json({ created: body.name });
}
}
const app = streetApp({ port: 3000 });
app.registerController(UserController);
await app.listen();
Middleware
Express
1
2
3
4
5
6
7
8
app.use(cors({ origin: 'https://app.example.com' }));
app.use(helmet());
function auth(req, res, next) {
if (!req.headers.authorization) return res.status(401).end();
next();
}
app.get('/private', auth, handler);
StreetJS — CORS, security headers, and auth are built-in middleware:
1
2
3
4
5
6
7
8
9
import { streetApp, corsMiddleware, securityHeaders, authMiddleware, requireRoles } from 'streetjs';
const app = streetApp({ port: 3000 });
app.use(corsMiddleware({ origin: 'https://app.example.com' }));
app.use(securityHeaders());
// Route-level authorization via decorator metadata / middleware:
app.use(authMiddleware({ /* jwt verification options */ }));
// then guard specific roles with requireRoles('admin') on the route/controller
Error handling
Express uses error-first middleware; StreetJS uses typed exceptions caught by a central handler that produces a safe JSON response (no stack-trace leakage).
Express
1
2
3
4
5
6
app.get('/x', (req, res, next) => {
const item = find(req.params.id);
if (!item) return next(new Error('not found'));
res.json(item);
});
app.use((err, req, res, next) => res.status(500).json({ error: err.message }));
StreetJS
1
2
3
4
5
6
7
8
9
10
11
12
import { Controller, Get, NotFoundException } from 'streetjs';
import type { StreetContext } from 'streetjs';
@Controller('/x')
class XController {
@Get('/:id')
async getOne(ctx: StreetContext) {
const item = find(ctx.params.id);
if (!item) throw new NotFoundException('item not found'); // → 404 JSON
ctx.json(item);
}
}
Available exceptions: BadRequestException (400), UnauthorizedException (401),
ForbiddenException (403), NotFoundException (404), ConflictException (409),
and the base StreetException.
Dependency injection (replacing manual singletons)
Express — you new-up and pass services manually. StreetJS — annotate with
@Injectable() and the container wires constructor dependencies:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Injectable, Controller, Get } from 'streetjs';
import type { StreetContext } from 'streetjs';
@Injectable()
class UserService {
list() { return [{ id: 1 }]; }
}
@Controller('/users')
class UserController {
constructor(private readonly users: UserService) {}
@Get('/')
async list(ctx: StreetContext) {
ctx.json(this.users.list());
}
}
Database (no pg)
Express apps typically add pg. StreetJS ships a native PostgreSQL wire driver:
1
2
3
4
import { PgPool } from 'streetjs';
const pool = new PgPool({ host: 'localhost', database: 'app', user: 'app', password: '...' });
const result = await pool.query('SELECT * FROM users WHERE id = $1', [id]); // parameterized
Checklist
- Replace
express()withstreetApp({ port }). - Convert route handlers to
@Controllerclasses with@Get/@Post/.... - Drop
body-parser— JSON parses automatically viactx.body. - Replace
cors()/helmet()withcorsMiddleware/securityHeaders. - Replace
next(err)with thrownStreetExceptionsubclasses. - Replace manual service wiring with
@Injectable()+ constructor injection. - Replace
pgwithPgPool.
See also: Migrating from NestJS · Migrating from Fastify.