Make response stage additive

This commit is contained in:
shalvah
2019-10-10 00:37:35 +01:00
parent 4c0a753a62
commit 048f281fe1
9 changed files with 54 additions and 73 deletions

View File

@@ -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.

View File

@@ -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) {

View File

@@ -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];

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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";

View File

@@ -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

View File

@@ -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']];
}
}

View File

@@ -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);