DEV Community

Cover image for LLM integration with OpenAI Completions API
Željko Šević
Željko Šević

Posted on • Originally published at sevic.dev on

LLM integration with OpenAI Completions API

ChatGPT is a large language model (LLM) that understands and processes human prompts to produce helpful responses. OpenAI exposes models through the Chat Completions API. The official openai npm package is the practical way to call it from Node.js. This post covers common patterns beyond a single user message.

For the newer Responses API (web search, instructions, and input), see the dedicated post.

Prerequisites

  • OpenAI account
  • Generated API key
  • Enabled billing
  • Node.js version 26
  • openai package installed (npm i openai)
  • For Markdown output: marked, dompurify, and jsdom (npm i marked dompurify jsdom)

Client setup

Create a client with your API key (read from the environment in production).

import OpenAI from 'openai';

const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
Enter fullscreen mode Exit fullscreen mode

The same SDK can target OpenAI-compatible gateways by setting baseURL and apiKey:

const client = new OpenAI({
  apiKey: process.env.LLM_API_KEY,
  baseURL: 'https://your-gateway.example/v1',
});
Enter fullscreen mode Exit fullscreen mode

Azure OpenAI uses AzureOpenAI instead. Many third-party hosts implement Chat Completions, so this API is a common integration path.

Basic integration

Send a user message and read the assistant reply from choices[0].message.content.

const completion = await client.chat.completions.create({
  model: 'gpt-5.5',
  messages: [
    { role: 'user', content: 'Write a one-sentence bedtime story about a unicorn.' },
  ],
});

console.log(completion.choices[0].message.content);
Enter fullscreen mode Exit fullscreen mode

System prompt

Add a system message (or developer on newer models) before the user message to set tone, format, and role.

const completion = await client.chat.completions.create({
  model: 'gpt-5.5',
  messages: [
    { role: 'system', content: 'Reply in one short sentence. Use plain language.' },
    { role: 'user', content: 'Explain what an LLM is.' },
  ],
});

console.log(completion.choices[0].message.content);
Enter fullscreen mode Exit fullscreen mode

Few-shot prompting

Include prior user and assistant turns in messages, then the new user question. Keep task rules in the system message.

const completion = await client.chat.completions.create({
  model: 'gpt-5.5',
  messages: [
    {
      role: 'system',
      content:
        'Classify sentiment as exactly one word: positive, negative, or neutral.',
    },
    { role: 'user', content: 'I love this!' },
    { role: 'assistant', content: 'positive' },
    { role: 'user', content: 'This is awful.' },
    { role: 'assistant', content: 'negative' },
    { role: 'user', content: 'It is fine I guess.' },
  ],
});

console.log(completion.choices[0].message.content);
Enter fullscreen mode Exit fullscreen mode

Streaming

Set stream: true and read incremental text from choices[0].delta.content.

const stream = await client.chat.completions.create({
  model: 'gpt-5.5',
  messages: [{ role: 'user', content: 'List three colors.' }],
  stream: true,
});

process.stdout.write('[stream] ');
for await (const chunk of stream) {
  const delta = chunk.choices[0]?.delta?.content;
  if (delta) {
    process.stdout.write(delta);
  }
}
process.stdout.write('\n');
Enter fullscreen mode Exit fullscreen mode

Structured output with JSON schema

Use response_format with type: 'json_schema' and strict: true so the model returns JSON matching your schema.

const completion = await client.chat.completions.create({
  model: 'gpt-5.5',
  messages: [
    {
      role: 'user',
      content: 'The film Inception was directed by Christopher Nolan.',
    },
  ],
  response_format: {
    type: 'json_schema',
    json_schema: {
      name: 'movie_summary',
      strict: true,
      schema: {
        type: 'object',
        properties: {
          title: { type: 'string' },
          director: { type: 'string' },
        },
        required: ['title', 'director'],
        additionalProperties: false,
      },
    },
  },
});

const data = JSON.parse(completion.choices[0].message.content);
console.log(data.title, data.director);
Enter fullscreen mode Exit fullscreen mode

For typed parsing with Zod, you can use client.chat.completions.parse() instead of JSON.parse.

Markdown output to HTML

Ask for Markdown in the system message, then convert the assistant reply to HTML and sanitize before rendering.

import { marked } from 'marked';
import { JSDOM } from 'jsdom';
import DOMPurify from 'dompurify';

const purify = DOMPurify(new JSDOM('').window);

const completion = await client.chat.completions.create({
  model: 'gpt-5.5',
  messages: [
    {
      role: 'system',
      content: 'Reply in Markdown only. Use a heading and a short bullet list.',
    },
    { role: 'user', content: 'Explain what an LLM is in three bullet points.' },
  ],
});

const markdown = completion.choices[0].message.content;
const html = marked.parse(markdown);
const safeHtml = purify.sanitize(html);
Enter fullscreen mode Exit fullscreen mode

Always run DOMPurify.sanitize on model-generated HTML. The model can emit unsafe markup; sanitization strips scripts and other dangerous content.

Demo

Runnable scripts for each section live in the openai-chat-completions-api-demo folder. Get access via code demos.

Top comments (0)