Skip to content

Commit

Permalink
API specification generation (#178)
Browse files Browse the repository at this point in the history
  • Loading branch information
romalytvynenko authored Jan 20, 2025
1 parent 28ae3f1 commit b8ea810
Show file tree
Hide file tree
Showing 16 changed files with 186 additions and 323 deletions.
46 changes: 46 additions & 0 deletions .github/workflows/build-api-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
on:
schedule:
- cron: '0 7 * * *'

env:
DOCS_REPOSITORY: cachethq/docs
DOCS_BRANCH: main

jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.3
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo

- name: Install dependencies
run: composer install

- name: Install Scramble PRO
run: |
composer config repositories.scramble-pro '{"type": "composer", "url": "https://satis.dedoc.co"}'
composer config http-basic.satis.dedoc.co ${{ secrets.SCRAMBLE_USERNAME }} ${{ secrets.SCRAMBLE_KEY }}
composer require dedoc/scramble-pro:0.7.0-alpha.1 --dev
- name: Checkout documentation repository
uses: actions/checkout@v4
with:
repository: ${{ env.DOCS_REPOSITORY }}
ref: ${{ env.DOCS_BRANCH }}
path: 'docs-repository'

- name: Build API docs
run: php vendor/bin/testbench scramble:export --path=docs-repository/api-reference/openapi.json

- name: Commit and push generated specification
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "Generated API specification from ${{ github.repository }}/${{ github.ref}}@${{ github.sha }}"
repository: "docs-repository"
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"twig/twig": "^3.0"
},
"require-dev": {
"dedoc/scramble": "0.12.0-alpha.1",
"larastan/larastan": "^3.0",
"laravel/pail": "^1.1",
"orchestra/testbench": "^9.5.1",
Expand Down
26 changes: 26 additions & 0 deletions src/CachetCoreServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
use Cachet\Models\Schedule;
use Cachet\Settings\AppSettings;
use Cachet\View\ViewManager;
use Dedoc\Scramble\Scramble;
use Dedoc\Scramble\Support\Generator\OpenApi;
use Dedoc\Scramble\Support\Generator\SecurityScheme;
use Cachet\Documentation\AddAuthenticationToOperation;
use Filament\Support\Colors\Color;
use Filament\Support\Facades\FilamentColor;
use Illuminate\Cache\RateLimiting\Limit;
Expand Down Expand Up @@ -73,6 +77,8 @@ public function boot(): void
FilamentColor::register([
'cachet' => Color::rgb('rgb(4, 193, 71)'),
]);

$this->configureScramble();
}

/**
Expand Down Expand Up @@ -192,4 +198,24 @@ private function registerSchedules(): void
$schedule->command('cachet:beacon')->daily();
});
}

/**
* Scramble is installed as dev dependency hence the class existence check.
*/
private function configureScramble(): void
{
if (! class_exists(Scramble::class)) {
return;
}

Scramble::afterOpenApiGenerated(function (OpenApi $openApi) {
$openApi->info->description = 'API documentation for Cachet, the open-source, self-hosted status page system.';

$openApi->secure(
SecurityScheme::http('bearer')
);
});

Scramble::registerExtension(AddAuthenticationToOperation::class);
}
}
20 changes: 20 additions & 0 deletions src/Documentation/AddAuthenticationToOperation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Cachet\Documentation;

use Dedoc\Scramble\Extensions\OperationExtension;
use Dedoc\Scramble\Support\Generator\Operation;
use Dedoc\Scramble\Support\RouteInfo;
use Illuminate\Support\Str;

