Always validate API request and response data using schema validation to ensure type safety and prevent runtime errors. Define explicit schemas (e.g., using Zod or similar) for all API interfaces rather than relying on TypeScript types alone.

Example:

// Before
interface ChatMessage {
  action: string;
  chatInput: string;
  sessionId: string;
}

async function handleMessage(data: RawData) {
  const message = jsonParse<ChatMessage>(data.toString());
  // No validation, could fail at runtime
  await processMessage(message);
}

// After
const chatMessageSchema = z.object({
  action: z.enum(['user', 'system']),
  chatInput: z.string(),
  sessionId: z.string().uuid()
});

type ChatMessage = z.infer<typeof chatMessageSchema>;

async function handleMessage(data: RawData) {
  const rawMessage = jsonParse(data.toString());
  const message = chatMessageSchema.parse(rawMessage);
  // Validated data, guaranteed to match schema
  await processMessage(message);
}

This practice: