Lesson 2: Wire the API & FlowEngine
Flow plumbing
medical-appointment-bot/src/flow.module.ts keeps the runtime tiny:
@Module({
imports: [ConfigModule.forRoot()],
providers: [FlowEngine],
exports: [FlowEngine, ConfigModule],
})
export class FlowModule {}
FlowEngine is the single dependency you pass around; it already knows how to load sessions, bind tools, and persist step state.
App module + controllers
src/app.module.ts imports FlowModule and exposes only two controllers:
@Module({
imports: [FlowModule, ConfigModule],
controllers: [ChatController, HealthController],
})
export class AppModule {}
HealthControlleranswers/healthcheckfor probes.ChatControlleris the entry point for every chat turn.
Chat endpoints
src/controllers/chat-controller.ts shows the minimal integration surface:
@ApiTags('ai')
@Controller('ai')
export class ChatController {
constructor(private flowEngine: FlowEngine) {
flowEngine.registerFlows({ MedicalFlow });
flowEngine.registerModel(ChatGoogleGenerativeAI, {
model: 'gemini-2.5-pro',
temperature: CoreConfig.llmTemperature,
apiKey: CoreConfig.GeminiKey,
maxRetries: CoreConfig.llmRetry,
});
}
@Post('run')
async run(@Res() res: FastifyReply,
@Body(K.message) userMessage: string,
@Body(K.flowName) flowName: string,
@Body('config') config: object,
@Headers(K.ChatSessionID) sessionId = '') {
await this.flowEngine.run(res, flowName, userMessage, sessionId, config);
}
@Post('end')
async endChat(@Res() res: FastifyReply,
@Headers(K.ChatSessionID) sessionId = '') {
const result = await this.flowEngine.endChat(sessionId);
if (!result.success) res.status(HttpStatus.BAD_REQUEST);
res.send(result);
}
}
Key points:
- Flow + model registration happens once in the constructor.
/ai/runis the only turn-by-turn endpoint;/ai/endcloses sessions.- The engine handles retries, tool dispatch, and state writes under the hood.
main.ts
src/main.ts wires Fastify and Swagger:
const app = await NestFactory.create<NestFastifyApplication>(AppModule, new FastifyAdapter());
app.useStaticAssets({ root: join(__dirname, '..', 'public'), prefix: '/public/' });
const config = new DocumentBuilder().setTitle('Chat Flow API').setDescription('API documentation for Chat Flow').setVersion('1.0').build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
await app.listen(8000, '0.0.0.0');
Nothing else is needed to run the bot: register the flow, expose the endpoints, and start Fastify.