Quellcode durchsuchen

define the controller and service for the airport management

Sven Czarnian vor 2 Jahren
Ursprung
Commit
a21eddda93

+ 18 - 0
src/airport/airport.controller.spec.ts

@@ -0,0 +1,18 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { AirportController } from './airport.controller';
+
+describe('AirportController', () => {
+  let controller: AirportController;
+
+  beforeEach(async () => {
+    const module: TestingModule = await Test.createTestingModule({
+      controllers: [AirportController],
+    }).compile();
+
+    controller = module.get<AirportController>(AirportController);
+  });
+
+  it('should be defined', () => {
+    expect(controller).toBeDefined();
+  });
+});

+ 237 - 0
src/airport/airport.controller.ts

@@ -0,0 +1,237 @@
+import {
+  Body,
+  Controller,
+  Get,
+  Delete,
+  Post,
+  Query,
+  HttpException,
+  HttpStatus,
+} from '@nestjs/common';
+import { ApiBody, ApiQuery, ApiResponse } from '@nestjs/swagger';
+import { AirportService } from './airport.service';
+import { Airport } from './models/airport.model';
+import { AirportDto } from './dto/airport.dto';
+import { ArrivalRouteDto } from './dto/arrivalroute.dto';
+import { AssignmentDto } from './dto/assignment.dto';
+import { ConstraintDto } from './dto/constraint.dto';
+import { PlanningDto } from './dto/planning.dto';
+import { RunwaySpacingDto } from './dto/runwayspacing.dto';
+import { ArrivalRoute } from './models/arrivalroute.model';
+import { Assignment } from './models/assignment.model';
+import { Constraint } from './models/constraint.model';
+import { Planning } from './models/planning.model';
+import { RunwaySpacing } from './models/runwayspacing.model';
+
+@Controller('airport')
+export class AirportController {
+  constructor(private readonly airportService: AirportService) {}
+
+  private static convertConstraint<T>(
+    constraint: Constraint | ConstraintDto,
+  ): T {
+    return {
+      waypoint: constraint.waypoint,
+      altitude: {
+        constraint: constraint.altitude.constraint,
+        mode: constraint.altitude.mode,
+      },
+      speed: {
+        constraint: constraint.speed.constraint,
+        mode: constraint.speed.mode,
+      },
+    } as T;
+  }
+
+  private static convertConstraints<T>(
+    constraints: Constraint[] | ConstraintDto[],
+  ): T[] {
+    const retval: T[] = [];
+    constraints.forEach((constraint) =>
+      retval.push(AirportController.convertConstraint<T>(constraint)),
+    );
+    return retval;
+  }
+
+  private static convertArrivalRoutes<T, U>(
+    routes: ArrivalRoute[] | ArrivalRouteDto[],
+  ): T[] {
+    const retval: T[] = [];
+    routes.forEach((route) =>
+      retval.push({
+        arrival: route.runway,
+        runway: route.runway,
+        constraints: AirportController.convertConstraints<U>(route.constraints),
+      } as T),
+    );
+    return retval;
+  }
+
+  private static convertRunwaySpacings<T>(
+    spacings: RunwaySpacing[] | RunwaySpacingDto[],
+  ): T[] {
+    const retval: T[] = [];
+    spacings.forEach((spacing) =>
+      retval.push({
+        runway: spacing.runway,
+        spacing: spacing.spacing,
+      } as T),
+    );
+    return retval;
+  }
+
+  private static convertAssignments<T>(
+    assignments: Assignment[] | AssignmentDto[],
+  ): T[] {
+    const retval: T[] = [];
+    assignments.forEach((assignment) =>
+      retval.push({
+        runway: assignment.runway,
+        type: assignment.type,
+        aircrafts: assignment.aircrafts,
+        assignedStands: assignment.assignedStands,
+      } as T),
+    );
+    return retval;
+  }
+
+  private static convertPlanning<T, U>(planning: Planning | PlanningDto): T {
+    return {
+      optimization: {
+        windowSize: planning.optimization.windowSize,
+        windowOverlap: planning.optimization.windowOverlap,
+        fixedBeforeInitialApproachFix:
+          planning.optimization.fixedBeforeInitialApproachFix,
+        maximumAirportDistance: planning.optimization.maximumAirportDistance,
+      },
+      assignments: AirportController.convertAssignments<U>(
+        planning.assignments,
+      ),
+    } as T;
+  }
+
+  private static airportToAirportDto(airport: Airport): AirportDto {
+    if (!airport) return null;
+
+    return {
+      icao: airport.icao,
+      upperConstraints: AirportController.convertConstraints<ConstraintDto>(
+        airport.upperConstraints,
+      ),
+      arrivalRoutes: AirportController.convertArrivalRoutes<
+        ArrivalRouteDto,
+        ConstraintDto
+      >(airport.arrivalRoutes),
+      spacings: AirportController.convertRunwaySpacings<RunwaySpacingDto>(
+        airport.spacings,
+      ),
+      planning: AirportController.convertPlanning<PlanningDto, AssignmentDto>(
+        airport.planning,
+      ),
+    };
+  }
+
+  private static airportDtoToAirport(airport: AirportDto): Airport {
+    if (!airport) return null;
+
+    return {
+      icao: airport.icao,
+      upperConstraints: AirportController.convertConstraints<Constraint>(
+        airport.upperConstraints,
+      ),
+      arrivalRoutes: AirportController.convertArrivalRoutes<
+        ArrivalRoute,
+        Constraint
+      >(airport.arrivalRoutes),
+      spacings: AirportController.convertRunwaySpacings<RunwaySpacing>(
+        airport.spacings,
+      ),
+      planning: AirportController.convertPlanning<Planning, Assignment>(
+        airport.planning,
+      ),
+    };
+  }
+
+  @Get('/allCodes')
+  @ApiResponse({
+    status: 200,
+    description: 'All available airports',
+    type: [String],
+  })
+  async allCodes(): Promise<string[]> {
+    return this.airportService.airportsList();
+  }
+
+  @Get('/get')
+  @ApiQuery({
+    name: 'icao',
+    description: 'The ICAO code of the airport',
+    type: String,
+  })
+  @ApiResponse({
+    status: 200,
+    description: 'The airport configuration',
+    type: [AirportDto],
+  })
+  @ApiResponse({
+    status: 404,
+    description: 'No airport found',
+  })
+  async get(@Query('icao') icao: string): Promise<AirportDto> {
+    return this.airportService.airport(icao).then((airport) => {
+      if (!airport) {
+        throw new HttpException('Airport not found', HttpStatus.NOT_FOUND);
+      }
+      return AirportController.airportToAirportDto(airport);
+    });
+  }
+
+  @Post('/register')
+  @ApiBody({
+    description: 'The airport definition',
+    type: AirportDto,
+  })
+  @ApiResponse({
+    status: 201,
+    description: 'The airport is registered',
+  })
+  @ApiResponse({
+    status: 409,
+    description: 'The airport is already registered',
+  })
+  async register(@Body('airport') airport: AirportDto): Promise<void> {
+    await this.airportService
+      .registerAirport(AirportController.airportDtoToAirport(airport))
+      .then((registered) => {
+        if (!registered) {
+          throw new HttpException(
+            'Airport already available',
+            HttpStatus.CONFLICT,
+          );
+        }
+      });
+  }
+
+  @Delete('/remove')
+  @ApiQuery({
+    name: 'icao',
+    description: 'The ICAO code of the airport',
+    type: String,
+  })
+  @ApiResponse({
+    status: 200,
+    description: 'All log entries are deleted',
+  })
+  @ApiResponse({
+    status: 404,
+    description: 'Could not find the airport',
+  })
+  async remove(@Query('icao') icao: string): Promise<void> {
+    await this.airportService.airport(icao).then(async (airport) => {
+      if (!airport) {
+        throw new HttpException('Airport not found', HttpStatus.NOT_FOUND);
+      }
+      await this.airportService.deleteAirport(icao);
+    });
+  }
+}

