Skip to main content

Error Handling

Basic Error Handling

router(function() {
route(method(GET), url_path("/api/users/:id"), function() {
$id = $_GET[':id'];
$user = User::find($id);

if (!$user) {
throw new \Error("User not found", 404);
}

render(200, json_out($user->toArray()));
});
});

Output when user not found:

{
"error": "User not found"
}

TeensyPHP Exceptions

use TeensyPHP\Exceptions\TeensyPHPException;

router(function() {
route(method(GET), url_path("/api/resource"), function() {
// Not found
TeensyPHPException::throwNotFound();
});

route(method(POST), url_path("/api/resource"), function() {
$data = json_in();

if (empty($data['name'])) {
TeensyPHPException::throwBadRequest();
}

// Process...
});

route(method(GET), url_path("/api/admin"), function() {
if (!isAdmin()) {
TeensyPHPException::throwUnauthorized();
}

render(200, json_out(["admin" => true]));
});
});

Custom Error Messages

use TeensyPHP\Exceptions\TeensyPHPException;

router(function() {
route(method(POST), url_path("/api/users"), function() {
$data = json_in();

if (empty($data['email'])) {
throw new TeensyPHPException("Email is required", 400);
}

if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
throw new TeensyPHPException("Invalid email format", 400);
}

if (User::findByEmail($data['email'])) {
throw new TeensyPHPException("Email already exists", 409);
}

$user = User::create($data);
render(201, json_out($user->toArray()));
});
});

Early Exit with stop()

function requireAuth()
{
$token = request_header('Authorization');

if (empty($token)) {
render(401, json_out(['error' => 'Unauthorized']));
stop(); // Stops execution here
}

if (!validateToken($token)) {
render(403, json_out(['error' => 'Invalid token']));
stop();
}
}

router(function() {
route(method(GET), url_path("/api/protected"), function() {
requireAuth();
// Only reaches here if authenticated
render(200, json_out(["data" => "secret"]));
});
});

Try-Catch Pattern

router(function() {
route(method(POST), url_path("/api/process"), function() {
try {
$data = json_in();
$result = processComplexOperation($data);
render(200, json_out(["result" => $result]));

} catch (\InvalidArgumentException $e) {
render(400, json_out(["error" => $e->getMessage()]));

} catch (\RuntimeException $e) {
render(500, json_out(["error" => "Processing failed"]));
error_log($e->getMessage());

} catch (\Exception $e) {
render(500, json_out(["error" => "Internal server error"]));
error_log($e->getMessage());
}
});
});

How Error Handling Works

The TeensyPHP router() function includes a built-in error handler that catches exceptions and renders JSON error responses automatically.

When you throw an exception:

  1. The router catches it
  2. Uses the exception code as the HTTP status code
  3. Returns the exception message as a JSON error response

For more control, use try-catch blocks or the stop() function to handle errors manually.

Function Reference

TeensyPHPException

use TeensyPHP\Exceptions\TeensyPHPException;

throw new TeensyPHPException(string $message, int $code);
ParameterTypeDescription
$messagestringError message (default: "Internal Server Error")
$codeintHTTP status code (default: 500)

Helper Methods

MethodStatus CodeDescription
TeensyPHPException::throwNotFound()404Resource not found
TeensyPHPException::throwBadRequest()400Invalid request
TeensyPHPException::throwUnauthorized()403Access denied

stop()

stop(int $code = 0): void

Halts script execution. Use instead of exit() to keep code testable.

ParameterTypeDescription
$codeintExit code (default: 0)

Common HTTP Error Codes

CodeNameWhen to Use
400Bad RequestInvalid input, validation errors
401UnauthorizedMissing authentication
403ForbiddenValid auth but no permission
404Not FoundResource doesn't exist
405Method Not AllowedWrong HTTP method
409ConflictDuplicate resource
422Unprocessable EntitySemantic validation errors
500Internal Server ErrorServer-side failures