Commit de5aff0c authored by Matthias Adrowski's avatar Matthias Adrowski
Browse files

Merge branch 'feature_exception2response' into 'master'

[FEATURE] Return certain Exceptions as response with correct header

See merge request !5
parents 7588e5d3 a1e5560d
......@@ -34,6 +34,7 @@ use SGalinski\SgRest\Service\Authentication\AuthenticationServiceInterface;
use SGalinski\SgRest\Service\Authentication\BasicAuthenticationService;
use SGalinski\SgRest\Service\Authentication\BearerAuthenticationService;
use SGalinski\SgRest\Service\RegistrationService;
use TYPO3\CMS\Core\Http\Response;
/**
* This class provides the basic prerequisites for the REST middlewares. New middlewares ideally extend this class
......@@ -56,6 +57,15 @@ abstract class AbstractRestMiddleware implements LoggerAwareInterface, Middlewar
*/
public const restPageType = 1595576052;
/**
* Array of Exception Codes that we will return as proper JSON response
*
* @var int[]
*/
protected $reasonableExceptionCodes = [
401, 403, 404
];
/**
* This array contains all information about the request header as associative array.
*
......@@ -148,14 +158,41 @@ abstract class AbstractRestMiddleware implements LoggerAwareInterface, Middlewar
/**
* Method returns the requested action for the rest controller. If no
*
* @param $method
* @return string
* @throws Exception
*/
protected function getCallableActionName($method): string {
if($method === 'POST'){
return 'post'.mb_strtoupper(mb_substr($this->pathSegments['verb'], 0, 1)) . mb_substr($this->pathSegments['verb'], 1);
if ($method === 'POST') {
return 'post' . mb_strtoupper(mb_substr($this->pathSegments['verb'], 0, 1)) . mb_substr(
$this->pathSegments['verb'], 1
);
}
return 'get'.mb_strtoupper(mb_substr($this->pathSegments['verb'], 0, 1)) . mb_substr($this->pathSegments['verb'], 1);
return 'get' . mb_strtoupper(mb_substr($this->pathSegments['verb'], 0, 1)) . mb_substr(
$this->pathSegments['verb'], 1
);
}
/**
* @param $data
* @param int $statusCode
* @return Response
*/
protected function createExceptionJsonResponse($data, int $statusCode): Response {
if (is_string($data)) {
$message = $data;
$data = [];
$data['message'] = $message;
}
$response = (new Response())
->withStatus($statusCode)
->withHeader('Content-Type', 'application/json; charset=utf-8');
if (!empty($data)) {
$options = JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_UNESCAPED_SLASHES;
$response->getBody()->write(json_encode($data ?: NULL, $options));
$response->getBody()->rewind();
}
return $response;
}
}
......@@ -69,12 +69,28 @@ class RestAuthenticator extends AbstractRestMiddleware {
$this->requestHeaders = $request->getHeaders();
// Get class name and the action name of the requested rest controller
$this->pathSegments = PathUtility::analyseRequestSegments($this->requestSegments);
try {
$this->pathSegments = PathUtility::analyseRequestSegments($this->requestSegments);
} catch (\RuntimeException $exception) {
if (in_array($exception->getCode(), $this->reasonableExceptionCodes, TRUE)) {
return $this->createExceptionJsonResponse($exception->getMessage(), $exception->getCode());
}
throw $exception;
}
$apiKey = $this->pathSegments['apiKey'];
$identifier = $this->pathSegments['identifier'];
$httpPermissions = $this->registrationService->getHttpPermissionsForEntity(
$this->pathSegments['entity'], $apiKey
);
try {
// @todo: this currently returns a 500 for a permission question?
$httpPermissions = $this->registrationService->getHttpPermissionsForEntity(
$this->pathSegments['entity'], $apiKey
);
} catch (\RuntimeException $exception) {
if (in_array($exception->getCode(), $this->reasonableExceptionCodes, TRUE)) {
return $this->createExceptionJsonResponse($exception->getMessage(), $exception->getCode());
}
throw $exception;
}
$this->accessGroup = $this->registrationService->getAccessGroupByApiKey($apiKey);
$className = $this->getClassName();
......@@ -102,7 +118,7 @@ class RestAuthenticator extends AbstractRestMiddleware {
);
}
throw new \RuntimeException('Auth-token was not provided or was invalid.', 401);
return $this->createExceptionJsonResponse('Auth-token was not provided or was invalid.', 401);
}
$apiKey = $this->requestSegments[0];
......@@ -122,7 +138,7 @@ class RestAuthenticator extends AbstractRestMiddleware {
);
}
throw new \RuntimeException(
return $this->createExceptionJsonResponse(
'You tried to access an object where you do not have the necessary permissions.', 403
);
}
......@@ -145,7 +161,9 @@ class RestAuthenticator extends AbstractRestMiddleware {
);
}
throw new \RuntimeException('The DELETE method is not permitted for the given path.', 405);
return $this->createExceptionJsonResponse(
'The DELETE method is not permitted for the given path.', 405
);
}
if (
......@@ -170,7 +188,9 @@ class RestAuthenticator extends AbstractRestMiddleware {
);
}
throw new \RuntimeException('The ' . $httpMethod . ' method is not permitted for the given path.', 405);
return $this->createExceptionJsonResponse(
'The ' . $httpMethod . ' method is not permitted for the given path.', 405
);
}
if ($httpMethod === 'POST') {
......@@ -194,7 +214,7 @@ class RestAuthenticator extends AbstractRestMiddleware {
);
}
throw new \RuntimeException('The requested path does not exist.', 404);
return $this->createExceptionJsonResponse('The requested path does not exist.', 404);
}
if ($actionName !== '' && !method_exists($className, $actionName . 'Action')) {
......@@ -212,7 +232,7 @@ class RestAuthenticator extends AbstractRestMiddleware {
]
);
throw new \RuntimeException('The requested path does not exist.', 404);
return $this->createExceptionJsonResponse('The requested path does not exist.', 404);
}
}
......
......@@ -74,7 +74,14 @@ class RestDispatcher extends AbstractRestMiddleware {
$this->requestHeaders = $request->getHeaders();
// Get class name and the action name of the requested rest controller
$this->pathSegments = PathUtility::analyseRequestSegments($this->requestSegments);
try {
$this->pathSegments = PathUtility::analyseRequestSegments($this->requestSegments);
} catch (\RuntimeException $exception) {
if (in_array($exception->getCode(), $this->reasonableExceptionCodes, TRUE)) {
return $this->createExceptionJsonResponse($exception->getMessage(), $exception->getCode());
}
throw $exception;
}
$apiKey = $this->pathSegments['apiKey'];
$identifier = $this->pathSegments['identifier'];
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment