Skip to content

Controllers

In OzeanJs, a Controller’s main responsibility is to receive incoming HTTP requests from the client, process them, and send back an HTTP response. A Controller acts as the “front line” that connects the outside world to your application’s business logic.

The structure of a Controller is designed to be clear and modular, using Decorators to define routing and handle data.

We create a Controller by creating a TypeScript class and attaching the @Controller() decorator.

  • @Controller('/prefix'): This decorator defines a “base path” or URL prefix for all routes defined within this class. For example, if you define @Controller('/users'), all routes in this controller will start with /users.

Inside a Controller, we create various methods that act as “Route Handlers”. They are bound to specific HTTP Methods and sub-paths using Decorators:

  • @Get('/path'): For handling GET requests.
  • @Post('/path'): For handling POST requests.
  • @Put('/path'): For handling PUT requests.
  • @Delete('/path'): For handling DELETE requests.
  • @Patch('/path'): For handling PATCH requests.

Accessing Request Data (Parameter Decorators)

Section titled “Accessing Request Data (Parameter Decorators)”

OzeanJs provides Parameter Decorators that help you easily extract data from various parts of the request into your handler methods:

  • @Param('key'): Extracts a value from the URL parameter (e.g., from the route /users/:id).
  • @Query('key'): Extracts a value from the URL’s query string (e.g., from /users?role=admin).
  • @Body(): Extracts the entire request body (typically used with POST, PUT, PATCH).

Here is a complete example of a UsersController that demonstrates all these concepts working together.

src/users/users.service.ts
import { Injectable } from 'ozean';
// Assume we have a UsersService that handles user-related logic
@Injectable()
export class UsersService {
private users = [{ id: 1, name: 'John Doe' }];
findAll() {
return this.users;
}
findOne(id: number) {
return this.users.find((user) => user.id === id);
}
create(userData: { name: string }) {
const newUser = { id: this.users.length + 1, ...userData };
this.users.push(newUser);
return newUser;
}
}
// src/users/users.controller.ts
import { Controller, Get, Post, Param, Body } from 'ozean';
import { UsersService } from './users.service';
@Controller('/users') // All routes in here will be prefixed with /users
export class UsersController {
constructor(private readonly usersService: UsersService) {}
// Handles GET requests to /users
@Get()
getAllUsers() {
return this.usersService.findAll();
}
// Handles GET requests to /users/:id (e.g., /users/1)
@Get('/:id')
getUserById(@Param('id') id: string) {
const user = this.usersService.findOne(parseInt(id, 10));
if (!user) {
// You can return a Response object directly to set a custom status code
return new Response('User not found', { status: 404 });
}
return user; // Will be automatically converted to a JSON response
}
// Handles POST requests to /users
@Post()
createUser(@Body() userData: { name: string }) {
return this.usersService.create(userData);
}
}

Finally, don’t forget to register the UsersController you created in the controllers array of the relevant module (e.g., UsersModule) so that OzeanJs recognizes it and creates the routes automatically.

src/users/users.module.ts
import { Module } from 'ozean';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}

With this structure, the logic for handling HTTP requests is clearly separated within the Controller, making your code cleaner and easier to maintain.