> 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/components/controller.md).

# Controller

A **controller** is the HTTP entry point. In soap-express it is **decorator-based**: `@Controller` sets the base path, route decorators map methods to endpoints, and `ResultMapper` turns a `Result` into an HTTP response. Controllers live in a feature's `api/` folder and depend on use cases or CQRS buses.

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

@Controller('/comics')
export class ComicsController {
  constructor(
    @Inject(ListComicsUseCase.Token) private readonly listComics: ListComicsUseCase,
    @Inject(CreateComicUseCase.Token) private readonly createComic: CreateComicUseCase,
  ) {}

  @Get('/')
  async list(req: Request, res: Response): Promise<void> {
    const result = await this.listComics.execute({ publisher: req.query.publisher as string });
    ResultMapper.toResponse(result, res);
  }

  @Post('/')
  @AdminOnly()
  async create(req: Request, res: Response): Promise<void> {
    const result = await this.createComic.execute(req.body);
    ResultMapper.toResponse(result, res, { successStatus: 201 });
  }
}
```

Register it in `bootstrap()`:

```typescript
await bootstrap({ controllers: [ComicsController], container });
```

Decorators:

* **Routes:** `@Get` `@Post` `@Put` `@Delete` `@Patch` `@Head` `@Options`
* **Auth:** `@Auth(strategy)` `@AdminOnly()` `@RolesOnly(roles)` `@SelfOnly()` `@Public()`

A controller can also dispatch CQRS commands/queries via `CommandBus` / `QueryBus` instead of calling use cases directly — see CQRS & Events.
