Browse Source

Make response stage additive

shalvah 5 years ago
parent
commit
048f281fe1

+ 20 - 2
docs/plugins.md

@@ -142,9 +142,27 @@ Each strategy class must implement the __invoke method with the parameters as de
 - In the `bodyParameters` and `queryParameters` stages, you can return an array with arbitrary keys. These keys will serve as the names of your parameters. Array keys can be indicated with Laravel's dot notation. The value of each key should be an array with the following keys:
 
 ```
-'type', // Only used in bodyParameters
+'type', // Only valid in bodyParameters
 'description', 
 'required', // boolean
 'value', // An example value for the parameter
 ```
-- In the `responses` stage, your strategy should return an array containing the responses for different status codes. Each key in the array should be a HTTP status code, and each value should be a string containing the response.
+- In the `responses` stage, your strategy should return an array containing the responses for different status codes. Each item in the array should be an array representing the response with a `status` key containing the HTTP status code, and a `content` key a string containing the response. For example:
+
+```php
+
+    public function __invoke(Route $route, \ReflectionClass $controller, \ReflectionMethod $method, array $routeRules, array $context = [])
+    {
+        return [
+            [
+                'content' => "Haha",
+                'status' => 201
+            ],
+            [
+                'content' => "Nope",
+                'status' => 404
+            ],
+        ]
+    }
+```
+Responses are _additive_. This means all the responses returned from each stage are added together.

+ 6 - 1
src/Strategies/Responses/ResponseCalls.php

@@ -45,7 +45,12 @@ class ResponseCalls extends Strategy
 
         try {
             $response = $this->makeApiCall($request);
-            $response = [$response->getStatusCode() => $response->getContent()];
+            $response = [
+                [
+                'status' => $response->getStatusCode(),
+                'content' => $response->getContent()
+            ]
+            ];
         } catch (\Exception $e) {
             echo 'Exception thrown during response call for ['.implode(',', $route->methods)."] {$route->uri}.\n";
             if (Flags::$shouldBeVerbose) {

+ 10 - 4
src/Strategies/Responses/UseApiResourceTags.php

@@ -3,6 +3,7 @@
 namespace Mpociot\ApiDoc\Strategies\Responses;
 
 use Exception;
+use Illuminate\Http\Response;
 use ReflectionClass;
 use ReflectionMethod;
 use Illuminate\Support\Arr;
@@ -79,10 +80,15 @@ class UseApiResourceTags extends Strategy
                     : $apiResourceClass::collection(collect($models));
             }
 
+            /** @var Response $response */
+            $response = response()->json(
+                $resource->toArray(app(Request::class))
+            );
             return [
-                $statusCode => response()
-                    ->json($resource->toArray(app(Request::class)))
-                    ->getContent(),
+                [
+                    'status' => $statusCode ?: $response->getStatusCode(),
+                    'content' => $response->getContent(),
+                ],
             ];
         } catch (\Exception $e) {
             echo 'Exception thrown when fetching Eloquent API resource response for ['.implode(',', $route->methods)."] {$route->uri}.\n";
@@ -105,7 +111,7 @@ class UseApiResourceTags extends Strategy
     {
         $content = $tag->getContent();
         preg_match('/^(\d{3})?\s?([\s\S]*)$/', $content, $result);
-        $status = $result[1] ?: 200;
+        $status = $result[1] ?: 0;
         $apiResourceClass = $result[2];
 
         return [$status, $apiResourceClass];

+ 2 - 3
src/Strategies/Responses/UseResponseFileTag.php

@@ -60,10 +60,9 @@ class UseResponseFileTag extends Strategy
             $json = ! empty($result[3]) ? str_replace("'", '"', $result[3]) : '{}';
             $merged = array_merge(json_decode($content, true), json_decode($json, true));
 
-            return [json_encode($merged), (int) $status];
+            return ['content' => json_encode($merged), 'status' => (int) $status];
         }, $responseFileTags);
 
-        // Convert responses to [200 => 'response', 401 => 'response']
-        return collect($responses)->pluck('0', '1')->toArray();
+        return $responses;
     }
 }

+ 2 - 2
src/Strategies/Responses/UseResponseTag.php

@@ -58,10 +58,10 @@ class UseResponseTag extends Strategy
             $status = $result[1] ?: 200;
             $content = $result[2] ?: '{}';
 
-            return [$content, (int) $status];
+            return ['content' => $content, 'status' => (int) $status];
         }, $responseTags);
 
         // Convert responses to [200 => 'response', 401 => 'response']
-        return collect($responses)->pluck('0', '1')->toArray();
+        return $responses;
     }
 }

+ 5 - 2
src/Strategies/Responses/UseTransformerTags.php

@@ -73,9 +73,12 @@ class UseTransformerTags extends Strategy
                     new $transformer)
                 : new Item($modelInstance, new $transformer);
 