class AddAuthenticationToOperation extends OperationExtension
{
public function handle(Operation $operation, RouteInfo $routeInfo)
{
$hasAuthMiddleware = collect($routeInfo->route->gatherMiddleware())->contains(fn ($m) => Str::startsWith($m, 'auth:'));

if (! $hasAuthMiddleware) {
$operation->addSecurity([]);
}
}
}
49 changes: 13 additions & 36 deletions src/Http/Controllers/Api/ComponentController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@
use Cachet\Concerns\GuardsApiAbilities;
use Cachet\Data\Requests\Component\CreateComponentRequestData;
use Cachet\Data\Requests\Component\UpdateComponentRequestData;
use Cachet\Enums\ComponentStatusEnum;
use Cachet\Http\Resources\Component as ComponentResource;
use Cachet\Http\Resources\Incident as IncidentResource;
use Cachet\Models\Component;
use Dedoc\Scramble\Attributes\Group;
use Dedoc\Scramble\Attributes\QueryParameter;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Http\Response;
use Illuminate\Pagination\Paginator;
use Illuminate\Routing\Controller;
use Spatie\QueryBuilder\AllowedFilter;
use Spatie\QueryBuilder\QueryBuilder;

/**
* @group Components
*/
#[Group('Components', weight: 1)]
class ComponentController extends Controller
{
use GuardsApiAbilities;
Expand All @@ -33,18 +37,13 @@ class ComponentController extends Controller
/**
* List Components
*
* @apiResourceCollection \Cachet\Http\Resources\Component
*
* @apiResourceModel \Cachet\Models\Component
*
* @queryParam per_page int How many items to show per page. Example: 20
* @queryParam page int Which page to show. Example: 2
* @queryParam sort Field to sort by. Enum: name, status, enabled. Example: name
* @queryParam include Include related resources. Enum: group, incidents. Example: group,incidents
* @queryParam filters[name] string Filter by name. Example: My Component
* @queryParam filters[status] Filter by status. Enum: 1 , 2, 3. Example: 1
* @queryParam filters[enabled] Filter by enabled status. Enum: 0, 1. Example: 1
* @response AnonymousResourceCollection<Paginator<ComponentResource>>
*/
#[QueryParameter('filter[status]', 'Filter by status', type: ComponentStatusEnum::class, example: 1)]
#[QueryParameter('filter[name]', 'Filter by name.', example: 'My Component')]
#[QueryParameter('filter[enabled]', 'Filter by enabled status.', type: 'bool', example: '1')]
#[QueryParameter('per_page', 'How many items to show per page.', type: 'int', default: 15, example: 20)]
#[QueryParameter('page', 'Which page to show.', type: 'int', example: 2)]
public function index()
{
$components = QueryBuilder::for(Component::class)
Expand All @@ -62,12 +61,6 @@ public function index()

/**
* Create Component
*
* @apiResource \Cachet\Http\Resources\Component
*
* @apiResourceModel \Cachet\Models\Component
*
* @authenticated
*/
public function store(CreateComponentRequestData $data, CreateComponent $createComponentAction)
{
Expand All @@ -82,12 +75,6 @@ public function store(CreateComponentRequestData $data, CreateComponent $createC

/**
* Get Component
*
* @apiResource \Cachet\Http\Resources\Component
*
* @apiResourceModel \Cachet\Models\Component
*
* @queryParam include Include related resources. Enum: group, incidents. Example: group,incidents
*/
public function show(Component $component)
{
Expand All @@ -102,12 +89,6 @@ public function show(Component $component)

/**
* Update Component
*
* @apiResource \Cachet\Http\Resources\Component
*
* @apiResourceModel \Cachet\Models\Component
*
* @authenticated
*/
public function update(UpdateComponentRequestData $data, Component $component, UpdateComponent $updateComponentAction)
{
Expand All @@ -120,10 +101,6 @@ public function update(UpdateComponentRequestData $data, Component $component, U

/**
* Delete Component
*
* @response 204
*
* @authenticated
*/
public function destroy(Component $component, DeleteComponent $deleteComponentAction)
{
Expand Down
43 changes: 8 additions & 35 deletions src/Http/Controllers/Api/ComponentGroupController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,26 @@
use Cachet\Data\Requests\ComponentGroup\UpdateComponentGroupRequestData;
use Cachet\Http\Resources\ComponentGroup as ComponentGroupResource;
use Cachet\Models\ComponentGroup;
use Dedoc\Scramble\Attributes\Group;
use Dedoc\Scramble\Attributes\QueryParameter;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Http\Response;
use Illuminate\Pagination\Paginator;
use Illuminate\Routing\Controller;
use Spatie\QueryBuilder\QueryBuilder;

/**
* @group Component Groups
*/
#[Group('Component Groups', weight: 2)]
class ComponentGroupController extends Controller
{
use GuardsApiAbilities;

/**
* List Component Groups
*
* @apiResource \Cachet\Http\Resources\ComponentGroup
*
* @apiResourceModel \Cachet\Models\ComponentGroup
*
* @queryParam per_page int How many items to show per page. Example: 20
* @queryParam page int Which page to show. Example: 2
* @queryParam sort Field to sort by. Enum: name, id. Example: name
* @queryParam include Include related resources. Enum: components. Example: components
* @response AnonymousResourceCollection<Paginator<ComponentGroupResource>>
*/
#[QueryParameter('per_page', 'How many items to show per page.', type: 'int', default: 15, example: 20)]
#[QueryParameter('page', 'Which page to show.', type: 'int', example: 2)]
public function index()
{
$componentGroups = QueryBuilder::for(ComponentGroup::class)
Expand All @@ -45,12 +42,6 @@ public function index()

/**
* Create Component Group
*
* @apiResource \Cachet\Http\Resources\ComponentGroup
*
* @apiResourceModel \Cachet\Models\ComponentGroup
*
* @authenticated
*/
public function store(CreateComponentGroupRequestData $data, CreateComponentGroup $createComponentGroupAction)
{
Expand All @@ -63,12 +54,6 @@ public function store(CreateComponentGroupRequestData $data, CreateComponentGrou

/**
* Get Component Group
*
* @apiResource \Cachet\Http\Resources\ComponentGroup
*
* @apiResourceModel \Cachet\Models\ComponentGroup
*
* @queryParam include Include related resources. Enum: components. Example: components
*/
public function show(ComponentGroup $componentGroup)
{
Expand All @@ -83,12 +68,6 @@ public function show(ComponentGroup $componentGroup)

/**
* Update Component Group
*
* @apiResource \Cachet\Http\Resources\ComponentGroup
*
* @apiResourceModel \Cachet\Models\ComponentGroup
*
* @authenticated
*/
public function update(UpdateComponentGroupRequestData $data, ComponentGroup $componentGroup, UpdateComponentGroup $updateComponentGroupAction)
{
Expand All @@ -101,12 +80,6 @@ public function update(UpdateComponentGroupRequestData $data, ComponentGroup $co

/**
* Delete Component Group
*
* @apiResource \Cachet\Http\Resources\ComponentGroup
*
* @apiResourceModel \Cachet\Models\ComponentGroup
*
* @authenticated
*/
public function destroy(ComponentGroup $componentGroup, DeleteComponentGroup $deleteComponentGroupAction)
{
Expand Down
16 changes: 3 additions & 13 deletions src/Http/Controllers/Api/GeneralController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,15 @@
namespace Cachet\Http\Controllers\Api;

use Cachet\Cachet;
use Dedoc\Scramble\Attributes\Group;
use Illuminate\Http\JsonResponse;
use Illuminate\Routing\Controller;

/**
* @group Cachet
*/
#[Group('Cachet', weight: 0)]
class GeneralController extends Controller
{
/**
* Test the API
*
* @response {
* "data": "Pong!"
* }
*/
public function ping(): JsonResponse
{
Expand All @@ -25,17 +20,12 @@ public function ping(): JsonResponse

/**
* Get Version
*
* @response {
* "data": {
* "version": "3.x-dev"
* }
* }
*/
public function version(): JsonResponse
{
return response()->json([
'data' => [
/** @var "'3.x-dev'" */
'version' => Cachet::version(),
],
]);
Expand Down
Loading

0 comments on commit b8ea810

Please sign in to comment.