Skip to content

Controllers

A controller is a class annotated with @DController(path). Methods inside it become handlers when annotated with one of @DGet / @DPost / @DPut / @DPatch / @DDelete.

typescript
import {
    DController,
    DGet,
    DPost,
    DPut,
    DPatch,
    DDelete,
    DPath,
    DBody,
} from '@routup/decorators';

@DController('/users')
export class UserController {
    @DGet('')          async list()                                {}
    @DGet('/:id')      async show(@DPath('id') id: string)         {}
    @DPost('')         async create(@DBody() body: any)            {}
    @DPut('/:id')      async replace(@DPath('id') id: string)      {}
    @DPatch('/:id')    async patch(@DPath('id') id: string)        {}
    @DDelete('/:id')   async remove(@DPath('id') id: string)       {}
}

The full path is controllerPath + methodPath, so the show handler above resolves to GET /users/:id.

Returning values

In routup v5, handlers return values directly — no send(res, data). The return value is converted to a Response by the core (see routup's response model):

typescript
@DGet('')
async list() {
    return [{ id: 1 }, { id: 2 }];   // → application/json
}

@DGet('/raw')
async raw() {
    return 'hello';                  // → text/plain
}

@DGet('/file')
async file() {
    return new Response(buffer, { headers: { 'content-type': 'image/png' } });
}

Accessing the event

Use @DContext() when you need the full IRoutupEvent (e.g. to set event.response.status, read event.headers, mutate event.store):

typescript
import type { IRoutupEvent } from 'routup';
import { DContext, DController, DPost } from '@routup/decorators';

@DController('/orders')
export class OrderController {
    @DPost('')
    async create(@DContext() event: IRoutupEvent) {
        event.response.status = 201;
        return { id: '...' };
    }
}

Async handlers

All method decorators support async handlers; the plugin awaits the returned promise before passing the result to the response pipeline.

Multiple controllers

Pass an array to decorators({ controllers: [...] }). Each controller's @DController(path) becomes a sub-mount:

typescript
router.use(decorators({
    controllers: [UserController, OrderController, AuthController],
    // ...
}));

See also

  • Parameters — every @D* parameter decorator
  • Overview — installation, tsconfig, and full app wiring

Released under the MIT License.