Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Swagger API docs #105

Merged
merged 1 commit into from
Dec 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions app/config/swagger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

return [
'documentation' => [
'info' => [
'title' => 'Buggregator API',
'description' => '',
'version' => env('API_VERSION', '1.0.0'),
],
'components' => [
'schemas' => [
'ResponseMeta' => [
'type' => 'object',
'properties' => [
'grid' => [
'type' => 'object',
'properties' => [
// TODO: add grid meta
],
],
],
],
'NotFoundError' => [
'type' => 'object',
'properties' => [
'error' => [
'type' => 'string',
'example' => 'Http Error - 404',
],
'status' => [
'type' => 'integer',
'example' => 404,
],
],
],
'ValidationError' => [
'type' => 'object',
'properties' => [
'message' => [
'type' => 'string',
'example' => 'The given data was invalid.',
],
'code' => [
'type' => 'integer',
'example' => 433,
],
'errors' => [
'type' => 'object',
'properties' => [
'field' => [
'type' => 'string',
],
],
],
'context' => [
'type' => 'object',
],
],
],
],
],
],
'paths' => [
directory('app') . 'src/Application/HTTP/Response',
directory('app') . 'src/Interfaces/Http',
directory('app') . 'modules/Events/Interfaces/Http',
],
];
16 changes: 16 additions & 0 deletions app/modules/Events/Interfaces/Http/Controllers/ClearAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,23 @@
use Modules\Events\Interfaces\Http\Request\ClearEventsRequest;
use Spiral\Cqrs\CommandBusInterface;
use Spiral\Router\Annotation\Route;
use OpenApi\Attributes as OA;

#[OA\Delete(
path: '/api/events',
description: 'Clear all events',
requestBody: new OA\RequestBody(
content: new OA\JsonContent(ref: ClearEventsRequest::class),
),
tags: ['Events'],
responses: [
new OA\Response(
response: 200,
description: 'Success',
content: new OA\JsonContent(ref: SuccessResource::class),
),
]
)]
final class ClearAction
{
#[Route(route: 'events', name: 'events.clear', methods: 'DELETE', group: 'api')]
Expand Down
21 changes: 21 additions & 0 deletions app/modules/Events/Interfaces/Http/Controllers/DeleteAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,28 @@
use App\Application\HTTP\Response\SuccessResource;
use Spiral\Cqrs\CommandBusInterface;
use Spiral\Router\Annotation\Route;
use OpenApi\Attributes as OA;

#[OA\Delete(
path: '/api/event/{uuid}',
description: 'Delete an event by UUID',
tags: ['Events'],
parameters: [
new OA\PathParameter(
name: 'uuid',
description: 'Event UUID',
required: true,
schema: new OA\Schema(type: 'string', format: 'uuid'),
),
],
responses: [
new OA\Response(
response: 200,
description: 'Success',
content: new OA\JsonContent(ref: SuccessResource::class),
),
]
)]
final class DeleteAction
{
#[Route(route: 'event/<uuid>', name: 'event.delete', methods: 'DELETE', group: 'api')]
Expand Down
44 changes: 44 additions & 0 deletions app/modules/Events/Interfaces/Http/Controllers/ListAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,53 @@
use App\Application\Commands\FindEvents;
use Modules\Events\Interfaces\Http\Request\EventsRequest;
use Modules\Events\Interfaces\Http\Resources\EventCollection;
use Modules\Events\Interfaces\Http\Resources\EventResource;
use Spiral\Cqrs\QueryBusInterface;
use Spiral\Router\Annotation\Route;
use OpenApi\Attributes as OA;

#[OA\Get(
path: '/api/events',
description: 'Retrieve all events',
tags: ['Events'],
parameters: [
new OA\QueryParameter(
name: 'type',
description: 'Filter by event type',
required: false,
schema: new OA\Schema(type: 'string'),
),
],
responses: [
new OA\Response(
response: 200,
description: 'Success',
content: new OA\JsonContent(
properties: [
new OA\Property(
property: 'data',
type: 'array',
items: new OA\Items(
ref: EventResource::class,
),
),
new OA\Property(
property: 'meta',
ref: '#/components/schemas/ResponseMeta',
type: 'object',
),
],
),
),
new OA\Response(
response: 404,
description: 'Not found',
content: new OA\JsonContent(
ref: '#/components/schemas/NotFoundError',
),
),
]
)]
final class ListAction
{
#[Route(route: 'events', name: 'events.list', methods: 'GET', group: 'api')]
Expand Down
30 changes: 29 additions & 1 deletion app/modules/Events/Interfaces/Http/Controllers/ShowAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,43 @@
use Spiral\Cqrs\QueryBusInterface;
use Spiral\Http\Exception\ClientException\NotFoundException;
use Spiral\Router\Annotation\Route;
use OpenApi\Attributes as OA;

#[OA\Get(
path: '/api/event/{uuid}',
description: 'Retrieve an event by UUID',
tags: ['Events'],
parameters: [
new OA\PathParameter(
name: 'uuid',
description: 'Event UUID',
required: true,
schema: new OA\Schema(type: 'string', format: 'uuid'),
),
],
responses: [
new OA\Response(
response: 200,
description: 'Success',
content: new OA\JsonContent(ref: EventResource::class),
),
new OA\Response(
response: 404,
description: 'Not found',
content: new OA\JsonContent(
ref: '#/components/schemas/NotFoundError',
),
),
]
)]
final class ShowAction
{
#[Route(route: 'event/<uuid>', name: 'event.show', methods: 'GET', group: 'api')]
public function __invoke(QueryBusInterface $bus, Uuid $uuid): EventResource
{
try {
return new EventResource(
$bus->ask(new FindEventByUuid($uuid))
$bus->ask(new FindEventByUuid($uuid)),
);
} catch (EntityNotFoundException $e) {
throw new NotFoundException($e->getMessage());
Expand Down
11 changes: 11 additions & 0 deletions app/modules/Events/Interfaces/Http/Request/ClearEventsRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,20 @@
use Spiral\Filters\Model\FilterDefinitionInterface;
use Spiral\Filters\Model\HasFilterDefinition;
use Spiral\Validator\FilterDefinition;
use OpenApi\Attributes as OA;


#[OA\Schema(
schema: 'ClearEventsRequest',
)]
final class ClearEventsRequest extends Filter implements HasFilterDefinition
{
#[OA\Property(
property: 'type',
description: 'Event type',
type: 'string',
nullable: true,
)]
#[Data]
public ?string $type = null;