+            $response = response($fractal->createData($resource)->toJson());
             return [
-                $statusCode => response($fractal->createData($resource)->toJson())
-                    ->getContent(),
+                [
+                    'status' => $statusCode ?: $response->getStatusCode(),
+                    'content' => $response->getContent(),
+                ],
             ];
         } catch (\Exception $e) {
             echo 'Exception thrown when fetching transformer response for ['.implode(',', $route->methods)."] {$route->uri}.\n";

+ 6 - 6
src/Tools/Generator.php

@@ -117,12 +117,7 @@ class Generator
     {
         $responses = $this->iterateThroughStrategies('responses', $context, [$route, $controller, $method, $rulesToApply]);
         if (count($responses)) {
-            return collect($responses)->map(function (string $response, int $status) {
-                return [
-                    'status' => $status ?: 200,
-                    'content' => $response,
-                ];
-            })->values()->toArray();
+            return $responses;
         }
 
         return null;
@@ -161,6 +156,11 @@ class Generator
             $results = $strategy(...$arguments);
             if (! is_null($results)) {
                 foreach ($results as $index => $item) {
+                    if ($stage == "responses") {
+                        // Responses are additive
+                        $context[$stage][] = $item;
+                        continue;
+                    }
                     // Using a for loop rather than array_merge or +=
                     // so it does not renumber numeric keys
                     // and also allows values to be overwritten

+ 3 - 27
tests/Unit/GeneratorPluginSystemTestCase.php

@@ -126,24 +126,8 @@ class GeneratorPluginSystemTestCase extends LaravelGeneratorTest
     }
 
     /** @test */
-    public function overwrites_results_from_previous_strategies_in_same_stage()
+    public function overwrites_metadat_from_previous_strategies_in_same_stage()
     {
-        $config = [
-            'strategies' => [
-                'responses' => [DummyResponseStrategy200::class, StillDummyResponseStrategyAlso200::class],
-            ],
-        ];
-        $route = $this->createRoute('GET', '/api/test', 'dummy', true, TestController::class);
-        $generator = new Generator(new DocumentationConfig($config));
-        $parsed = $generator->processRoute($route);
-
-        $this->assertTrue($parsed['showresponse']);
-        $this->assertCount(1, $parsed['response']);
-        $first = array_shift($parsed['response']);
-        $this->assertTrue(is_array($first));
-        $this->assertEquals(200, $first['status']);
-        $this->assertEquals('stilldummy', $first['content']);
-
         $config = [
             'strategies' => [
                 'metadata' => [NotDummyMetadataStrategy::class, PartialDummyMetadataStrategy1::class],
@@ -241,15 +225,7 @@ class DummyResponseStrategy200 extends Strategy
 {
     public function __invoke(Route $route, ReflectionClass $controller, ReflectionMethod $method, array $routeRules, array $context = [])
     {
-        return [200 => 'dummy'];
-    }
-}
-
-class StillDummyResponseStrategyAlso200 extends Strategy
-{
-    public function __invoke(Route $route, ReflectionClass $controller, ReflectionMethod $method, array $routeRules, array $context = [])
-    {
-        return [200 => 'stilldummy'];
+        return [['status' => 200, 'content' => 'dummy']];
     }
 }
 
@@ -257,6 +233,6 @@ class DummyResponseStrategy400 extends Strategy
 {
     public function __invoke(Route $route, ReflectionClass $controller, ReflectionMethod $method, array $routeRules, array $context = [])
     {
-        return [400 => 'dummy2'];
+        return [['status' => 400, 'content' => 'dummy2']];
     }
 }

+ 0 - 26
tests/Unit/GeneratorTestCase.php

@@ -889,32 +889,6 @@ abstract class GeneratorTestCase extends TestCase
         $this->assertSame("This will be the long description.\nIt can also be multiple lines long.", $parsed['description']);
     }
 
-    /** @test */
-    public function combines_responses_from_different_strategies()
-    {
-        $route = $this->createRoute('GET', '/api/indexResource', 'index', true, TestResourceController::class);
-        $rules = [
-            'headers' => [
-                'Accept' => 'application/json',
-            ],
-            'response_calls' => [
-                'methods' => ['*'],
-            ],
-        ];
-
-        $parsed = $this->generator->processRoute($route, $rules);
-
-        $this->assertTrue(is_array($parsed));
-        $this->assertArrayHasKey('showresponse', $parsed);
-        $this->assertTrue($parsed['showresponse']);
-        $this->assertSame(1, count($parsed['response']));
-        $this->assertTrue(is_array($parsed['response'][0]));
-        $this->assertEquals(200, $parsed['response'][0]['status']);
-        $this->assertArraySubset([
-            'index_resource' => true,
-        ], json_decode($parsed['response'][0]['content'], true));
-    }
-
     abstract public function createRoute(string $httpMethod, string $path, string $controllerMethod, $register = false, $class = TestController::class);
 
     abstract public function createRouteUsesArray(string $httpMethod, string $path, string $controllerMethod, $register = false, $class = TestController::class);