From 18cfc7adbaf6baeb4f9ec8480d2c33811f962ab4 Mon Sep 17 00:00:00 2001 From: Miguel Nogueira Date: Wed, 16 Apr 2025 18:51:53 +0100 Subject: [PATCH] feat: add CORS handling --- public/index.php | 28 +++++++++++++++++++++++++ src/Controllers/TaskController.php | 33 +++++++++++++++--------------- src/Models/Task.php | 2 +- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/public/index.php b/public/index.php index 938cc94..6cb10ac 100644 --- a/public/index.php +++ b/public/index.php @@ -4,19 +4,47 @@ use Controllers\TaskController; use DI\Bridge\Slim\Bridge; use DI\Container; use Controllers\HomeFrontController; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\RequestHandlerInterface; use Slim\Handlers\Strategies\RequestResponseArgs; require_once __DIR__ . '/../vendor/autoload.php'; $container = new Container(); $app = Bridge::create($container); + $app->addBodyParsingMiddleware(); +$app->addRoutingMiddleware(); +$app->addErrorMiddleware(true, true, true); // this strategy is preferable because we aren't using a lot of named placeholders $routeCollector = $app->getRouteCollector(); $routeCollector->setDefaultInvocationStrategy(new RequestResponseArgs()); +$app->add(function (ServerRequestInterface $request, RequestHandlerInterface $handler) use ($app): ResponseInterface { + if ($request->getMethod() === 'OPTIONS') { + $response = $app->getResponseFactory()->createResponse(); + } else { + $response = $handler->handle($request); + } + + $response = $response + ->withHeader('Access-Control-Allow-Credentials', 'true') + ->withHeader('Access-Control-Allow-Origin', '*') + ->withHeader('Access-Control-Allow-Headers', '*') + ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS') + ->withHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') + ->withHeader('Pragma', 'no-cache'); + + if (ob_get_contents()) { + ob_clean(); + } + + return $response; +}); + $app->get('/', [HomeFrontController::class, 'home']); diff --git a/src/Controllers/TaskController.php b/src/Controllers/TaskController.php index ab839b6..27bd541 100644 --- a/src/Controllers/TaskController.php +++ b/src/Controllers/TaskController.php @@ -16,7 +16,8 @@ use Utils\StructuredResponseBuilder; class TaskController { - private $repository, $builder; + private StructuredResponseBuilder $builder; + private TaskRepository $repository; // instead of requesting the builder here, we could simply make it static public function __construct(TaskRepository $taskRepository, StructuredResponseBuilder $builder) @@ -34,7 +35,7 @@ class TaskController $requiredKeys = ['name', 'description', 'status', 'start', 'end']; - if (!array_key_exists('tasks', $params)) { + if (!array_key_exists('payload', $params)) { $this->builder->setError(); $this->builder->setErrorMessage('Malformed request payload. Please try again.'); $this->builder->setErrorCode(400); @@ -48,7 +49,7 @@ class TaskController $missingKeys = []; foreach ($requiredKeys as $key) { - if (!array_key_exists($key, $params['tasks'])) { + if (!array_key_exists($key, $params['payload'])) { $missingKeys[] = $key; } } @@ -66,8 +67,8 @@ class TaskController try { - $start = Carbon::parse($params['tasks']['start']); - $end = Carbon::parse($params['tasks']['end']); + $start = Carbon::parse($params['payload']['start']); + $end = Carbon::parse($params['payload']['end']); if ($start->gt($end) || $end->lt($start)) { throw new InvalidTaskDateException('Invalid task date. Start date must not be after end date.'); @@ -85,7 +86,7 @@ class TaskController return $errorResponse; } - if (is_null(TaskStatus::tryFrom($params['tasks']['status']))) { + if (is_null(TaskStatus::tryFrom($params['payload']['status']))) { $this->builder->setError(); $this->builder->setErrorCode(400); $this->builder->setErrorMessage('Invalid task status code. Status must range from 1-4 (started, in progress, blocked, completed).'); @@ -97,11 +98,11 @@ class TaskController } $task = new Task(); - $task->setName($params['tasks']['name']) - ->setStatusId(TaskStatus::tryFrom((int) $params['tasks']['status'])) - ->setDescription($params['tasks']['description']) - ->setStart($params['tasks']['start']) - ->setEnd($params['tasks']['end']); + $task->setName($params['payload']['name']) + ->setStatusId(TaskStatus::tryFrom((int) $params['payload']['status'])) + ->setDescription($params['payload']['description']) + ->setStart($params['payload']['start']) + ->setEnd($params['payload']['end']); $createdTask = $this->repository->create($task); @@ -133,7 +134,7 @@ class TaskController $this->builder->setPayload($payload)->setOptionalMessage('Listing all tasks: '); $response->getBody()->write($this->builder->build()); - return $response; + return $response->withHeader('Content-Type', 'application/json'); } public function getTask(ServerRequestInterface $request, ResponseInterface $response, string $id): ResponseInterface @@ -144,12 +145,12 @@ class TaskController $this->builder->setPayload($payload)->setOptionalMessage("Task retrieved."); $response->getBody()->write($this->builder->build()); - return $response; + return $response->withHeader('Content-Type', 'application/json'); } catch (TaskNotFoundException $e) { $this->builder->setError()->setErrorMessage($e->getMessage())->setErrorCode(404); - $errorResponse = $response->withStatus(404, $e->getMessage()); + $errorResponse = $response->withStatus(404, $e->getMessage())->withHeader('Content-Type', 'application/json'); $response->getBody()->write($this->builder->build()); return $errorResponse; @@ -166,7 +167,7 @@ class TaskController $this->builder->setOptionalMessage('Task deleted.'); $response->getBody()->write($this->builder->build()); - return $response; + return $response->withHeader('Content-Type', 'application/json'); } catch (TaskNotFoundException $exception) { @@ -175,7 +176,7 @@ class TaskController $errorResponse = $response->withStatus(404); $errorResponse->getBody()->write($this->builder->build()); - return $errorResponse; + return $errorResponse->withHeader('Content-Type', 'application/json'); } } diff --git a/src/Models/Task.php b/src/Models/Task.php index c1de1d5..6936be1 100644 --- a/src/Models/Task.php +++ b/src/Models/Task.php @@ -37,7 +37,7 @@ class Task public function __construct($status = TaskStatus::STARTED) { $this->statusId = $status; - + $this->createdAt = Carbon::now(); }