Skip to content

Commit

Permalink
Support streamed responses
Browse files Browse the repository at this point in the history
  • Loading branch information
shalvah committed Feb 25, 2025
1 parent 956e9bf commit 790ad94
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 4 deletions.
31 changes: 27 additions & 4 deletions src/Extracting/Strategies/Responses/ResponseCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use Exception;
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Http\UploadedFile;
use Illuminate\Routing\Route;
use Illuminate\Support\Facades\Config;
Expand All @@ -18,6 +17,8 @@
use Knuckles\Scribe\Tools\ErrorHandlingUtils as e;
use Knuckles\Scribe\Tools\Globals;
use Knuckles\Scribe\Tools\Utils;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;

/**
* Make a call to the route and retrieve its response.
Expand Down Expand Up @@ -89,7 +90,7 @@ public function makeResponseCall(ExtractedEndpointData $endpointData, array $set
$response = [
[
'status' => $response->getStatusCode(),
'content' => $response->getContent(),
'content' => $this->getContentFromResponse($response),
'headers' => $this->getResponseHeaders($response),
],
];
Expand Down Expand Up @@ -240,15 +241,15 @@ private function addBodyParameters(Request $request, array $body): void
*
* @param Route $route
*
* @return \Symfony\Component\HttpFoundation\Response
* @return Response
* @throws Exception
*/
protected function makeApiCall(Request $request, Route $route)
{
return $this->callLaravelRoute($request);
}

protected function callLaravelRoute(Request $request): \Symfony\Component\HttpFoundation\Response
protected function callLaravelRoute(Request $request): Response
{
/** @var \Illuminate\Foundation\Http\Kernel $kernel */
$kernel = app(Kernel::class);
Expand Down Expand Up @@ -323,4 +324,26 @@ public static function withSettings(
'cookies',
));
}

protected function getContentFromResponse(Response $response): string|false
{
if (!$response instanceof StreamedResponse) {
return $response->getContent();
}

// For streamed responses, the content is null, and only output directly via "echo" when we call "sendContent".
// We use output buffering to capture the output into a new fake response.
$renderedResponse = new Response('', $response->getStatusCode());
$originalCallback = $response->getCallback();
$response->setCallback(function () use ($originalCallback, $renderedResponse) {
ob_start(function ($output) use ($renderedResponse) {
$renderedResponse->setContent($output);
});
$originalCallback();
ob_end_flush();
});
$response->sendContent();
$renderedResponse->headers = $response->headers;
return $renderedResponse->getContent();
}
}
11 changes: 11 additions & 0 deletions tests/Fixtures/TestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,17 @@ public function shouldFetchRouteResponse()
];
}

public function withStreamedResponse()
{
function yieldItems() {
yield 'one';
yield 'two';
}
return response()->streamJson([
'items' => yieldItems(),
]);
}

public function echoesConfig()
{
return [
Expand Down
16 changes: 16 additions & 0 deletions tests/Strategies/Responses/ResponseCallsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,22 @@ public function does_not_make_response_call_if_success_response_already_gotten()
$this->assertNull($responses);
}

/** @test */
public function can_get_content_from_streamed_response()
{
$route = LaravelRouteFacade::post('/withStreamedResponse', [TestController::class, 'withStreamedResponse']);

$responses = $this->invokeStrategy($route);

$this->assertEquals(200, $responses[0]['status']);
$this->assertArraySubset([
'items' => [
'one',
'two',
]
], json_decode($responses[0]['content'], true));
}

protected function convertRules(array $rules): mixed
{
return Extractor::transformOldRouteRulesIntoNewSettings('responses', $rules, ResponseCalls::class);
Expand Down

0 comments on commit 790ad94

Please sign in to comment.