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:

  1. Generating a description for a task.
  2. Creating a task schedule based on the available time.
  3. Suggesting subtasks for a given main task.

1. Learning Objectives

By the end of this lesson, students will:

  1. Understand how to integrate the OpenAI API into an Express application.
  2. Create endpoints for generating task descriptions, schedules, and subtasks.
  3. 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 openai

2.2. Add OpenAI Configuration

  1. Get the API Key:

  2. Add the API Key to the .env File:
OPENAI_API_KEY=your_openai_api_key_here

2.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

  1. Start the Backend Server:
npm run dev
  1. Test the OpenAI Routes:
npm test
  1. 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

  1. Modify the OpenAI prompt for subtasks to return 5 subtasks instead of 3.
  2. Add error handling for OpenAI rate limits.
  3. Write a test case to simulate an invalid request (e.g., missing task in 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.

Copyright © Big Poppa Code & Progress and Fortune LLC 2025