Prism provides a structured approach to errors: throw typed errors from handlers, and middleware catches them and converts them to consistent JSON responses.
// 1. Add the error middlewareawait server.use(PrismErrorMiddleware())// 2. Throw errors from handlers — they become JSON responsesawait server.get("/users/:id") { request in let id = request.parameters["id"]! guard let user = try db.queryFirst("SELECT * FROM users WHERE id = ?", parameters: [.text(id)]) else { throw PrismAppError.notFound("User \(id) not found") } return .json(user.columns)}
The client receives:
{ "error": "NOT_FOUND", "message": "User 42 not found"}
await server.post("/users") { request in // Validation errors return 422 automatically let validation = request.validate { v in v.field("email", .required, .email) v.field("name", .required, .minLength(2)) } if let errorResponse = validation.errorResponse() { return errorResponse } // Business logic errors let email = request.formData["email"]! let exists = try db.queryFirst( "SELECT id FROM users WHERE email = ?", parameters: [.text(email)] ) if exists != nil { throw PrismAppError.conflict("Email already registered") } try db.execute( "INSERT INTO users (name, email) VALUES (?, ?)", parameters: [.text(request.formData["name"]!), .text(email)] ) return .json(["email": email], status: .created)}
Always put PrismErrorMiddleware as one of the first middleware in your stack. If it’s added after other middleware, errors thrown in those middleware won’t be caught.