1.9 KiB
1.9 KiB
Stage 2: Handlers
Status: ⬜ Not Started Blocked By: Foundation Unlocks: Errors, Adapters
Objective
Convert functions with throw to handlers returning Result<T, E>.
Handlers to Convert
{{#each HANDLERS}}
{{this.name}}
- File:
{{this.file}}:{{this.line}} - Current:
{{this.signature}} - Throws: {{this.throws}}
- Priority: {{this.priority}}
Conversion
- Define input schema (Zod)
- Define output type
- Identify error cases → taxonomy mapping
- Convert to Handler signature
- Replace
throwwithResult.err() - Add
createValidator()for input - Update callers to use
isOk()/isErr() - Add/update tests
// Target signature
const {{this.name}}: Handler<{{this.inputType}}, {{this.outputType}}, {{this.errorType}}> = async (input, ctx) => {
// ...
};
{{/each}}
Conversion Pattern
Before
async function getUser(id: string): Promise<User> {
const user = await db.users.findById(id);
if (!user) throw new Error(`Not found: ${id}`);
return user;
}
try {
const user = await getUser("123");
} catch (error) {
console.error(error.message);
}
After
import { Result, NotFoundError, type Handler } from "@outfitter/contracts";
const getUser: Handler<{ id: string }, User, NotFoundError> = async (input, ctx) => {
const user = await db.users.findById(input.id);
if (!user) return Result.err(new NotFoundError("user", input.id));
return Result.ok(user);
};
const result = await getUser({ id: "123" }, ctx);
if (result.isErr()) {
ctx.logger.error("Failed", { error: result.error });
}
Completion Checklist
- All handlers return
Result<T, E> - No
throwin handler code - Input validation with
createValidator() - Callers check
isOk()/isErr() - Tests updated for Result assertions
Notes
{{HANDLER_NOTES}}