+ 15 - 0
src/airport/airport.module.ts

@@ -0,0 +1,15 @@
+import { Module } from '@nestjs/common';
+import { MongooseModule } from '@nestjs/mongoose';
+import { AirportSchema } from './models/airport.model';
+import { AirportService } from './airport.service';
+import { AirportController } from './airport.controller';
+
+@Module({
+  imports: [
+    MongooseModule.forFeature([{ name: 'airport', schema: AirportSchema }]),
+  ],
+  providers: [AirportService],
+  controllers: [AirportController],
+  exports: [AirportService],
+})
+export class AirportModule {}

+ 18 - 0
src/airport/airport.service.spec.ts

@@ -0,0 +1,18 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { AirportService } from './airport.service';
+
+describe('AirportService', () => {
+  let service: AirportService;
+
+  beforeEach(async () => {
+    const module: TestingModule = await Test.createTestingModule({
+      providers: [AirportService],
+    }).compile();
+
+    service = module.get<AirportService>(AirportService);
+  });
+
+  it('should be defined', () => {
+    expect(service).toBeDefined();
+  });
+});

+ 64 - 0
src/airport/airport.service.ts

@@ -0,0 +1,64 @@
+import { Injectable } from '@nestjs/common';
+import { InjectModel } from '@nestjs/mongoose';
+import { Model } from 'mongoose';
+import { Airport, AirportDocument } from './models/airport.model';
+
+@Injectable()
+export class AirportService {
+  constructor(
+    @InjectModel('airport')
+    private readonly airportModel: Model<AirportDocument>,
+  ) {}
+
+  private async airportExists(icao: string): Promise<boolean> {
+    return this.airportModel
+      .find({ icao })
+      .then((response) => response && response.length !== 0);
+  }
+
+  async airportsList(): Promise<string[]> {
+    return this.airportModel.find({}).then((response) => {
+      const icaoCodes: string[] = [];
+      response.forEach((airport) => icaoCodes.push(airport.icao));
+      return icaoCodes;
+    });
+  }
+
+  async airport(icao: string): Promise<Airport> {
+    return this.airportModel.find({ icao }).then((response) => {
+      if (!response || response.length !== 1) return null;
+      return response[0];
+    });
+  }
+
+  async registerAirport(airport: Airport): Promise<boolean> {
+    this.airportExists(airport.icao).then(async (exists) => {
+      if (!exists) {
+        await this.airportModel.create(airport);
+      }
+
+      return !exists;
+    });
+
+    return false;
+  }
+
+  async updateAirport(airport: Airport): Promise<boolean> {
+    this.airportExists(airport.icao).then(async (exists) => {
+      if (exists) {
+        await this.airportModel.findOneAndUpdate(
+          { icao: airport.icao },
+          airport,
+        );
+      }
+
+      return exists;
+    });
+
+    return false;
+  }
+
+  async deleteAirport(icao: string): Promise<void> {
+    this.airportModel.deleteOne({ icao });
+  }
+}

+ 39 - 0
src/airport/dto/airport.dto.ts

@@ -0,0 +1,39 @@
+import { IsNotEmpty, IsOptional } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
+import { ConstraintDto } from './constraint.dto';
+import { ArrivalRouteDto } from './arrivalroute.dto';
+import { RunwaySpacingDto } from './runwayspacing.dto';
+import { PlanningDto } from './planning.dto';
+
+export class AirportDto {
+  @IsNotEmpty()
+  @ApiProperty({
+    description: 'The unique ICAO code',
+    example: 'EDDB',
+  })
+  icao: string;
+
+  @IsOptional()
+  @ApiProperty({
+    description: 'The constraints in upper airspaces',
+  })
+  upperConstraints: ConstraintDto[];
+
+  @IsNotEmpty()
+  @ApiProperty({
+    description: 'The different arrival routes with potential constraints',
+  })
+  arrivalRoutes: ArrivalRouteDto[];
+
+  @IsNotEmpty()
+  @ApiProperty({
+    description: 'The spacings for the runways',
+  })
+  spacings: RunwaySpacingDto[];
+
+  @IsNotEmpty()
+  @ApiProperty({
+    description: 'The planning configuration',
+  })
+  planning: PlanningDto;
+}

+ 25 - 0
src/airport/dto/arrivalroute.dto.ts

@@ -0,0 +1,25 @@
+import { IsNotEmpty, IsOptional } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
+import { ConstraintDto } from './constraint.dto';
+
+export class ArrivalRouteDto {
+  @IsNotEmpty()
+  @ApiProperty({
+    description: 'The arrival route identifier',
+    example: 'KLF25L',
+  })
+  arrival: string;
+
+  @IsNotEmpty()
+  @ApiProperty({
+    description: 'The runway of the arrival route',
+    example: '25L',
+  })
+  runway: string;
+
+  @IsOptional()
+  @ApiProperty({
+    description: 'The constraints on the arrival route',
+  })
+  constraints: ConstraintDto[];
+}

+ 32 - 0
src/airport/dto/assignment.dto.ts

@@ -0,0 +1,32 @@
+import { IsNotEmpty, IsOptional } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
+
+export class AssignmentDto {
+  @IsNotEmpty()
+  @ApiProperty({
+    description: 'The runway identifier',
+    example: '25L',
+  })
+  runway: string;
+
+  @IsNotEmpty()
+  @ApiProperty({
+    description: 'The urgency of the assignment (possible: SHALL, SHOULD, MAY)',
+    example: 'MAY',
+  })
+  type: string;
+
+  @IsOptional()
+  @ApiProperty({
+    description: 'The aircrafts (ICAO codes) that require this assignment',
+    example: '[ "A346", "B748" ]',
+  })
+  aircrafts: string[];
+
+  @IsOptional()
+  @ApiProperty({
+    description: 'The assigned stands that require this assignment',
+    example: '[ "A01", "A02" ]',
+  })
+  assignedStands: string[];
+}

+ 26 - 0
src/airport/dto/constraint.dto.ts

@@ -0,0 +1,26 @@
+import { IsNotEmpty, IsOptional } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
+import { ConstraintTypeDto } from './constrainttype.dto';
+
+export class ConstraintDto {
+  @IsNotEmpty()
+  @ApiProperty({
+    description: 'The identifier of the waypoint',
+    example: 'AKUDI',
+  })
+  waypoint: string;
+
+  @IsOptional()
+  @ApiProperty({
+    description: 'The altitude constraint in feet',
+    example: '{ constraint: 20000, mode: "BELOW" }',
+  })
+  altitude: ConstraintTypeDto;
+
+  @IsOptional()
+  @ApiProperty({
+    description: 'The speed constraint in knots',
+    example: '{ constraint: 250, mode: "EXACT" }',
+  })
+  speed: ConstraintTypeDto;
+}

+ 18 - 0
src/airport/dto/constrainttype.dto.ts

@@ -0,0 +1,18 @@
+import { IsNotEmpty } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
+
+export class ConstraintTypeDto {
+  @IsNotEmpty()
+  @ApiProperty({
+    description: 'The identifier of the waypoint',
+    example: 20000,
+  })
+  constraint: number;
+
+  @IsNotEmpty()
+  @ApiProperty({
+    description: 'The constraint mode (possible: BELOW, EXACT, ABOVE)',
+    example: 'EXACT',
+  })
+  mode: string;
+}

+ 34 - 0
src/airport/dto/optimization.dto.ts

@@ -0,0 +1,34 @@
+import { IsNotEmpty } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
+
+export class OptimizationDto {
+  @IsNotEmpty()
+  @ApiProperty({
+    description: 'The window length in seconds',
+    example: 120,
+  })
+  windowSize: number;
+
+  @IsNotEmpty()
+  @ApiProperty({
+    description: 'The optimized windows for the sequence',
+    example: 3,
+  })
+  windowOverlap: number;
+
+  @IsNotEmpty()
+  @ApiProperty({
+    description:
+      'The final approach sequence before the IAF is reached in minutes',
+    example: 10,
+  })
+  fixedBeforeInitialApproachFix: number;
+
+  @IsNotEmpty()
+  @ApiProperty({
+    description:
+      'The maximum distance to the airport before the optimization is started',
+    example: 300,
+  })
+  maximumAirportDistance: number;
+}

