Skip to content

API Endpoint ​

A REST API for chat completions with SSE streaming support.

Features ​

  • SSE Streaming - Server-Sent Events for real-time responses
  • Rate Limiting - In-memory request throttling
  • Validation - Request body validation
  • Error Handling - Proper HTTP status codes

Quick Start ​

bash
export OPENAI_API_KEY=your_key
npm run recipe:api-endpoint

How It Works ​

This recipe creates a simple HTTP server that wraps Meloqui's ChatClient, exposing it as a REST API with SSE streaming support.

Endpoints:

  • POST /chat - Send a message and get a completion (supports streaming)
  • GET /health - Health check endpoint

Flow:

  1. Client sends a POST request with a message
  2. Server validates the request and checks rate limits
  3. Meloqui's ChatClient forwards the request to OpenAI
  4. Response streams back through SSE or returns as JSON

Architecture ​

API Reference ​

POST /chat ​

Send a chat message and receive a response.

Request:

json
{
  "message": "Hello!",
  "stream": false
}
FieldTypeRequiredDescription
messagestringYesThe message to send
streambooleanNoEnable SSE streaming (default: false)

Response (non-streaming):

json
{
  "content": "Hi there! How can I help you?",
  "tokensUsed": 15
}

Response (streaming):

Content-Type: text/event-stream

data: {"content": "Hi"}
data: {"content": " there"}
data: {"content": "!"}
data: [DONE]

GET /health ​

Health check endpoint.

json
{"content": "ok"}

Testing with curl ​

Non-streaming Request ​

bash
curl -X POST http://localhost:3000/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "What is 2+2?"}'

Streaming Request ​

bash
curl -X POST http://localhost:3000/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "Tell me a short joke", "stream": true}'

Health Check ​

bash
curl http://localhost:3000/health

Code Walkthrough ​

Server Setup ​

typescript
import * as http from 'http';
import { ChatClient } from 'meloqui';

const client = new ChatClient({
  provider: 'openai',
  model: 'gpt-4o-mini',
  apiKey: process.env.OPENAI_API_KEY
});

const server = http.createServer(async (req, res) => {
  if (req.url === '/chat' && req.method === 'POST') {
    await handleChat(req, res, client);
  }
});

server.listen(3000);

SSE Streaming ​

typescript
// Set SSE headers
res.writeHead(200, {
  'Content-Type': 'text/event-stream',
  'Cache-Control': 'no-cache',
  'Connection': 'keep-alive'
});

// Stream chunks
for await (const chunk of client.stream(message)) {
  res.write(`data: ${JSON.stringify({ content: chunk.content })}\n\n`);
}

res.write('data: [DONE]\n\n');
res.end();

Rate Limiting ​

typescript
const RATE_LIMIT_WINDOW_MS = 60_000; // 1 minute
const RATE_LIMIT_MAX_REQUESTS = 20;

const rateLimitMap = new Map<string, { count: number; resetTime: number }>();

function checkRateLimit(clientIP: string): boolean {
  const now = Date.now();
  const record = rateLimitMap.get(clientIP);

  if (!record || now > record.resetTime) {
    rateLimitMap.set(clientIP, { count: 1, resetTime: now + RATE_LIMIT_WINDOW_MS });
    return true;
  }

  if (record.count >= RATE_LIMIT_MAX_REQUESTS) {
    return false;
  }

  record.count++;
  return true;
}

Error Responses ​

StatusCodeDescription
400INVALID_REQUESTInvalid JSON body
400VALIDATION_ERRORMissing or invalid fields
401AUTH_ERRORAPI key authentication failed
404NOT_FOUNDEndpoint not found
429RATE_LIMITEDToo many requests
429PROVIDER_RATE_LIMITEDOpenAI rate limit hit
500CHAT_ERRORChat completion failed
500INTERNAL_ERRORUnexpected error

Rate Limit Headers ​

All responses include rate limit information:

X-RateLimit-Limit: 20
X-RateLimit-Remaining: 19
X-RateLimit-Reset: 60

Configuration ​

Environment variables:

VariableDefaultDescription
OPENAI_API_KEY-Required. OpenAI API key
PORT3000Server port

Full Source ​

View on GitHub

Released under the MIT License.