Expand Down
10 changes: 10 additions & 0 deletions app/modules/Events/Interfaces/Http/Resources/EventResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,20 @@

use App\Application\HTTP\Response\JsonResource;
use Modules\Events\Domain\Event;
use OpenApi\Attributes as OA;

/**
* @property-read Event $data
*/
#[OA\Schema(
schema: 'Event',
properties: [
new OA\Property(property: 'uuid', type: 'string', format: 'uuid'),
new OA\Property(property: 'type', type: 'string'),
new OA\Property(property: 'payload', description: 'Event payload based on type', type: 'object'),
new OA\Property(property: 'timestamp', type: 'float', example: 1630540800.12312),
],
)]
final class EventResource extends JsonResource
{
public function __construct(Event $data)
Expand Down
18 changes: 18 additions & 0 deletions app/src/Application/Bootloader/RoutesBootloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Spiral\Router\Bootloader\AnnotatedRoutesBootloader;
use Spiral\Router\GroupRegistry;
use Spiral\Router\Loader\Configurator\RoutingConfigurator;
use Spiral\OpenApi\Controller\DocumentationController;

final class RoutesBootloader extends BaseRoutesBootloader
{
Expand All @@ -31,7 +32,9 @@ protected function globalMiddleware(): array
protected function middlewareGroups(): array
{
return [
'web' => [],
'api' => [],
'docs' => [],
];
}

Expand All @@ -45,6 +48,21 @@ protected function configureRouteGroups(GroupRegistry $groups): void

protected function defineRoutes(RoutingConfigurator $routes): void
{
$routes
->add('swagger-api-html', '/api/docs')
->group('docs')
->action(DocumentationController::class, 'html');

$routes
->add('swagger-api-json', '/api/docs.json')
->group('docs')
->action(DocumentationController::class, 'json');

$routes
->add('swagger-api-yaml', '/api/docs.yaml')
->group('docs')
->action(DocumentationController::class, 'yaml');

$routes->default('/<path:.*>')
->group('web')
->action(EventHandlerAction::class, 'handle');
Expand Down
9 changes: 9 additions & 0 deletions app/src/Application/HTTP/Response/SuccessResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,18 @@

namespace App\Application\HTTP\Response;

use OpenApi\Attributes as OA;

/**
* @property-read bool $data
*/
#[OA\Schema(
schema: 'SuccessResource',
properties: [
new OA\Property(property: 'status', type: 'boolean'),
],
type: 'object'
)]
final class SuccessResource extends JsonResource
{
public function __construct(bool $status = true)
Expand Down
4 changes: 4 additions & 0 deletions app/src/Application/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use Spiral\Monolog\Bootloader\MonologBootloader;
use Spiral\Nyholm\Bootloader\NyholmBootloader;
use Spiral\RoadRunnerBridge\Bootloader as RoadRunnerBridge;
use Spiral\Stempler\Bootloader\StemplerBootloader;
use Spiral\Storage\Bootloader\StorageBootloader;
use Spiral\Tokenizer\Bootloader\TokenizerListenerBootloader;
use Spiral\Validation\Bootloader\ValidationBootloader;
Expand Down Expand Up @@ -61,6 +62,8 @@ protected function defineBootloaders(): array
ValidationBootloader::class,
ValidatorBootloader::class,

StemplerBootloader::class,

// HTTP extensions
NyholmBootloader::class,
Framework\Http\RouterBootloader::class,
Expand All @@ -86,6 +89,7 @@ protected function defineBootloaders(): array
RoadRunnerBridge\CommandBootloader::class,

// Configure route groups, middleware for route groups
\Spiral\OpenApi\Bootloader\SwaggerBootloader::class,
Bootloader\RoutesBootloader::class,

StorageBootloader::class,
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
"spiral/validator": "^1.1",
"symfony/mime": "^6.2",
"symfony/var-dumper": "^6.1",
"zbateson/mail-mime-parser": "^2.0"
"zbateson/mail-mime-parser": "^2.0",
"zentlix/swagger-php": "1.x-dev"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
Expand Down
Loading