> For the complete documentation index, see [llms.txt](https://docs.soapjs.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.soapjs.com/plugins/node.js/soap-express.md).

# Soap Express

`@soapjs/soap-express` is the HTTP layer for SoapJS on Express — controllers, routing, middleware, auth guards, and CQRS wiring — assembled with a single `bootstrap()` call.

> Current version: **0.3.x**. Requires `@soapjs/soap` ≥ 0.10.

### Install

```bash
npm install @soapjs/soap @soapjs/soap-express reflect-metadata express
```

### Bootstrap

`bootstrap()` wires Express, middleware, routing, auth and CQRS in one call:

```typescript
import 'reflect-metadata';
import { bootstrap } from '@soapjs/soap-express';

const app = await bootstrap({
  port: 3000,
  container,                 // your pre-wired DIContainer
  controllers: [CharactersController, AuthController],
  middleware: { cors: true, helmet: true, logging: true, compression: true },
  auth: jwtStrategy,         // guards @Auth() routes
  cqrs: true,                // wire CommandBus + QueryBus
  healthCheck: true,
});
```

### Controllers & routes

```typescript
import { Controller, Get, Post, Auth, AdminOnly, ResultMapper } from '@soapjs/soap-express';

@Controller('/characters')
export class CharactersController {
  constructor(@Inject('QueryBus') private readonly queryBus: QueryBus) {}

  @Get('/')
  async list(req: Request, res: Response): Promise<void> {
    const result = await this.queryBus.dispatch(new ListCharactersQuery());
    ResultMapper.toResponse(result, res);
  }

  @Post('/')
  @AdminOnly()
  async create(req: Request, res: Response): Promise<void> { /* ... */ }
}
```

Route decorators: `@Get` `@Post` `@Put` `@Delete` `@Patch` `@Head` `@Options`. Auth decorators: `@Auth(strategy)` `@AdminOnly()` `@RolesOnly(roles)` `@SelfOnly()` `@Public()`.

### Authentication

Strategies come from `@soapjs/soap-auth`. Register them on the app, and pass one as `auth:` in `bootstrap()` to guard `@Auth()` routes:

```typescript
app.registerAuth(soapAuth);            // all HTTP strategies from a soap-auth provider
app.registerAuthStrategy(strategy);    // ...or a single strategy
```

### CQRS & Events

With `cqrs: true`, `bootstrap()` binds `CommandBus` + `QueryBus` and registers every `@CommandHandler` / `@QueryHandler`. Controllers inject the buses and dispatch. Domain events use `@EventHandler` — note they are **registered but not auto-wired**; you connect your own event bus. Full details: CQRS & Events.

### Errors → HTTP

`ResultMapper.toResponse(result, res)` maps a `Result` failure to a status code. Register custom mappings at startup:

```typescript
ResultMapper.register('ValidationError', 400);
ResultMapper.register('DomainRuleError', 422);
```

### Full reference

A complete app (controllers, CQRS, events, auth, sockets): the [Comics Universe demo](https://github.com/soapjs/soap-node-demo).
