A production-ready Node.js HTTP API server that powers an AI chat feature with conversation continuity and multiple tools including ping, weather, DNS lookup, and timezone support.
- AI-powered conversations using Google Gemini (gemini-2.0-flash-exp)
- Conversation continuity - maintain context across multiple messages
- Multiple tools for the AI to use:
- Ping - Check if hosts are reachable with latency info
- Weather - Get current weather for any city (via Open-Meteo API)
- DNS - Look up DNS records for domains
- DateTime - Get current time in any timezone
- Result caching - tool results are cached in SQLite to reduce redundant requests
- Rate limiting - configurable protection against API abuse
- Security hardened - helmet.js headers, CORS configuration, input sanitization
- Request logging - track all incoming requests with structured logging
- SQLite database - persistent storage for conversations and cache
- Docker support - easy containerized deployment
- OpenAPI documentation - complete API specification
- Unit tests - Jest-based test suite
- Node.js 18+
- A Google AI API key (get one free at Google AI Studio)
- Clone the repository
git clone <repository-url> cd ai-chat-api-server
- Install dependencies
npm install
- Configure environment variables
cp .env.example .env
Edit .env and add your Google AI API key:
GOOGLE_AI_API_KEY=your_api_key_here
- Start the server
Development mode (with hot reload):
npm run dev
Production mode:
npm run build npm start
The server will start on http://localhost:3000 (or the port specified in .env).
- Build and run with Docker Compose
# Set your API key export GOOGLE_AI_API_KEY=your_api_key_here # Build and start docker-compose up -d # View logs docker-compose logs -f
- Or build manually
docker build -t ai-chat-api .
docker run -p 3000:3000 -e GOOGLE_AI_API_KEY=your_key ai-chat-apiGET /api/health
Response:
{
"success": true,
"data": { "status": "ok", "uptime": 123.45 }
}Send a message to the AI assistant and receive a response.
POST /api/chat/message
Content-Type: application/json
Request Body:
{
"message": "What's the weather in Tokyo?",
"conversationId": "optional-uuid-for-continuing-conversation"
}Response:
{
"success": true,
"data": {
"conversationId": "550e8400-e29b-41d4-a716-446655440000",
"message": {
"role": "assistant",
"content": "The current weather in Tokyo is 18°C with clear skies...",
"toolCalls": [
{
"name": "weather",
"input": { "location": "Tokyo" },
"result": {
"success": true,
"data": {
"location": "Tokyo, Japan",
"temperature": "18°C",
"conditions": "Clear sky",
"humidity": "65%"
}
}
}
]
}
}
}Retrieve the full history of a conversation.
GET /api/chat/conversations/:conversationId
Response:
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"messages": [
{
"id": 1,
"role": "user",
"content": "Hello!",
"timestamp": 1702345678000
},
{
"id": 2,
"role": "assistant",
"content": "Hello! How can I help you today?",
"timestamp": 1702345679000
}
],
"createdAt": 1702345678000,
"updatedAt": 1702345679000
}
}All errors follow a consistent format:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message",
"details": {}
}
}Error Codes:
| Code | HTTP Status | Description |
|---|---|---|
VALIDATION_ERROR |
400 | Invalid request body or parameters |
NOT_FOUND |
404 | Resource not found |
RATE_LIMITED |
429 | Too many requests |
AI_SERVICE_ERROR |
502 | AI provider error |
TOOL_EXECUTION_ERROR |
500 | Tool execution failed |
INTERNAL_ERROR |
500 | Unexpected server error |
The AI assistant has access to the following tools:
Check if a host is reachable and get latency information.
Example prompts:
- "Can you check if google.com is reachable?"
- "Is 8.8.8.8 online?"
- "Ping cloudflare.com for me"
Security: Only public hostnames/IPs are allowed. Private/internal addresses (localhost, 192.168.x.x, etc.) are blocked.
Get current weather for any city using the free Open-Meteo API.
Example prompts:
- "What's the weather in London?"
- "How's the weather in New York?"
- "Tell me the temperature in Tokyo"
Look up DNS records for a domain.
Example prompts:
- "What are the DNS records for google.com?"
- "Look up the MX records for example.org"
- "What's the IP address of github.com?"
Supported record types: A, AAAA, MX, TXT, NS, CNAME, SOA
Get current date/time in any timezone.
Example prompts:
- "What time is it in Tokyo?"
- "What's the current time in PST?"
- "Tell me the date in London"
Supported formats: City names, timezone abbreviations (PST, EST, UTC), and IANA timezones (America/New_York)
curl -X POST http://localhost:3000/api/chat/message \ -H "Content-Type: application/json" \ -d '{"message": "Hello! What can you do?"}'
curl -X POST http://localhost:3000/api/chat/message \ -H "Content-Type: application/json" \ -d '{"message": "What is the weather like in Paris?"}'
curl -X POST http://localhost:3000/api/chat/message \ -H "Content-Type: application/json" \ -d '{"message": "Is github.com reachable?"}'
curl -X POST http://localhost:3000/api/chat/message \ -H "Content-Type: application/json" \ -d '{"message": "What are the MX records for gmail.com?"}'
curl -X POST http://localhost:3000/api/chat/message \ -H "Content-Type: application/json" \ -d '{"message": "What time is it in Sydney?"}'
-
Express.js - Chosen for its maturity, extensive middleware ecosystem, and excellent TypeScript support.
-
Google Gemini (gemini-1.5-flash) - Selected because:
- Free tier available via Google AI Studio
- Excellent function/tool calling support
- Good documentation and SDK
-
SQLite with better-sqlite3 - Perfect for this use case because:
- Zero configuration (no external database server)
- Single file storage (portable)
- Synchronous API for simpler code
- Sufficient performance for conversation storage and caching
-
TypeScript - Provides type safety and better developer experience.
-
Open-Meteo API - Free weather API with no API key required.
- Layered architecture: Routes → Controllers → Services → Database
- Tool registry pattern: Easily extensible for adding new tools
- Caching layer: Tool results are cached (default 5 minutes) to reduce external requests
- Conversation persistence: Full conversation history stored for context
- Rate limiting: Protects API from abuse (60 req/min general, 20 req/min for chat)
- Input validation: All API inputs are validated using Zod schemas
- Command injection prevention: Ping/DNS tools validate inputs using strict regex patterns
- Private IP blocking: Internal network addresses are blocked from ping tool
- Rate limiting: Prevents API abuse
- No sensitive data in responses: Error messages don't leak internal details
- Non-root Docker user: Container runs as non-privileged user
| Endpoint | Limit |
|---|---|
| General API | 60 requests/minute |
| Chat messages | 20 requests/minute |
ai-chat-api-server/
├── src/
│ ├── index.ts # Entry point
│ ├── config/
│ │ └── index.ts # Environment configuration
│ ├── routes/
│ │ ├── index.ts # Route aggregator
│ │ └── chat.routes.ts # Chat endpoints
│ ├── controllers/
│ │ └── chat.controller.ts # Request handlers
│ ├── services/
│ │ ├── chat.service.ts # AI/chat logic
│ │ └── cache.service.ts # Caching layer
│ ├── tools/
│ │ ├── index.ts # Tool registry
│ │ ├── ping.tool.ts # Ping implementation
│ │ ├── weather.tool.ts # Weather lookup
│ │ ├── dns.tool.ts # DNS lookup
│ │ └── datetime.tool.ts # Timezone/datetime
│ ├── db/
│ │ ├── index.ts # Database connection
│ │ └── schema.ts # Table definitions
│ ├── types/
│ │ └── index.ts # TypeScript types
│ ├── middleware/
│ │ ├── error.middleware.ts # Global error handler
│ │ ├── rate-limit.middleware.ts # Rate limiting
│ │ ├── request-logger.middleware.ts
│ │ └── validation.middleware.ts
│ └── utils/
│ ├── logger.ts
│ ├── errors.ts # Custom error classes
│ └── sanitize.ts # Input sanitization
├── data/ # SQLite database (created at runtime)
├── Dockerfile
├── docker-compose.yml
├── .dockerignore
├── .env.example
├── .gitignore
├── package.json
├── tsconfig.json
└── README.md
Run the test suite:
# Run all tests npm test # Run tests in watch mode npm run test:watch # Run tests with coverage report npm run test:coverage
Full API documentation is available in openapi.yaml. You can view it using:
- Swagger Editor - Paste the contents of openapi.yaml
- Redoc - For beautiful documentation rendering
This server implements multiple security measures:
- Helmet.js - Adds security HTTP headers (CSP, X-Frame-Options, etc.)
- CORS - Configurable cross-origin resource sharing
- Rate Limiting - Prevents API abuse (configurable limits)
- Input Sanitization - All inputs are sanitized before storage
- Command Injection Prevention - Ping tool uses
execFile()with strict validation - Private IP Blocking - Internal network addresses are blocked from ping tool
- No Sensitive Data Leakage - Error messages don't expose internal details
MIT