mirror of
https://github.com/BookStackApp/BookStack.git
synced 2026-10-12 02:01:37 +00:00
API Docs: Added new endpoints to download docs as html/json
Had to rename underlying controller method to prevent name clashing.
This commit is contained in:
@@ -2,10 +2,22 @@
|
||||
|
||||
namespace BookStack\Api;
|
||||
|
||||
use BookStack\Entities\Tools\Markdown\HtmlToMarkdown;
|
||||
use BookStack\Http\ApiController;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ApiDocsController extends ApiController
|
||||
{
|
||||
protected static array $gettingStartedSectionsById = [
|
||||
'authentication' => 'Authentication',
|
||||
'request-format' => 'Request Format',
|
||||
'listing-endpoints' => 'Listing Endpoints',
|
||||
'error-handling' => 'Error Handling',
|
||||
'rate-limits' => 'Rate Limits',
|
||||
'content-security' => 'Content Security',
|
||||
];
|
||||
|
||||
/**
|
||||
* Load the docs page for the API.
|
||||
*/
|
||||
@@ -16,6 +28,7 @@ class ApiDocsController extends ApiController
|
||||
|
||||
return view('api-docs.index', [
|
||||
'docs' => $docs,
|
||||
'gettingStartedSections' => static::$gettingStartedSectionsById,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -29,10 +42,36 @@ class ApiDocsController extends ApiController
|
||||
return response()->json($docs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the API docs as a cleaner HTML file or as JSON with embedded HTML guidance.
|
||||
* Provide a ?format=json query parameter to download as JSON.
|
||||
*/
|
||||
public function download(Request $request)
|
||||
{
|
||||
$format = $request->query('format') ?? 'html';
|
||||
$docs = ApiDocsGenerator::generateConsideringCache();
|
||||
$downloadName = Str::slug(strtolower(setting('app-name')) . '-api-docs');
|
||||
|
||||
if ($format === 'json') {
|
||||
$docs->prepend(
|
||||
view('api-docs.parts.getting-started')->render(),
|
||||
'getting-started-guide'
|
||||
);
|
||||
return $this->createDownload()->directly(json_encode($docs), "{$downloadName}.json");
|
||||
}
|
||||
|
||||
$responseData = view('api-docs.download', [
|
||||
'docs' => $docs,
|
||||
'gettingStartedSections' => static::$gettingStartedSectionsById,
|
||||
])->render();
|
||||
|
||||
return $this->createDownload()->directly($responseData, "{$downloadName}.html");
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to the API docs page.
|
||||
* Required as a controller method, instead of the Route::redirect helper,
|
||||
* to ensure the URL is generated correctly.
|
||||
* Required as a controller method, instead of the Route::redirect helper,
|
||||
* to ensure the URL is generated correctly.
|
||||
*/
|
||||
public function redirect()
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ class BookExportApiController extends ApiController
|
||||
$book = $this->queries->findVisibleByIdOrFail($id);
|
||||
$pdfContent = $this->exportFormatter->bookToPdf($book);
|
||||
|
||||
return $this->download()->directly($pdfContent, $book->slug . '.pdf');
|
||||
return $this->createDownload()->directly($pdfContent, $book->slug . '.pdf');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +41,7 @@ class BookExportApiController extends ApiController
|
||||
$book = $this->queries->findVisibleByIdOrFail($id);
|
||||
$htmlContent = $this->exportFormatter->bookToContainedHtml($book);
|
||||
|
||||
return $this->download()->directly($htmlContent, $book->slug . '.html');
|
||||
return $this->createDownload()->directly($htmlContent, $book->slug . '.html');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +52,7 @@ class BookExportApiController extends ApiController
|
||||
$book = $this->queries->findVisibleByIdOrFail($id);
|
||||
$textContent = $this->exportFormatter->bookToPlainText($book);
|
||||
|
||||
return $this->download()->directly($textContent, $book->slug . '.txt');
|
||||
return $this->createDownload()->directly($textContent, $book->slug . '.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,7 +63,7 @@ class BookExportApiController extends ApiController
|
||||
$book = $this->queries->findVisibleByIdOrFail($id);
|
||||
$markdown = $this->exportFormatter->bookToMarkdown($book);
|
||||
|
||||
return $this->download()->directly($markdown, $book->slug . '.md');
|
||||
return $this->createDownload()->directly($markdown, $book->slug . '.md');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,6 +74,6 @@ class BookExportApiController extends ApiController
|
||||
$book = $this->queries->findVisibleByIdOrFail($id);
|
||||
$zip = $builder->buildForBook($book);
|
||||
|
||||
return $this->download()->streamedFileDirectly($zip, $book->slug . '.zip', true);
|
||||
return $this->createDownload()->streamedFileDirectly($zip, $book->slug . '.zip', true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ class BookExportController extends Controller
|
||||
$book = $this->queries->findVisibleBySlugOrFail($bookSlug);
|
||||
$pdfContent = $this->exportFormatter->bookToPdf($book);
|
||||
|
||||
return $this->download()->directly($pdfContent, $bookSlug . '.pdf');
|
||||
return $this->createDownload()->directly($pdfContent, $bookSlug . '.pdf');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,7 +43,7 @@ class BookExportController extends Controller
|
||||
$book = $this->queries->findVisibleBySlugOrFail($bookSlug);
|
||||
$htmlContent = $this->exportFormatter->bookToContainedHtml($book);
|
||||
|
||||
return $this->download()->directly($htmlContent, $bookSlug . '.html');
|
||||
return $this->createDownload()->directly($htmlContent, $bookSlug . '.html');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,7 +54,7 @@ class BookExportController extends Controller
|
||||
$book = $this->queries->findVisibleBySlugOrFail($bookSlug);
|
||||
$textContent = $this->exportFormatter->bookToPlainText($book);
|
||||
|
||||
return $this->download()->directly($textContent, $bookSlug . '.txt');
|
||||
return $this->createDownload()->directly($textContent, $bookSlug . '.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,7 +65,7 @@ class BookExportController extends Controller
|
||||
$book = $this->queries->findVisibleBySlugOrFail($bookSlug);
|
||||
$textContent = $this->exportFormatter->bookToMarkdown($book);
|
||||
|
||||
return $this->download()->directly($textContent, $bookSlug . '.md');
|
||||
return $this->createDownload()->directly($textContent, $bookSlug . '.md');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,6 +77,6 @@ class BookExportController extends Controller
|
||||
$book = $this->queries->findVisibleBySlugOrFail($bookSlug);
|
||||
$zip = $builder->buildForBook($book);
|
||||
|
||||
return $this->download()->streamedFileDirectly($zip, $bookSlug . '.zip', true);
|
||||
return $this->createDownload()->streamedFileDirectly($zip, $bookSlug . '.zip', true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ class ChapterExportApiController extends ApiController
|
||||
$chapter = $this->queries->findVisibleByIdOrFail($id);
|
||||
$pdfContent = $this->exportFormatter->chapterToPdf($chapter);
|
||||
|
||||
return $this->download()->directly($pdfContent, $chapter->slug . '.pdf');
|
||||
return $this->createDownload()->directly($pdfContent, $chapter->slug . '.pdf');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +41,7 @@ class ChapterExportApiController extends ApiController
|
||||
$chapter = $this->queries->findVisibleByIdOrFail($id);
|
||||
$htmlContent = $this->exportFormatter->chapterToContainedHtml($chapter);
|
||||
|
||||
return $this->download()->directly($htmlContent, $chapter->slug . '.html');
|
||||
return $this->createDownload()->directly($htmlContent, $chapter->slug . '.html');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +52,7 @@ class ChapterExportApiController extends ApiController
|
||||
$chapter = $this->queries->findVisibleByIdOrFail($id);
|
||||
$textContent = $this->exportFormatter->chapterToPlainText($chapter);
|
||||
|
||||
return $this->download()->directly($textContent, $chapter->slug . '.txt');
|
||||
return $this->createDownload()->directly($textContent, $chapter->slug . '.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,7 +63,7 @@ class ChapterExportApiController extends ApiController
|
||||
$chapter = $this->queries->findVisibleByIdOrFail($id);
|
||||
$markdown = $this->exportFormatter->chapterToMarkdown($chapter);
|
||||
|
||||
return $this->download()->directly($markdown, $chapter->slug . '.md');
|
||||
return $this->createDownload()->directly($markdown, $chapter->slug . '.md');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,6 +74,6 @@ class ChapterExportApiController extends ApiController
|
||||
$chapter = $this->queries->findVisibleByIdOrFail($id);
|
||||
$zip = $builder->buildForChapter($chapter);
|
||||
|
||||
return $this->download()->streamedFileDirectly($zip, $chapter->slug . '.zip', true);
|
||||
return $this->createDownload()->streamedFileDirectly($zip, $chapter->slug . '.zip', true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ class ChapterExportController extends Controller
|
||||
$chapter = $this->queries->findVisibleBySlugsOrFail($bookSlug, $chapterSlug);
|
||||
$pdfContent = $this->exportFormatter->chapterToPdf($chapter);
|
||||
|
||||
return $this->download()->directly($pdfContent, $chapterSlug . '.pdf');
|
||||
return $this->createDownload()->directly($pdfContent, $chapterSlug . '.pdf');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,7 +45,7 @@ class ChapterExportController extends Controller
|
||||
$chapter = $this->queries->findVisibleBySlugsOrFail($bookSlug, $chapterSlug);
|
||||
$containedHtml = $this->exportFormatter->chapterToContainedHtml($chapter);
|
||||
|
||||
return $this->download()->directly($containedHtml, $chapterSlug . '.html');
|
||||
return $this->createDownload()->directly($containedHtml, $chapterSlug . '.html');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,7 +58,7 @@ class ChapterExportController extends Controller
|
||||
$chapter = $this->queries->findVisibleBySlugsOrFail($bookSlug, $chapterSlug);
|
||||
$chapterText = $this->exportFormatter->chapterToPlainText($chapter);
|
||||
|
||||
return $this->download()->directly($chapterText, $chapterSlug . '.txt');
|
||||
return $this->createDownload()->directly($chapterText, $chapterSlug . '.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,7 +71,7 @@ class ChapterExportController extends Controller
|
||||
$chapter = $this->queries->findVisibleBySlugsOrFail($bookSlug, $chapterSlug);
|
||||
$chapterText = $this->exportFormatter->chapterToMarkdown($chapter);
|
||||
|
||||
return $this->download()->directly($chapterText, $chapterSlug . '.md');
|
||||
return $this->createDownload()->directly($chapterText, $chapterSlug . '.md');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,6 +83,6 @@ class ChapterExportController extends Controller
|
||||
$chapter = $this->queries->findVisibleBySlugsOrFail($bookSlug, $chapterSlug);
|
||||
$zip = $builder->buildForChapter($chapter);
|
||||
|
||||
return $this->download()->streamedFileDirectly($zip, $chapterSlug . '.zip', true);
|
||||
return $this->createDownload()->streamedFileDirectly($zip, $chapterSlug . '.zip', true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ class PageExportApiController extends ApiController
|
||||
$page = $this->queries->findVisibleByIdOrFail($id);
|
||||
$pdfContent = $this->exportFormatter->pageToPdf($page);
|
||||
|
||||
return $this->download()->directly($pdfContent, $page->slug . '.pdf');
|
||||
return $this->createDownload()->directly($pdfContent, $page->slug . '.pdf');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +41,7 @@ class PageExportApiController extends ApiController
|
||||
$page = $this->queries->findVisibleByIdOrFail($id);
|
||||
$htmlContent = $this->exportFormatter->pageToContainedHtml($page);
|
||||
|
||||
return $this->download()->directly($htmlContent, $page->slug . '.html');
|
||||
return $this->createDownload()->directly($htmlContent, $page->slug . '.html');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +52,7 @@ class PageExportApiController extends ApiController
|
||||
$page = $this->queries->findVisibleByIdOrFail($id);
|
||||
$textContent = $this->exportFormatter->pageToPlainText($page);
|
||||
|
||||
return $this->download()->directly($textContent, $page->slug . '.txt');
|
||||
return $this->createDownload()->directly($textContent, $page->slug . '.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,7 +63,7 @@ class PageExportApiController extends ApiController
|
||||
$page = $this->queries->findVisibleByIdOrFail($id);
|
||||
$markdown = $this->exportFormatter->pageToMarkdown($page);
|
||||
|
||||
return $this->download()->directly($markdown, $page->slug . '.md');
|
||||
return $this->createDownload()->directly($markdown, $page->slug . '.md');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,6 +74,6 @@ class PageExportApiController extends ApiController
|
||||
$page = $this->queries->findVisibleByIdOrFail($id);
|
||||
$zip = $builder->buildForPage($page);
|
||||
|
||||
return $this->download()->streamedFileDirectly($zip, $page->slug . '.zip', true);
|
||||
return $this->createDownload()->streamedFileDirectly($zip, $page->slug . '.zip', true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class PageExportController extends Controller
|
||||
$page->html = (new PageContent($page))->render();
|
||||
$pdfContent = $this->exportFormatter->pageToPdf($page);
|
||||
|
||||
return $this->download()->directly($pdfContent, $pageSlug . '.pdf');
|
||||
return $this->createDownload()->directly($pdfContent, $pageSlug . '.pdf');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,7 +49,7 @@ class PageExportController extends Controller
|
||||
$page->html = (new PageContent($page))->render();
|
||||
$containedHtml = $this->exportFormatter->pageToContainedHtml($page);
|
||||
|
||||
return $this->download()->directly($containedHtml, $pageSlug . '.html');
|
||||
return $this->createDownload()->directly($containedHtml, $pageSlug . '.html');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +62,7 @@ class PageExportController extends Controller
|
||||
$page = $this->queries->findVisibleBySlugsOrFail($bookSlug, $pageSlug);
|
||||
$pageText = $this->exportFormatter->pageToPlainText($page);
|
||||
|
||||
return $this->download()->directly($pageText, $pageSlug . '.txt');
|
||||
return $this->createDownload()->directly($pageText, $pageSlug . '.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,7 +75,7 @@ class PageExportController extends Controller
|
||||
$page = $this->queries->findVisibleBySlugsOrFail($bookSlug, $pageSlug);
|
||||
$pageText = $this->exportFormatter->pageToMarkdown($page);
|
||||
|
||||
return $this->download()->directly($pageText, $pageSlug . '.md');
|
||||
return $this->createDownload()->directly($pageText, $pageSlug . '.md');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,6 +87,6 @@ class PageExportController extends Controller
|
||||
$page = $this->queries->findVisibleBySlugsOrFail($bookSlug, $pageSlug);
|
||||
$zip = $builder->buildForPage($page);
|
||||
|
||||
return $this->download()->streamedFileDirectly($zip, $pageSlug . '.zip', true);
|
||||
return $this->createDownload()->streamedFileDirectly($zip, $pageSlug . '.zip', true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ abstract class Controller extends BaseController
|
||||
/**
|
||||
* Create and return a new download response factory using the current request.
|
||||
*/
|
||||
protected function download(): DownloadResponseFactory
|
||||
protected function createDownload(): DownloadResponseFactory
|
||||
{
|
||||
return new DownloadResponseFactory(request());
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class ThemeController extends Controller
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$response = $this->download()->streamedFileInline($filePath);
|
||||
$response = $this->createDownload()->streamedFileInline($filePath);
|
||||
$response->setMaxAge(86400);
|
||||
|
||||
return $response;
|
||||
|
||||
@@ -232,10 +232,10 @@ class AttachmentController extends Controller
|
||||
$attachmentSize = $this->attachmentService->getAttachmentFileSize($attachment);
|
||||
|
||||
if ($request->input('open') === 'true') {
|
||||
return $this->download()->streamedInline($attachmentStream, $fileName, $attachmentSize);
|
||||
return $this->createDownload()->streamedInline($attachmentStream, $fileName, $attachmentSize);
|
||||
}
|
||||
|
||||
return $this->download()->streamedDirectly($attachmentStream, $fileName, $attachmentSize);
|
||||
return $this->createDownload()->streamedDirectly($attachmentStream, $fileName, $attachmentSize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -253,6 +253,9 @@
|
||||
/**
|
||||
* API Docs
|
||||
*/
|
||||
.api-docs h2.list-heading {
|
||||
font-size: 1.666rem;
|
||||
}
|
||||
.api-method {
|
||||
font-size: 0.75rem;
|
||||
background-color: #888;
|
||||
@@ -282,11 +285,11 @@
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: #F2F2F2;
|
||||
background: linear-gradient(180deg,rgba(242, 242, 242, 1) 66%, rgba(242, 242, 242, 0) 100%);
|
||||
background: linear-gradient(180deg,rgba(242, 242, 242, 1) 80%, rgba(242, 242, 242, 0) 100%);
|
||||
z-index: 4;
|
||||
}
|
||||
}
|
||||
.dark-mode .sticky-sidebar-header {
|
||||
background: #111;
|
||||
background: linear-gradient(180deg,rgba(17, 17, 17, 1) 66%, rgba(17, 17, 17, 0) 100%);
|
||||
background: linear-gradient(180deg,rgba(17, 17, 17, 1) 80%, rgba(17, 17, 17, 0) 100%);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<title>{{ setting('app-name') }} API Docs</title>
|
||||
<style>
|
||||
body {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding-bottom: 2rem;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
h2 {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
table.table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.table th, table.table td {
|
||||
border: 1px solid #ccc;
|
||||
padding: 0.2em 0.4em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>{{ setting('app-name') }} API Documentation</h1>
|
||||
|
||||
<h2>Contents</h2>
|
||||
<ul>
|
||||
@foreach($gettingStartedSections as $id => $label)
|
||||
<li><a href="#{{ $id }}">{{ $label }}</a></li>
|
||||
@endforeach
|
||||
<li style="list-style: none">---</li>
|
||||
@foreach($docs as $model => $endpoints)
|
||||
<li><a href="#section-{{ str_replace(' ', '-', $model) }}">{{ $model }}</a></li>
|
||||
@endforeach
|
||||
</ul>
|
||||
|
||||
<section id="section-getting-started" component="code-highlighter" class="card content-wrap auto-height">
|
||||
@include('api-docs.parts.getting-started')
|
||||
</section>
|
||||
|
||||
@foreach($docs as $model => $endpoints)
|
||||
<section id="section-{{ str_replace(' ', '-', $model) }}" class="card content-wrap auto-height">
|
||||
<h2>{{ $model }}</h2>
|
||||
|
||||
@if($endpoints[0]['model_description'])
|
||||
<p>{{ $endpoints[0]['model_description'] }}</p>
|
||||
@endif
|
||||
|
||||
@foreach($endpoints as $endpoint)
|
||||
<div>
|
||||
<h3 id="{{ $endpoint['name'] }}">{{ $endpoint['name'] }}</h3>
|
||||
<p>{{ $endpoint['method'] }} {{ url($endpoint['uri']) }}</p>
|
||||
</div>
|
||||
@include('api-docs.parts.endpoint-details')
|
||||
@endforeach
|
||||
</section>
|
||||
@endforeach
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
@section('body')
|
||||
|
||||
<div component="api-nav" class="container">
|
||||
<div component="api-nav" class="container api-docs">
|
||||
|
||||
<div class="grid right-focus reverse-collapse">
|
||||
<div>
|
||||
|
||||
<div refs="api-nav@sidebar" class="sticky-sidebar">
|
||||
|
||||
<div class="sticky-sidebar-header py-xl">
|
||||
<div class="sticky-sidebar-header pt-xl pb-m">
|
||||
<select refs="api-nav@select" name="navigation" id="navigation">
|
||||
<option value="getting-started" selected>Jump To Section</option>
|
||||
<option value="getting-started">Getting Started</option>
|
||||
@@ -22,15 +22,17 @@
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="flex-container-row wrap gap-xs mb-s">
|
||||
<a href="{{ url('/api/docs/download?format=html') }}" title="Download API docs as HTML" class="button outline small">@icon('download')<span>HTML</span></a>
|
||||
<a href="{{ url('/api/docs/download?format=json') }}" title="Download API docs as JSON" class="button outline small">@icon('download')<span>JSON</span></a>
|
||||
</div>
|
||||
|
||||
<div class="mb-xl">
|
||||
<p id="sidebar-header-getting-started" class="text-uppercase text-muted mb-xm"><strong>Getting Started</strong></p>
|
||||
<div class="text-mono">
|
||||
<div class="mb-xs"><a href="#authentication">Authentication</a></div>
|
||||
<div class="mb-xs"><a href="#request-format">Request Format</a></div>
|
||||
<div class="mb-xs"><a href="#listing-endpoints">Listing Endpoints</a></div>
|
||||
<div class="mb-xs"><a href="#error-handling">Error Handling</a></div>
|
||||
<div class="mb-xs"><a href="#rate-limits">Rate Limits</a></div>
|
||||
<div class="mb-xs"><a href="#content-security">Content Security</a></div>
|
||||
@foreach($gettingStartedSections as $id => $label)
|
||||
<div class="mb-xs"><a href="#{{ $id }}">{{ $label }}</a></div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -61,7 +63,7 @@
|
||||
|
||||
@foreach($docs as $model => $endpoints)
|
||||
<section id="section-{{ str_replace(' ', '-', $model) }}" class="card content-wrap auto-height">
|
||||
<h1 class="list-heading text-capitals">{{ $model }}</h1>
|
||||
<h2 class="list-heading text-capitals">{{ $model }}</h2>
|
||||
@if($endpoints[0]['model_description'])
|
||||
<p>{{ $endpoints[0]['model_description'] }}</p>
|
||||
@endif
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<div class="mb-m">
|
||||
@foreach(explode("\n", $endpoint['description'] ?? '') as $descriptionBlock)
|
||||
<p class="mb-xxs">{{ $descriptionBlock }}</p>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
@if($endpoint['body_params'] ?? false)
|
||||
<details class="mb-m">
|
||||
<summary class="text-muted">{{ $endpoint['method'] === 'GET' ? 'Query' : 'Body' }} Parameters</summary>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Param Name</th>
|
||||
<th>Value Rules</th>
|
||||
</tr>
|
||||
@foreach($endpoint['body_params'] as $paramName => $rules)
|
||||
<tr>
|
||||
<td>{{ $paramName }}</td>
|
||||
<td>
|
||||
@foreach($rules as $rule)
|
||||
<code class="mr-xs">{{ $rule }}</code>
|
||||
@endforeach
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</table>
|
||||
</details>
|
||||
@endif
|
||||
|
||||
@if($endpoint['example_request'] ?? false)
|
||||
<details component="details-highlighter" class="mb-m">
|
||||
<summary class="text-muted">Example Request</summary>
|
||||
<pre><code class="language-json">{{ $endpoint['example_request'] }}</code></pre>
|
||||
</details>
|
||||
@endif
|
||||
|
||||
@if($endpoint['example_response'] ?? false)
|
||||
<details component="details-highlighter" class="mb-m">
|
||||
<summary class="text-muted">Example Response</summary>
|
||||
<pre><code class="language-json">{{ $endpoint['example_response'] }}</code></pre>
|
||||
</details>
|
||||
@endif
|
||||
@@ -10,47 +10,7 @@
|
||||
<h6 class="text-uppercase text-muted text-mono ml-auto">{{ $endpoint['controller_method_kebab'] }}</h6>
|
||||
</div>
|
||||
|
||||
<div class="mb-m">
|
||||
@foreach(explode("\n", $endpoint['description'] ?? '') as $descriptionBlock)
|
||||
<p class="mb-xxs">{{ $descriptionBlock }}</p>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
@if($endpoint['body_params'] ?? false)
|
||||
<details class="mb-m">
|
||||
<summary class="text-muted">{{ $endpoint['method'] === 'GET' ? 'Query' : 'Body' }} Parameters</summary>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Param Name</th>
|
||||
<th>Value Rules</th>
|
||||
</tr>
|
||||
@foreach($endpoint['body_params'] as $paramName => $rules)
|
||||
<tr>
|
||||
<td>{{ $paramName }}</td>
|
||||
<td>
|
||||
@foreach($rules as $rule)
|
||||
<code class="mr-xs">{{ $rule }}</code>
|
||||
@endforeach
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</table>
|
||||
</details>
|
||||
@endif
|
||||
|
||||
@if($endpoint['example_request'] ?? false)
|
||||
<details component="details-highlighter" class="mb-m">
|
||||
<summary class="text-muted">Example Request</summary>
|
||||
<pre><code class="language-json">{{ $endpoint['example_request'] }}</code></pre>
|
||||
</details>
|
||||
@endif
|
||||
|
||||
@if($endpoint['example_response'] ?? false)
|
||||
<details component="details-highlighter" class="mb-m">
|
||||
<summary class="text-muted">Example Response</summary>
|
||||
<pre><code class="language-json">{{ $endpoint['example_response'] }}</code></pre>
|
||||
</details>
|
||||
@endif
|
||||
@include('api-docs.parts.endpoint-details')
|
||||
|
||||
@if(!$loop->last)
|
||||
<hr>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<h1 class="list-heading text-capitals mb-l">Getting Started</h1>
|
||||
<h2 class="list-heading text-capitals mb-l">Getting Started</h2>
|
||||
|
||||
<p class="mb-none">
|
||||
This documentation covers use of the REST API. <br>
|
||||
|
||||
@@ -40,6 +40,7 @@ Route::middleware('auth')->group(function () {
|
||||
// API docs routes
|
||||
Route::get('/api', [ApiDocsController::class, 'redirect']);
|
||||
Route::get('/api/docs', [ApiDocsController::class, 'display']);
|
||||
Route::get('/api/docs/download', [ApiDocsController::class, 'download']);
|
||||
|
||||
Route::get('/pages/recently-updated', [EntityControllers\PageController::class, 'showRecentlyUpdated']);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user