Add support for `GET` requests
authorAlexander Ebert <ebert@woltlab.com>
Sat, 9 Mar 2024 23:47:38 +0000 (00:47 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Sun, 10 Mar 2024 14:19:39 +0000 (15:19 +0100)
wcfsetup/install/files/lib/action/ApiAction.class.php
wcfsetup/install/files/lib/system/endpoint/GetRequest.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/endpoint/PostRequest.class.php
wcfsetup/install/files/lib/system/endpoint/RequestMethod.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/endpoint/RequestType.class.php [new file with mode: 0644]

index 25e68c6370043c8a41c9989184f2e35049b58974..6ed0d5f479eec87e6c508b2bcc0cd6f2f2d6a816 100644 (file)
@@ -11,8 +11,10 @@ use wcf\system\endpoint\error\RouteParameterError;
 use wcf\system\endpoint\event\ControllerCollecting;
 use wcf\system\endpoint\exception\ControllerMalformed;
 use wcf\system\endpoint\exception\RouteParameterMismatch;
+use wcf\system\endpoint\GetRequest;
 use wcf\system\endpoint\IController;
 use wcf\system\endpoint\PostRequest;
+use wcf\system\endpoint\RequestType;
 use wcf\system\event\EventHandler;
 use wcf\system\request\RouteHandler;
 
@@ -20,6 +22,22 @@ final class ApiAction implements RequestHandlerInterface
 {
     public function handle(ServerRequestInterface $request): ResponseInterface
     {
+        $targetAttribute = match ($request->getMethod()) {
+            'GET' => GetRequest::class,
+            'POST' => PostRequest::class,
+            default => null,
+        };
+
+        if ($targetAttribute === null) {
+            // TODO: debug response
+            return new JsonResponse([
+                'type' => 'invalid_request_error',
+                'code' => 'method_not_allowed',
+                'message' => 'The only supported verbs are "GET", "POST" and "DELETE".',
+                'param' => '',
+            ], 405);
+        }
+
         $result = $this->parsePathInfo(RouteHandler::getPathInfo());
         if ($result === null) {
             \wcfDebug(RouteHandler::getPathInfo());
@@ -33,7 +51,7 @@ final class ApiAction implements RequestHandlerInterface
         $method = null;
         $matches = [];
         foreach ($event->getControllers() as $controller) {
-            $result = $this->findRequestedEndpoint($prefix, $endpoint, $controller);
+            $result = $this->findRequestedEndpoint($targetAttribute, $prefix, $endpoint, $controller);
             if ($result !== null) {
                 [$method, $matches] = $result;
 
@@ -147,15 +165,21 @@ final class ApiAction implements RequestHandlerInterface
     }
 
     /**
+     * @template T of RequestType
+     * @param class-string<T> $targetAttribute
      * @return array{\ReflectionMethod, array{string: string}}|null
      */
-    private function findRequestedEndpoint(string $prefix, string $endpoint, IController $controller): array|null
-    {
+    private function findRequestedEndpoint(
+        string $targetAttribute,
+        string $prefix,
+        string $endpoint,
+        IController $controller
+    ): array|null {
         $reflectionClass = new \ReflectionClass($controller);
         $publicMethods = $reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC);
 
         foreach ($publicMethods as $method) {
-            $reflectionAttribute = \current($method->getAttributes(PostRequest::class));
+            $reflectionAttribute = \current($method->getAttributes($targetAttribute));
             if ($reflectionAttribute === false) {
                 continue;
             }
@@ -179,7 +203,7 @@ final class ApiAction implements RequestHandlerInterface
         return null;
     }
 
-    private function getMatchesFromUri(PostRequest $request, string $endpoint): array|null
+    private function getMatchesFromUri(RequestType $request, string $endpoint): array|null
     {
         $segments = \explode('/', $request->uri);
 
diff --git a/wcfsetup/install/files/lib/system/endpoint/GetRequest.class.php b/wcfsetup/install/files/lib/system/endpoint/GetRequest.class.php
new file mode 100644 (file)
index 0000000..d222c22
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+
+namespace wcf\system\endpoint;
+
+#[\Attribute(\Attribute::TARGET_METHOD)]
+final class GetRequest extends RequestType
+{
+    public function __construct(string $uri)
+    {
+        parent::__construct(RequestMethod::GET, $uri);
+    }
+}
index 7dc196f5ceab8b12e79fcf3747acca9104b06a31..0d5ea6e4a46d982ebf98defcc5e587864a3d8597 100644 (file)
@@ -3,10 +3,10 @@
 namespace wcf\system\endpoint;
 
 #[\Attribute(\Attribute::TARGET_METHOD)]
-final class PostRequest
+final class PostRequest extends RequestType
 {
-    public function __construct(
-        public readonly string $uri,
-    ) {
+    public function __construct(string $uri)
+    {
+        parent::__construct(RequestMethod::POST, $uri);
     }
 }
diff --git a/wcfsetup/install/files/lib/system/endpoint/RequestMethod.class.php b/wcfsetup/install/files/lib/system/endpoint/RequestMethod.class.php
new file mode 100644 (file)
index 0000000..939211e
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+
+namespace wcf\system\endpoint;
+
+enum RequestMethod: string
+{
+    case GET = 'GET';
+    case POST = 'POST';
+}
diff --git a/wcfsetup/install/files/lib/system/endpoint/RequestType.class.php b/wcfsetup/install/files/lib/system/endpoint/RequestType.class.php
new file mode 100644 (file)
index 0000000..9003c21
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+
+namespace wcf\system\endpoint;
+
+abstract class RequestType
+{
+    public function __construct(
+        public readonly RequestMethod $method,
+        public readonly string $uri,
+    ) {
+    }
+}