## What Duck Gen scans

Duck Gen looks for two things in your source code:

1. **Controller classes** decorated with `@Controller()`.
2. **HTTP method decorators** like `@Get()`, `@Post()`, `@Put()`, `@Patch()`, `@Delete()`.

For each decorated method, it extracts the route path, request shape, and response type.
Let us build a controller that demonstrates all of these.

## Create a Users module

First, create the file structure for a Users feature:

```bash
mkdir -p src/users/dto
```

## Define your DTOs

DTOs (Data Transfer Objects) describe the shape of data your API accepts and returns.
Duck Gen reads these types directly from your code.

```ts title="src/users/dto/create-user.dto.ts"
export class CreateUserDto {
  name: string
  email: string
  password: string
}
```

```ts title="src/users/dto/update-user.dto.ts"
export class UpdateUserDto {
  name?: string
  email?: string
}
```

```ts title="src/users/dto/user.dto.ts"
export class UserDto {
  id: string
  name: string
  email: string
  createdAt: string
}
```

```ts title="src/users/dto/pagination.dto.ts"
export class PaginationDto {
  page?: number
  limit?: number
}
```

} title="Why classes instead of interfaces?">
  NestJS uses classes for DTOs because they exist at runtime, which is needed for
  validation pipes. Duck Gen reads the type information from these classes at compile
  time, so it works with both classes and interfaces.

## Define a response wrapper

Most APIs wrap responses in a consistent shape. Create a generic response type:

```ts title="src/common/api-response.ts"
export class ApiResponse<TData, TMessage extends string = string> {
  data: TData
  message: TMessage
  success: boolean
}
```

Duck Gen fully resolves generics, so `ApiResponse<UserDto, UserMessage>` in a return type
will generate the expanded type in the output.

## Build the controller

Now create the Users controller with full CRUD operations:

```ts title="src/users/users.controller.ts"
import { Body, Controller, Delete, Get, Param, Post, Put, Query } from '@nestjs/common'
import { ApiResponse } from '../common/api-response'
import { CreateUserDto } from './dto/create-user.dto'
import { PaginationDto } from './dto/pagination.dto'
import { UpdateUserDto } from './dto/update-user.dto'
import { UserDto } from './dto/user.dto'

type UserMessage = 'USER_CREATED' | 'USER_UPDATED' | 'USER_DELETED' | 'USER_FOUND' | 'USERS_LISTED'

@Controller('users')
export class UsersController {
  @Get()
  findAll(@Query() query: PaginationDto): Promise<ApiResponse<UserDto[], UserMessage>> {
    // Duck Gen extracts:
    // - Method: GET
    // - Path: /api/users
    // - Query: PaginationDto
    // - Response: ApiResponse<UserDto[], UserMessage>
    return {} as any
  }

  @Get(':id')
  findOne(@Param('id') id: string): Promise<ApiResponse<UserDto, UserMessage>> {
    // Duck Gen extracts:
    // - Method: GET
    // - Path: /api/users/:id
    // - Params: { id: string }
    // - Response: ApiResponse<UserDto, UserMessage>
    return {} as any
  }

  @Post()
  create(@Body() body: CreateUserDto): Promise<ApiResponse<UserDto, UserMessage>> {
    // Duck Gen extracts:
    // - Method: POST
    // - Path: /api/users
    // - Body: CreateUserDto
    // - Response: ApiResponse<UserDto, UserMessage>
    return {} as any
  }

  @Put(':id')
  update(
    @Param('id') id: string,
    @Body() body: UpdateUserDto,
  ): Promise<ApiResponse<UserDto, UserMessage>> {
    // Duck Gen extracts:
    // - Method: PUT
    // - Path: /api/users/:id
    // - Params: { id: string }
    // - Body: UpdateUserDto
    // - Response: ApiResponse<UserDto, UserMessage>
    return {} as any
  }

  @Delete(':id')
  remove(@Param('id') id: string): Promise<ApiResponse<null, UserMessage>> {
    // Duck Gen extracts:
    // - Method: DELETE
    // - Path: /api/users/:id
    // - Params: { id: string }
    // - Response: ApiResponse<null, UserMessage>
    return {} as any
  }
}
```

## Register the controller

Add the controller to a module and import it in your app:

```ts title="src/users/users.module.ts"
import { Module } from '@nestjs/common'
import { UsersController } from './users.controller'

@Module({
  controllers: [UsersController],
})
export class UsersModule {}
```

```ts title="src/app.module.ts"
import { Module } from '@nestjs/common'
import { UsersModule } from './users/users.module'

@Module({
  imports: [UsersModule],
})
export class AppModule {}
```

## What Duck Gen sees

When you run `duck-gen`, it finds `UsersController` and extracts five routes:

| Method | Path | Body | Query | Params | Response |
| --- | --- | --- | --- | --- | --- |
| GET | /api/users | - | PaginationDto | - | ApiResponse\<UserDto\[], UserMessage> |
| GET | /api/users/:id | - | - | `{ id: string }` | ApiResponse\<UserDto, UserMessage> |
| POST | /api/users | CreateUserDto | - | - | ApiResponse\<UserDto, UserMessage> |
| PUT | /api/users/:id | UpdateUserDto | - | `{ id: string }` | ApiResponse\<UserDto, UserMessage> |
| DELETE | /api/users/:id | - | - | `{ id: string }` | ApiResponse\<null, UserMessage> |

Each route becomes an entry in the generated route map with fully resolved types.

## Key rules for Duck Gen scanning

1. **Use string literals in decorators.** `@Controller('users')` works. `@Controller(ROUTE_VAR)` does not, because Duck Gen cannot resolve runtime values.

2. **Add explicit return types.** If a method has no return type annotation, Duck Gen infers `any` and warns you. Always annotate your return types.

3. **Use standard NestJS parameter decorators.** `@Body()`, `@Query()`, `@Param()`, and `@Headers()` are all supported.

## Next

[Chapter 4: Generating Types](/duck-gen/course/generating-types)