Write secure, maintainable, and performant functions. Learn proven patterns for error handling, security, testing, and scalable architecture.
export const handler = async (event) => { const { httpMethod, body } = event; const data = body ? JSON.parse(body) : {}; switch (httpMethod) { case 'GET': return { statusCode: 200, body: JSON.stringify({ users: await getUsers() }) }; case 'POST': const newUser = await createUser(data); return { statusCode: 201, body: JSON.stringify({ id: newUser.id, message: 'User created' }) }; case 'PUT': const updatedUser = await updateUser(data); return { statusCode: 200, body: JSON.stringify(updatedUser) }; case 'DELETE': await deleteUser(data.id); return { statusCode: 204, body: '' }; default: return { statusCode: 405, body: JSON.stringify({ error: 'Method not allowed' }) }; } };
export const handler = async (event) => { const { body } = event; try { const data = JSON.parse(body || '{}'); // Validate required fields const errors = []; if (!data.email) errors.push('Email is required'); if (!data.password) errors.push('Password is required'); if (data.password && data.password.length < 8) { errors.push('Password must be at least 8 characters'); } // Return validation errors if (errors.length > 0) { return { statusCode: 400, body: JSON.stringify({ error: 'Validation failed', details: errors }) }; } // Process valid data const result = await processUser(data); return { statusCode: 200, body: JSON.stringify(result) }; } catch (error) { return { statusCode: 400, body: JSON.stringify({ error: 'Invalid JSON' }) }; } };
export const handler = async (event) => { try { const result = await processRequest(event); return { statusCode: 200, body: JSON.stringify({ success: true, data: result }) }; } catch (error) { console.error('Request processing error:', error); // Handle validation errors if (error.name === 'ValidationError') { return { statusCode: 400, body: JSON.stringify({ error: 'Invalid input', details: error.message }) }; } // Handle not found errors if (error.name === 'NotFoundError') { return { statusCode: 404, body: JSON.stringify({ error: 'Resource not found' }) }; } // Handle unexpected errors return { statusCode: 500, body: JSON.stringify({ error: 'Internal server error', requestId: event.requestContext?.requestId }) }; } };
import jwt from 'jsonwebtoken'; export const handler = async (event) => { try { // Extract token from header const authHeader = event.headers.Authorization || event.headers.authorization; if (!authHeader?.startsWith('Bearer ')) { return { statusCode: 401, body: JSON.stringify({ error: 'Missing or invalid authorization header' }) }; } const token = authHeader.substring(7); const decoded = jwt.verify(token, process.env.JWT_SECRET); // Check user permissions if (!decoded.permissions?.includes('admin')) { return { statusCode: 403, body: JSON.stringify({ error: 'Insufficient permissions' }) }; } // Continue with authenticated request const result = await processAuthenticatedRequest(decoded, event); return { statusCode: 200, body: JSON.stringify(result) }; } catch (error) { return { statusCode: 401, body: JSON.stringify({ error: 'Invalid token' }) }; } };
// Use environment variables for sensitive data const config = { database: { host: process.env.DB_HOST, username: process.env.DB_USERNAME, password: process.env.DB_PASSWORD, ssl: process.env.NODE_ENV === 'production' }, jwt: { secret: process.env.JWT_SECRET, expiresIn: process.env.JWT_EXPIRES_IN || '24h' }, external: { apiKey: process.env.EXTERNAL_API_KEY, webhookSecret: process.env.WEBHOOK_SECRET } }; // Validate required environment variables const requiredEnvVars = ['DB_HOST', 'JWT_SECRET', 'EXTERNAL_API_KEY']; const missingVars = requiredEnvVars.filter(varName => !process.env[varName]); if (missingVars.length > 0) { throw new Error(`Missing required environment variables: ${missingVars.join(', ')}`); }
// Initialize outside handler for reuse across invocations import { createConnection } from './database'; import { initializeCache } from './cache'; let dbConnection; let cache; // Initialize on first import const initializeResources = async () => { if (!dbConnection) { dbConnection = await createConnection(); } if (!cache) { cache = await initializeCache(); } }; export const handler = async (event) => { // Ensure resources are initialized await initializeResources(); // Use cached resources const result = await dbConnection.query('SELECT * FROM users'); await cache.set('users', result, 300); // Cache for 5 minutes return { statusCode: 200, body: JSON.stringify(result) }; };
import { Pool } from 'pg'; // Create connection pool outside handler const pool = new Pool({ host: process.env.DB_HOST, database: process.env.DB_NAME, user: process.env.DB_USER, password: process.env.DB_PASSWORD, max: 10, // Maximum pool size idleTimeoutMillis: 30000, connectionTimeoutMillis: 2000, }); export const handler = async (event) => { const client = await pool.connect(); try { // Use parameterized queries to prevent SQL injection const result = await client.query( 'SELECT * FROM users WHERE email = $1 AND status = $2', [event.body.email, 'active'] ); return { statusCode: 200, body: JSON.stringify(result.rows) }; } finally { client.release(); // Always release the client back to pool } };
import { handler } from '../src/user-handler'; describe('User Handler', () => { test('should create user with valid data', async () => { // Arrange const event = { httpMethod: 'POST', body: JSON.stringify({ name: 'John Doe', email: 'john@example.com', password: 'securePassword123' }) }; // Act const response = await handler(event); const body = JSON.parse(response.body); // Assert expect(response.statusCode).toBe(201); expect(body).toHaveProperty('id'); expect(body.message).toBe('User created'); }); test('should return validation error for invalid email', async () => { // Arrange const event = { httpMethod: 'POST', body: JSON.stringify({ name: 'John Doe', email: 'invalid-email', password: 'securePassword123' }) }; // Act const response = await handler(event); const body = JSON.parse(response.body); // Assert expect(response.statusCode).toBe(400); expect(body.error).toBe('Validation failed'); expect(body.details).toContain('Valid email is required'); }); });
export const handler = async (event) => { const { request, response } = event; const responseBody = JSON.parse(response.body); // Only enhance specific endpoints if (request.path.includes('/api/')) { // Add API-specific enhancements return { ...response, headers: { ...response.headers, 'X-API-Version': '1.0', 'X-Rate-Limit': '1000' }, body: JSON.stringify({ ...responseBody, meta: { version: '1.0', timestamp: new Date().toISOString() } }) }; } return response; // Return unchanged for other endpoints };
export const handler = async (event) => { const maxRetries = 3; let attempt = 0; while (attempt < maxRetries) { try { const result = await performTask(); return { statusCode: 200, body: JSON.stringify({ success: true, attempt: attempt + 1, result }) }; } catch (error) { attempt++; console.error(`Task attempt ${attempt} failed:`, error); if (attempt >= maxRetries) { // Send notification on final failure await sendTaskFailureNotification(error); return { statusCode: 500, body: JSON.stringify({ error: 'Task failed after maximum retries', attempts: attempt, lastError: error.message }) }; } // Wait before retrying (exponential backoff) await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000)); } } };
// Every day at 2:30 AM cron(30 2 * * ? *) // Every weekday at 9:00 AM cron(0 9 ? * MON-FRI *) // Every 15 minutes cron(*/15 * * * ? *) // First day of every month at midnight cron(0 0 1 * ? *) // Every Sunday at 6:00 PM cron(0 18 ? * SUN *)