scramble
scramble copied to clipboard
Wrong response structure for `$query->simplePaginate`
I have the following controller function:
/**
* Display a paginated list of News.
*
* @response LengthAwarePaginator<News>
*/
public function index(NewsListRequest $request): Paginator
{
$query = News::query();
if (Gate::check('news.viewall')) {
$query = $query->withTrashed();
}
return $query->simplePaginate($request->query('perPage', 10));
}
Scramble generates the following response structure:
{
"data": [
{
"id": 0,
"created_at": "string",
"updated_at": "string",
"deleted_at": "string",
"published_at": "string",
"status": "active",
"title": "string",
"content": "string",
"header_image": "string",
"author": {
"id": 0,
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"name": "string",
"email": "string",
"avatar_url": "string",
"status": "active"
}
}
],
"links": {
"first": "string",
"last": "string",
"prev": "string",
"next": "string"
},
"meta": {
"current_page": 0,
"from": 0,
"last_page": 0,
"links": [
{
"url": "string",
"label": "string",
"active": true
}
],
"path": "string",
"per_page": 0,
"to": 0,
"total": 0
}
}
which is wrong and should in fact be:
{
"current_page": 1,
"data": [],
"first_page_url": "http://localhost:8000/news?page=1",
"from": null,
"next_page_url": null,
"path": "http://localhost:8000/news",
"per_page": 10,
"prev_page_url": null,
"to": null
}
I created the following extension to workaround the problem:
<?php
namespace App\OpenApi;
use Dedoc\Scramble\Extensions\TypeToSchemaExtension;
use Dedoc\Scramble\Support\Generator\Response;
use Dedoc\Scramble\Support\Generator\Schema;
use Dedoc\Scramble\Support\Generator\Types\ArrayType;
use Dedoc\Scramble\Support\Generator\Types\IntegerType;
use Dedoc\Scramble\Support\Generator\Types\ObjectType as OpenApiObjectType;
use Dedoc\Scramble\Support\Generator\Types\StringType;
use Dedoc\Scramble\Support\Type\Generic;
use Dedoc\Scramble\Support\Type\Type;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\Log;
class SimplePaginationExtension extends TypeToSchemaExtension
{
public function shouldHandle(Type $type): bool
{
if (! ($type instanceof Generic)) {
return false;
}
return $type->name === Paginator::class;
}
public function toResponse(Type $type): Response
{
$collectingClassType = $type->templateTypes[0];
if (! $collectingClassType->isInstanceOf(JsonResource::class) && ! $collectingClassType->isInstanceOf(Model::class)) {
return null;
}
if (! ($collectingType = $this->openApiTransformer->transform($collectingClassType))) {
return null;
}
$type = new OpenApiObjectType;
$type->addProperty('current_page', new IntegerType);
$type->addProperty('data', (new ArrayType())->setItems($collectingType));
$type->addProperty('first_page_url', (new StringType)->nullable(true));
$type->addProperty('from', (new IntegerType)->nullable(true));
$type->addProperty('next_page_url', (new StringType)->nullable(true));
$type->addProperty('path', (new StringType)->nullable(true)->setDescription('Base path for paginator generated URLs.'));
$type->addProperty('prev_page_url', (new StringType)->nullable(true));
$type->addProperty('to', (new IntegerType)->nullable(true)->setDescription('Number of the last item in the slice.'));
$type->addProperty('per_page', (new IntegerType)->setDescription('Number of items shown per page.'));
$type->setRequired(['data', 'current_page', 'first_page_url', 'path', 'per_page', 'from', 'to']);
Log::info('schema', [Schema::fromType($type)]);
return Response::make(200)
->description('Simple paginated set of `' . $this->components->uniqueSchemaName($collectingClassType->name) . '`')
->setContent('application/json', Schema::fromType($type));
}
}
@axelrindle fixed in 0.11.17!