Lesson 6: Integrating the OpenAI API with Express
Goal
Integrate the OpenAI API into the Express backend to enable AI-powered features for the TodoList app. We will create endpoints for:
- Generating a description for a task.
- Creating a task schedule based on the available time.
- Suggesting subtasks for a given main task.
1. Learning Objectives
By the end of this lesson, students will:
- Understand how to integrate the OpenAI API into an Express application.
- Create endpoints for generating task descriptions, schedules, and subtasks.
- Test the OpenAI API integration using Jest and Supertest.
2. Setting Up OpenAI API
2.1. Install OpenAI SDK
Run the following command to install OpenAI:
npm install openai2.2. Add OpenAI Configuration
-
Get the API Key:
- Go to the OpenAI API website.
- Sign up or log in and generate an API key.
- Add the API Key to the
.envFile:
OPENAI_API_KEY=your_openai_api_key_here2.3. Create OpenAI Helper Service
To keep the OpenAI logic clean, we’ll create a helper service.
File: services/openaiService.ts
import { Configuration, OpenAIApi } from 'openai';
import dotenv from 'dotenv';
dotenv.config();
const configuration = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
export const generateTaskDescription = async (task: string): Promise<string> => {
const prompt = `Write a brief description for the following task: "${task}"`;
const response = await openai.createCompletion({
model: 'text-davinci-003',
prompt,
max_tokens: 50,
});
return response.data.choices[0]?.text?.trim() || '';
};
export const generateTaskSchedule = async (tasks: string[], totalTime: number): Promise<string> => {
const prompt = `Given the tasks ${tasks.join(', ')} and ${totalTime} hours available, create a simple schedule.`;
const response = await openai.createCompletion({
model: 'text-davinci-003',
prompt,
max_tokens: 200,
});
return response.data.choices[0]?.text?.trim() || '';
};
export const suggestSubtasks = async (task: string): Promise<string[]> => {
const prompt = `List 3 subtasks to complete the main task: "${task}"`;
const response = await openai.createCompletion({
model: 'text-davinci-003',
prompt,
max_tokens: 100,
});
const suggestions = response.data.choices[0]?.text?.trim().split('\n') || [];
return suggestions.map((subtask) => subtask.replace(/^\d+\.\s/, '').trim());
};3. Create OpenAI Routes
We will now create routes to interact with the OpenAI helper functions.
3.1. Update Controllers
File: controllers/openaiController.ts
import { Request, Response } from 'express';
import { generateTaskDescription, generateTaskSchedule, suggestSubtasks } from '../services/openaiService';
export const getTaskDescription = async (req: Request, res: Response) => {
const { task } = req.body;
if (!task) return res.status(400).json({ message: 'Task is required' });
try {
const description = await generateTaskDescription(task);
res.json({ description });
} catch (error) {
res.status(500).json({ message: 'Failed to generate description' });
}
};
export const getTaskSchedule = async (req: Request, res: Response) => {
const { tasks, totalTime } = req.body;
if (!tasks || !totalTime) return res.status(400).json({ message: 'Tasks and totalTime are required' });
try {
const schedule = await generateTaskSchedule(tasks, totalTime);
res.json({ schedule });
} catch (error) {
res.status(500).json({ message: 'Failed to generate schedule' });
}
};
export const getSubtasks = async (req: Request, res: Response) => {
const { task } = req.body;
if (!task) return res.status(400).json({ message: 'Task is required' });
try {
const subtasks = await suggestSubtasks(task);
res.json({ subtasks });
} catch (error) {
res.status(500).json({ message: 'Failed to suggest subtasks' });
}
};3.2. Add Routes
File: routes/openaiRoutes.ts
import { Router } from 'express';
import { getTaskDescription, getTaskSchedule, getSubtasks } from '../controllers/openaiController';
const router = Router();
router.post('/description', getTaskDescription);
router.post('/schedule', getTaskSchedule);
router.post('/subtasks', getSubtasks);
export default router;3.3. Connect Routes to the App
Update app.ts to include the new OpenAI routes.
import openaiRoutes from './routes/openaiRoutes';
app.use('/api/ai', openaiRoutes);4. Testing OpenAI Endpoints
We will test the OpenAI routes using Jest and Supertest.
4.1. Write Tests
File: tests/openai.test.ts
import request from 'supertest';
import app from '../app';
describe('OpenAI Routes', () => {
it('should generate a task description', async () => {
const res = await request(app)
.post('/api/ai/description')
.send({ task: 'Buy groceries' });
expect(res.status).toBe(200);
expect(res.body.description).toBeDefined();
});
it('should generate a task schedule', async () => {
const res = await request(app)
.post('/api/ai/schedule')
.send({ tasks: ['Task 1', 'Task 2'], totalTime: 3 });
expect(res.status).toBe(200);
expect(res.body.schedule).toBeDefined();
});
it('should generate subtasks for a task', async () => {
const res = await request(app)
.post('/api/ai/subtasks')
.send({ task: 'Prepare a presentation' });
expect(res.status).toBe(200);
expect(res.body.subtasks).toBeInstanceOf(Array);
});
});5. Running the Application
- Start the Backend Server:
npm run dev- Test the OpenAI Routes:
npm test- Test the API with Postman or Curl:
Generate Description:
curl -X POST http://localhost:5000/api/ai/description -H "Content-Type: application/json" -d '{"task":"Write a report"}'Generate Schedule:
curl -X POST http://localhost:5000/api/ai/schedule -H "Content-Type: application/json" -d '{"tasks":["Task 1","Task 2"],"totalTime":4}'Generate Subtasks:
curl -X POST http://localhost:5000/api/ai/subtasks -H "Content-Type: application/json" -d '{"task":"Plan a wedding"}'6. Homework Assignment
- Modify the OpenAI prompt for subtasks to return 5 subtasks instead of 3.
- Add error handling for OpenAI rate limits.
- Write a test case to simulate an invalid request (e.g., missing
taskin the body).
Next Lesson Preview: Lesson 7
In Lesson 7, we will:
- Set up the frontend for the app.
- Use React Query to fetch data from the backend.
- Implement TanStack/React Router for navigation.