+ 18 - 0
src/airport/dto/planning.dto.ts

@@ -0,0 +1,18 @@
+import { IsNotEmpty } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
+import { OptimizationDto } from './optimization.dto';
+import { AssignmentDto } from './assignment.dto';
+
+export class PlanningDto {
+  @IsNotEmpty()
+  @ApiProperty({
+    description: 'The optimization parameters',
+  })
+  optimization: OptimizationDto;
+
+  @IsNotEmpty()
+  @ApiProperty({
+    description: 'The runway assignments',
+  })
+  assignments: AssignmentDto[];
+}

+ 18 - 0
src/airport/dto/runwayspacing.dto.ts

@@ -0,0 +1,18 @@
+import { IsNotEmpty, IsOptional } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
+
+export class RunwaySpacingDto {
+  @IsNotEmpty()
+  @ApiProperty({
+    description: 'The runway identifier',
+    example: '25L',
+  })
+  runway: string;
+
+  @IsOptional()
+  @ApiProperty({
+    description: 'The touch-down sequence in nautical miles',
+    example: 4,
+  })
+  spacing: number;
+}

+ 42 - 0
src/airport/models/airport.model.ts

@@ -0,0 +1,42 @@
+import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
+import { Document } from 'mongoose';
+import { ArrivalRoute, ArrivalRouteSchema } from './arrivalroute.model';
+import { Constraint, ConstraintSchema } from './constraint.model';
+import { Planning, PlanningSchema } from './planning.model';
+import { RunwaySpacing, RunwaySpacingSchema } from './runwayspacing.model';
+
+export type AirportDocument = Airport & Document;
+
+@Schema()
+export class Airport {
+  @Prop({
+    required: true,
+    type: String,
+  })
+  icao: string;
+
+  @Prop({
+    type: [ConstraintSchema],
+  })
+  upperConstraints: Constraint[];
+
+  @Prop({
+    required: true,
+    type: [ArrivalRouteSchema],
+  })
+  arrivalRoutes: ArrivalRoute[];
+
+  @Prop({
+    required: true,
+    type: [RunwaySpacingSchema],
+  })
+  spacings: RunwaySpacing[];
+
+  @Prop({
+    required: true,
+    type: PlanningSchema,
+  })
+  planning: Planning;
+}
+
+export const AirportSchema = SchemaFactory.createForClass(Airport);

+ 27 - 0
src/airport/models/arrivalroute.model.ts

@@ -0,0 +1,27 @@
+import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
+import { Document } from 'mongoose';
+import { Constraint, ConstraintSchema } from './constraint.model';
+
+export type ArrivalRouteDocument = ArrivalRoute & Document;
+
+@Schema()
+export class ArrivalRoute {
+  @Prop({
+    required: true,
+    type: String,
+  })
+  arrival: string;
+
+  @Prop({
+    required: true,
+    type: String,
+  })
+  runway: string;
+
+  @Prop({
+    type: [ConstraintSchema],
+  })
+  constraints: Constraint[];
+}
+
+export const ArrivalRouteSchema = SchemaFactory.createForClass(ArrivalRoute);

+ 32 - 0
src/airport/models/assignment.model.ts

@@ -0,0 +1,32 @@
+import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
+import { Document } from 'mongoose';
+
+export type AssignmentDocument = Assignment & Document;
+
+@Schema()
+export class Assignment {
+  @Prop({
+    required: true,
+    type: String,
+  })
+  runway: string;
+
+  @Prop({
+    required: true,
+    type: String,
+    enum: ['SHALL', 'SHOULD', 'MAY'],
+  })
+  type: string;
+
+  @Prop({
+    type: [String],
+  })
+  aircrafts: string[];
+
+  @Prop({
+    type: [String],
+  })
+  assignedStands: string[];
+}
+
+export const AssignmentSchema = SchemaFactory.createForClass(Assignment);

+ 26 - 0
src/airport/models/constraint.model.ts

@@ -0,0 +1,26 @@
+import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
+import { Document } from 'mongoose';
+import { ConstraintType, ConstraintTypeSchema } from './constrainttype.model';
+
+export type ConstraintDocument = Constraint & Document;
+
+@Schema()
+export class Constraint {
+  @Prop({
+    required: true,
+    type: String,
+  })
+  waypoint: string;
+
+  @Prop({
+    type: ConstraintTypeSchema,
+  })
+  altitude: ConstraintType;
+
+  @Prop({
+    type: ConstraintTypeSchema,
+  })
+  speed: ConstraintType;
+}
+
+export const ConstraintSchema = SchemaFactory.createForClass(Constraint);

+ 22 - 0
src/airport/models/constrainttype.model.ts

@@ -0,0 +1,22 @@
+import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
+import { Document } from 'mongoose';
+
+export type ConstraintTypeDocument = ConstraintType & Document;
+
+@Schema()
+export class ConstraintType {
+  @Prop({
+    type: Number,
+  })
+  constraint: number;
+
+  @Prop({
+    type: String,
+    default: 'EXACT',
+    enum: ['BELOW', 'EXACT', 'ABOVE'],
+  })
+  mode: string;
+}
+
+export const ConstraintTypeSchema =
+  SchemaFactory.createForClass(ConstraintType);

+ 37 - 0
src/airport/models/optimization.model.ts

@@ -0,0 +1,37 @@
+import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
+import { Document } from 'mongoose';
+
+export type OptimizationDocument = Optimization & Document;
+
+@Schema()
+export class Optimization {
+  @Prop({
+    required: true,
+    type: Number,
+    default: 120,
+  })
+  windowSize: number;
+
+  @Prop({
+    required: true,
+    type: Number,
+    default: 3,
+  })
+  windowOverlap: number;
+
+  @Prop({
+    required: true,
+    type: Number,
+    default: 10,
+  })
+  fixedBeforeInitialApproachFix: number;
+
+  @Prop({
+    required: true,
+    type: Number,
+    default: 300,
+  })
+  maximumAirportDistance: number;
+}
+
+export const OptimizationSchema = SchemaFactory.createForClass(Optimization);

+ 23 - 0
src/airport/models/planning.model.ts

@@ -0,0 +1,23 @@
+import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
+import { Document } from 'mongoose';
+import { Assignment, AssignmentSchema } from './assignment.model';
+import { Optimization, OptimizationSchema } from './optimization.model';
+
+export type PlanningDocument = Planning & Document;
+
+@Schema()
+export class Planning {
+  @Prop({
+    required: true,
+    type: OptimizationSchema,
+  })
+  optimization: Optimization;
+
+  @Prop({
+    required: true,
+    type: [AssignmentSchema],
+  })
+  assignments: Assignment[];
+}
+
+export const PlanningSchema = SchemaFactory.createForClass(Planning);

+ 21 - 0
src/airport/models/runwayspacing.model.ts

@@ -0,0 +1,21 @@
+import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
+import { Document } from 'mongoose';
+
+export type RunwaySpacingDocument = RunwaySpacing & Document;
+
+@Schema()
+export class RunwaySpacing {
+  @Prop({
+    required: true,
+    type: String,
+  })
+  runway: string;
+
+  @Prop({
+    required: true,
+    type: Number,
+  })
+  spacing: number;
+}
+
+export const RunwaySpacingSchema = SchemaFactory.createForClass(RunwaySpacing);

+ 4 - 1
src/app.module.ts

@@ -4,8 +4,10 @@ import { MongooseModule } from '@nestjs/mongoose';
 import Configuration from './config/configuration';
 import { VersioningModule } from './versioning/versioning.module';
 import { PerformanceModule } from './performance/performance.module';
+import { AirportModule } from './airport/airport.module';
 import { LoggingModule } from './logging/logging.module';
 import { LoggingController } from './logging/logging.controller';
+import { AirportController } from './airport/airport.controller';
 
 @Module({
   imports: [
@@ -26,8 +28,9 @@ import { LoggingController } from './logging/logging.controller';
     }),
     VersioningModule,
     PerformanceModule,
+    AirportModule,
     LoggingModule,
   ],
-  controllers: [LoggingController],
+  controllers: [LoggingController, AirportController],
 })
 export class AppModule {}