Ave, young legionary! Consul Caesar.js is reaching out to you again. Now that you've learned the basics of our NestJS forum, it's time to learn how to navigate the digital provinces of the empire - that is, routing and handling various HTTP methods.
In a Roman legion, every soldier has their task and position. Similarly in NestJS, every endpoint has its role and path. Routing is our map of Roman roads - it tells us exactly where to find what we're looking for.
Routing in NestJS is a system that determines how the application responds to different client requests to specific endpoints. Each endpoint is defined by a URL path and a specific HTTP method (GET, POST, PUT, DELETE).
Just as in the Roman Empire we have different sections - the forum, the senate, the tribute warehouses - so in an application we have different paths leading to different functionalities.
1import { Controller, Get, Post, Put, Delete, Param, Body } from '@nestjs/common';
2
3@Controller('tributes')
4export class TributesController {
5 // GET - retrieving data (like checking the treasury contents)
6 @Get()
7 getAllTributes() {
8 return {
9 message: 'Here are all the tributes in the empire treasury!',
10 tributes: ['Gold coins', 'Gemstones', 'Sapphires']
11 };
12 }
13
14 // GET with parameter - retrieving a specific tribute
15 @Get(':id')
16 getTributeById(@Param('id') id: string) {
17 return {
18 message: `Found tribute with ID: ${id}`,
19 tribute: 'Golden medallion'
20 };
21 }
22
23 // POST - creating new data (adding tributes)
24 @Post()
25 addTribute(@Body() tributeData: any) {
26 return {
27 message: 'New tribute added to the treasury!',
28 tribute: tributeData
29 };
30 }
31
32 // PUT - updating data (replacing a tribute)
33 @Put(':id')
34 updateTribute(@Param('id') id: string, @Body() tributeData: any) {
35 return {
36 message: `Tribute ${id} has been updated`,
37 tribute: tributeData
38 };
39 }
40
41 // DELETE - removing data (transferring a tribute to another province)
42 @Delete(':id')
43 removeTribute(@Param('id') id: string) {
44 return {
45 message: `Tribute ${id} has been removed from the treasury`
46 };
47 }
48}NestJS uses decorators to define routes. Each HTTP decorator corresponds to a specific method:
Used when we want to fetch information, like checking the legion status:
1@Get('legion')
2getLegionStatus() {
3 return {
4 consul: 'Caesar.js',
5 centurion: 'Marcus Aurelius',
6 legionaries: 120,
7 status: 'Ready to march!'
8 };
9}Used when adding new legionaries:
1@Post('legion')
2addLegionary(@Body() newLegionary: any) {
3 return {
4 message: 'A new legionary has joined the legion!',
5 legionary: newLegionary
6 };
7}Used when completely changing information about a legionary:
1@Put('legion/:id')
2updateLegionary(@Param('id') id: string, @Body() legionaryData: any) {
3 return {
4 message: `Legionary ${id} has received new duties`,
5 updatedLegionary: legionaryData
6 };
7}Used when changing only part of the information:
1@Patch('legion/:id')
2updateLegionaryPartially(@Param('id') id: string, @Body() partialData: any) {
3 return {
4 message: `Partially updated legionary ${id} data`,
5 changes: partialData
6 };
7}Used when a legionary leaves the legion:
1@Delete('legion/:id')
2removeLegionary(@Param('id') id: string) {
3 return {
4 message: `Legionary ${id} has left the legion. Ave atque vale!`
5 };
6}In the Roman forum, every resource has its unique identifier. In NestJS, we use URL parameters to identify specific resources:
1@Controller('forum')
2export class ForumController {
3 // Path parameter
4 @Get('level/:floor')
5 getFloorInfo(@Param('floor') floor: string) {
6 return {
7 floor: floor,
8 description: this.getFloorDescription(floor)
9 };
10 }
11
12 // Multiple parameters
13 @Get('chamber/:floor/:number')
14 getChamberInfo(
15 @Param('floor') floor: string,
16 @Param('number') number: string
17 ) {
18 return {
19 location: `Level ${floor}, chamber ${number}`,
20 occupant: 'Available'
21 };
22 }
23
24 // Query parameters
25 @Get('search')
26 searchItems(@Query('type') type: string, @Query('value') value: string) {
27 return {
28 message: `Searching for ${type} worth ${value} aureus`,
29 results: []
30 };
31 }
32
33 private getFloorDescription(floor: string): string {
34 const descriptions = {
35 'upper': 'Upper level - the consul rules here',
36 'main': 'Main level - the center of forum life',
37 'lower': 'Lower level - warehouses and treasury'
38 };
39 return descriptions[floor] || 'Unknown level';
40 }
41}When provinces deliver new tributes to the empire, we need to check their quality and value. In NestJS, we use DTOs to validate data:
1// dto/tribute.dto.ts
2export class CreateTributeDto {
3 readonly name: string;
4 readonly type: string;
5 readonly value: number;
6 readonly description?: string;
7}
8
9@Controller('inventory')
10export class InventoryController {
11 @Post('add')
12 addToInventory(@Body() tributeDto: CreateTributeDto) {
13 // Validation was performed automatically
14 return {
15 message: 'Tribute added to the inventory!',
16 tribute: tributeDto,
17 addedAt: new Date().toISOString()
18 };
19 }
20}Sometimes legions send secret messages in dispatch headers. In NestJS, we can read and set HTTP headers:
1import { Headers, Res } from '@nestjs/common';
2import { Response } from 'express';
3
4@Controller('messages')
5export class MessageController {
6 @Get('secret')
7 getSecretMessage(@Headers('legion-token') token: string) {
8 if (token !== 'ave-caesar') {
9 return { error: 'Invalid legionary token!' };
10 }
11
12 return {
13 message: 'The tribute is hidden under the great oak in the province!'
14 };
15 }
16
17 @Post('send')
18 sendMessage(@Body() messageData: any, @Res() res: Response) {
19 // Setting custom header
20 res.setHeader('X-Legion-Response', 'message-sent');
21 res.setHeader('X-Legion-Name', 'Legio X Equestris');
22
23 return res.json({
24 message: 'Message sent!',
25 timestamp: new Date().toISOString()
26 });
27 }
28}Every HTTP response has its status code, like flag signals in the Roman Empire:
1import { HttpStatus, HttpCode } from '@nestjs/common';
2
3@Controller('operations')
4export class OperationController {
5 @Post('campaign')
6 @HttpCode(HttpStatus.ACCEPTED) // 202
7 launchCampaign(@Body() target: any) {
8 return {
9 message: 'Campaign launched!',
10 target: target.name,
11 status: 'in-progress'
12 };
13 }
14
15 @Get('tribute/:id')
16 findTribute(@Param('id') id: string) {
17 if (id === '404') {
18 throw new NotFoundException('Tribute was not found!');
19 }
20
21 return {
22 tribute: `Tribute ${id}`,
23 location: 'Forum treasury'
24 };
25 }
26}Sometimes we need flexible routes, like roads through various provinces:
1@Controller('navigation')
2export class NavigationController {
3 // Wildcard route - matches everything
4 @Get('province/*')
5 exploreProvince(@Param('0') path: string) {
6 return {
7 message: `Exploring province: ${path}`,
8 challenges: ['Local tribes', 'Difficult terrain', 'Unstable weather']
9 };
10 }
11
12 // Route patterns
13 @Get('coordinates/:lat-:lng')
14 getLocationInfo(@Param('lat') lat: string, @Param('lng') lng: string) {
15 return {
16 coordinates: { latitude: lat, longitude: lng },
17 description: 'Position on the empire map'
18 };
19 }
20}In the great forum, we organize everything into sections. In NestJS, we can group routes using prefixes:
1@Controller('api/v1/legion')
2export class LegionManagementController {
3 @Get('status')
4 getLegionStatus() {
5 return {
6 name: 'Legio X Equestris',
7 legionaries: 5000,
8 ballistae: 20,
9 speed: '25 km/day'
10 };
11 }
12
13 @Get('supplies')
14 getSupplies() {
15 return {
16 food: '30 days',
17 water: '25 days',
18 weapons: '5000 units',
19 wine: '1000 amphorae' // Important for morale!
20 };
21 }
22}