Skip to content

Commit

Permalink
Merge pull request #105 from buggregator/feature/71
Browse files Browse the repository at this point in the history
Adds Swagger API docs
  • Loading branch information
butschster authored Dec 2, 2023
2 parents 85c72d3 + 4b6e71d commit 80c57f9
Show file tree
Hide file tree
Showing 11 changed files with 232 additions and 2 deletions.
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

0 comments on commit 80c57f9

Please sign in to comment.