Skip to content

Commit 51dac55

Browse files
wip
1 parent e5bd504 commit 51dac55

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

packages/router/src/Exceptions/HttpExceptionHandler.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@
1111
use Tempest\Http\GenericResponse;
1212
use Tempest\Http\HttpRequestFailed;
1313
use Tempest\Http\Response;
14+
use Tempest\Http\Responses\Json;
1415
use Tempest\Http\Session\CsrfTokenDidNotMatch;
1516
use Tempest\Http\Status;
1617
use Tempest\Router\ResponseSender;
1718
use Tempest\Support\Filesystem;
1819
use Tempest\View\GenericView;
1920
use Throwable;
2021

22+
use function Tempest\Support\arr;
23+
2124
final readonly class HttpExceptionHandler implements ExceptionHandler
2225
{
2326
public function __construct(
@@ -49,6 +52,30 @@ public function handle(Throwable $throwable): void
4952

5053
private function renderErrorResponse(Status $status, ?HttpRequestFailed $exception = null): Response
5154
{
55+
if ($exception->request->headers->get('Accept') === 'application/json') {
56+
return new Json(
57+
$this->appConfig->environment->isLocal() && $exception !== null
58+
? [
59+
'message' => $exception->getMessage(),
60+
'exception' => get_class($exception),
61+
'file' => $exception->getFile(),
62+
'line' => $exception->getLine(),
63+
'trace' => arr($exception->getTrace())->map(
64+
fn ($trace) => arr($trace)->removeKeys('args')->toArray(),
65+
)->toArray(),
66+
] : [
67+
'message' => $exception?->getMessage() ?: match ($status) {
68+
Status::INTERNAL_SERVER_ERROR => 'An unexpected server error occurred',
69+
Status::NOT_FOUND => 'This page could not be found on the server',
70+
Status::FORBIDDEN => 'You do not have permission to access this page',
71+
Status::UNAUTHORIZED => 'You must be authenticated in to access this page',
72+
Status::UNPROCESSABLE_CONTENT => 'The request could not be processed due to invalid data',
73+
default => null,
74+
},
75+
],
76+
)->setStatus($status);
77+
}
78+
5279
return new GenericResponse(
5380
status: $status,
5481
body: new GenericView(__DIR__ . '/HttpErrorResponse/error.view.php', [

packages/router/src/HandleRouteExceptionMiddleware.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
use Tempest\Http\Request;
88
use Tempest\Http\Response;
99
use Tempest\Http\Responses\Invalid;
10+
use Tempest\Http\Responses\Json;
1011
use Tempest\Http\Responses\NotFound;
12+
use Tempest\Http\Status;
1113
use Tempest\Router\Exceptions\ConvertsToResponse;
1214
use Tempest\Router\Exceptions\RouteBindingFailed;
1315
use Tempest\Validation\Exceptions\ValidationFailed;
@@ -38,15 +40,33 @@ public function __invoke(Request $request, HttpMiddlewareCallable $next): Respon
3840
return $this->forward($request, $next);
3941
}
4042

43+
private function wantsJson(Request $request): bool
44+
{
45+
return $request->headers->get('Accept') === 'application/json';
46+
}
47+
4148
private function forward(Request $request, HttpMiddlewareCallable $next): Response
4249
{
4350
try {
4451
return $next($request);
4552
} catch (ConvertsToResponse $convertsToResponse) {
4653
return $convertsToResponse->toResponse();
4754
} catch (RouteBindingFailed) {
55+
if (! $this->wantsJson($request)) {
56+
return new NotFound([
57+
'message' => 'The requested resource was not found.',
58+
]);
59+
}
60+
4861
return new NotFound();
4962
} catch (ValidationFailed $validationException) {
63+
if (! $this->wantsJson($request)) {
64+
return new Json([
65+
'message' => $validationException->getMessage(),
66+
'errors' => $validationException->errorMessages,
67+
])->setStatus(Status::UNPROCESSABLE_CONTENT);
68+
}
69+
5070
return new Invalid($validationException->subject, $validationException->failingRules);
5171
}
5272
}

0 commit comments

Comments
 (0)