In my application I'm using FastRoute and I would like to have different types of 404 responses:
/api
then the application should return a JSON 404 response.To get a generic 404 response I did as per the documentation:
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
case FastRoute\Dispatcher::NOT_FOUND:
// ... 404 Not Found
break;
But I'm having trouble finding a way to get a 404 JSON response in case of a not existing /api
endpoint.
What I achieved so this:
$router->addGroup('/api', function (RouteCollector $r) {
$r->post('/login', 'ApiController@login');
$r->addRoute('*', '[/{str}]', 'ApiController@notFound');
});
For example:
/api/not-existing-endpoint
it returns a JSON 404 response (so it's OK)./api/not-existing-endpoint/aaa/bbb/ccc
it does not catch it and it returns a generic 404.How can fix the pattern of the route $r->addRoute('*', '[/{str}]', 'ApiController@notFound');
in order to also catch the nested URIs like /api/aaa/bbb/ccc/ddd
?
$r->addRoute('*', '[/{any:.*}]', 'ApiController@notFound');
require 'vendor/autoload.php';
$dispatcher = \FastRoute\simpleDispatcher(function(\FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/hello[/]', function() {
echo 'hello';
});
$r->addRoute('GET', '/hello/{name}', function($attribute) {
echo 'hello ' . $attribute['name'];
});
$r->addGroup('/api', function (\FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/hello[/]', function() {
header('Content-type: application/json');
echo json_encode(['msg' => 'hello API']);
});
$r->addRoute('*', '[/{any:.*}]', function() {
header('Content-type: application/json');
echo json_encode(['msg' => 'not found']);
});
});
});
// Fetch method and URI from somewhere
// for dynamic subfolder. https://github.com/nikic/FastRoute/issues/110
$base = dirname($_SERVER['PHP_SELF']);
ltrim($base, '/') ? $_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], strlen($base)) : '';
// end dynamic subfolder.
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
// Strip query string (?foo=bar) and decode URI
if (false !== $pos = strpos($uri, '?')) {
$uri = substr($uri, 0, $pos);
}
$uri = rawurldecode($uri);
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
case FastRoute\Dispatcher::NOT_FOUND:
// ... 404 Not Found
http_response_code(404);
echo 'not found';
break;
case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
$allowedMethods = $routeInfo[1];
// ... 405 Method Not Allowed
http_response_code(405);
echo 'method not allowed';
break;
case FastRoute\Dispatcher::FOUND:
$handler = $routeInfo[1];
$vars = $routeInfo[2];
// ... call $handler with $vars
$handler($vars);
break;
}
Tested:
I would recommend you to use 404 route to handle this instead. It is better and easier to manage your code in the future because it will not mixed with normal route.
switch ($routeInfo[0]) {
case FastRoute\Dispatcher::NOT_FOUND:
// ... 404 Not Found
http_response_code(404);
$expUri = explode('/', $uri);
if ($expUri[1] === 'api') {
// if first url segment is api. please check this again in your application that it is [1] or [0] and correct it.
header('Content-type: application/json');
echo json_encode(['msg' => 'not found']);
} else {
echo 'not found';
}
break;
// ...
}
<?php
require 'vendor/autoload.php';
$dispatcher = \FastRoute\simpleDispatcher(function(\FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/hello[/]', function() {
echo 'hello';
});
$r->addRoute('GET', '/hello/{name}', function($attribute) {
echo 'hello ' . $attribute['name'];
});
$r->addGroup('/api', function (\FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/hello[/]', function() {
header('Content-type: application/json');
echo json_encode(['msg' => 'hello API']);
});
});
});
// Fetch method and URI from somewhere
// for dynamic subfolder. https://github.com/nikic/FastRoute/issues/110
$base = dirname($_SERVER['PHP_SELF']);
ltrim($base, '/') ? $_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], strlen($base)) : '';
// end dynamic subfolder.
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
// Strip query string (?foo=bar) and decode URI
if (false !== $pos = strpos($uri, '?')) {
$uri = substr($uri, 0, $pos);
}
$uri = rawurldecode($uri);
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
case FastRoute\Dispatcher::NOT_FOUND:
// ... 404 Not Found
http_response_code(404);
$expUri = explode('/', $uri);
if ($expUri[1] === 'api') {
// if first url segment is api. please check this again in your application that it is [1] or [0] and correct it.
header('Content-type: application/json');
echo json_encode(['msg' => 'not found']);
} else {
echo 'not found';
}
break;
case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
$allowedMethods = $routeInfo[1];
// ... 405 Method Not Allowed
http_response_code(405);
echo 'method not allowed';
break;
case FastRoute\Dispatcher::FOUND:
$handler = $routeInfo[1];
$vars = $routeInfo[2];
// ... call $handler with $vars
$handler($vars);
break;
}