JSON REST API

Complete CRUD API with validation and error handling

A REST API follows conventions for resource-based URLs and HTTP methods. This example demonstrates a complete API with proper status codes, validation, and error handling.

Complete API Server

import { createServer } from 'node:http'; // In-memory data store let users = [ { id: 1, name: 'Alice', email: 'alice@example.com' }, { id: 2, name: 'Bob', email: 'bob@example.com' } ]; let nextId = 3; // Utility functions function parseJSON(req) { return new Promise((resolve, reject) => { let body = ''; req.on('data', chunk => body += chunk); req.on('end', () => { try { resolve(body ? JSON.parse(body) : {}); } catch { reject({ status: 400, message: 'Invalid JSON' }); } }); }); } function sendJSON(res, status, data) { res.writeHead(status, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }); res.end(JSON.stringify(data)); } function sendError(res, status, message) { sendJSON(res, status, { error: message }); } // Validation function validateUser(data) { const errors = []; if (!data.name || data.name.length < 2) { errors.push('Name must be at least 2 characters'); } if (!data.email || !data.email.includes('@')) { errors.push('Valid email is required'); } return errors; }

Request Handler

const server = createServer(async (req, res) => { const { method, url } = req; const [path, id] = url.match(/^\/users(?:\/(\d+))?$/) || []; // Handle CORS preflight if (method === 'OPTIONS') { res.writeHead(204, { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE', 'Access-Control-Allow-Headers': 'Content-Type' }); res.end(); return; } // Route: GET /users - List all users if (method === 'GET' && path && !id) { sendJSON(res, 200, users); return; } // Route: GET /users/:id - Get single user if (method === 'GET' && id) { const user = users.find(u => u.id === parseInt(id)); if (!user) { sendError(res, 404, 'User not found'); return; } sendJSON(res, 200, user); return; } // Route: POST /users - Create user if (method === 'POST' && path && !id) { try { const body = await parseJSON(req); const errors = validateUser(body); if (errors.length > 0) { sendJSON(res, 400, { errors }); return; } const user = { id: nextId++, name: body.name, email: body.email }; users.push(user); sendJSON(res, 201, user); // 201 Created } catch (error) { sendError(res, error.status || 500, error.message); } return; } // Route: PUT /users/:id - Update user if (method === 'PUT' && id) { try { const index = users.findIndex(u => u.id === parseInt(id)); if (index === -1) { sendError(res, 404, 'User not found'); return; } const body = await parseJSON(req); const errors = validateUser(body); if (errors.length > 0) { sendJSON(res, 400, { errors }); return; } users[index] = { ...users[index], name: body.name, email: body.email }; sendJSON(res, 200, users[index]); } catch (error) { sendError(res, error.status || 500, error.message); } return; } // Route: DELETE /users/:id - Delete user if (method === 'DELETE' && id) { const index = users.findIndex(u => u.id === parseInt(id)); if (index === -1) { sendError(res, 404, 'User not found'); return; } users.splice(index, 1); res.writeHead(204); // 204 No Content res.end(); return; } // No route matched sendError(res, 404, 'Not Found'); }); server.listen(3000);

Testing the API

# List all users curl http://localhost:3000/users # Get single user curl http://localhost:3000/users/1 # Create user curl -X POST http://localhost:3000/users \ -H "Content-Type: application/json" \ -d '{"name": "Charlie", "email": "charlie@example.com"}' # Update user curl -X PUT http://localhost:3000/users/1 \ -H "Content-Type: application/json" \ -d '{"name": "Alice Updated", "email": "alice.new@example.com"}' # Delete user curl -X DELETE http://localhost:3000/users/1 # Test validation error curl -X POST http://localhost:3000/users \ -H "Content-Type: application/json" \ -d '{"name": "A"}' # Too short, no email

Status codes used:

  • 200 OK - Successful GET/PUT
  • 201 Created - Successful POST (resource created)
  • 204 No Content - Successful DELETE (no body needed)
  • 400 Bad Request - Invalid input / validation error
  • 404 Not Found - Resource doesn't exist