parent
52da5b0e1d
commit
90296720d9
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
## Описание
|
## Описание
|
||||||
|
|
||||||
Данное руководство описывает процесс установки и настройки **Laravel Sanctum** для API аутентификации с использованием **wadakatu/laravel-spectrum** для генерации Swagger документации.
|
Данное руководство описывает процесс установки и настройки **Laravel Sanctum** для API аутентификации с использованием **wadakatu/laravel-spectrum** для автоматической генерации Swagger документации.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -38,7 +38,7 @@ composer require wadakatu/laravel-spectrum
|
||||||
# Публикация Sanctum
|
# Публикация Sanctum
|
||||||
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
|
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
|
||||||
|
|
||||||
# Публикация Spectrum
|
# Публикация Spectrum (если требуется)
|
||||||
php artisan vendor:publish --provider="Wadakatu\LaravelSpectrum\LaravelSpectrumServiceProvider"
|
php artisan vendor:publish --provider="Wadakatu\LaravelSpectrum\LaravelSpectrumServiceProvider"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -91,16 +91,16 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||||
health: '/up',
|
health: '/up',
|
||||||
)
|
)
|
||||||
->withMiddleware(function (Middleware $middleware): void {
|
->withMiddleware(function (Middleware $middleware): void {
|
||||||
$middleware->statefulApi();
|
//
|
||||||
})
|
})
|
||||||
->withExceptions(function (Exceptions $exceptions): void {
|
->withExceptions(function (Exceptions $exceptions): void {
|
||||||
//
|
//
|
||||||
})->create();
|
})->create();
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2.3 Конфигурация Sanctum
|
> **Важно:** Не используйте `statefulApi()` для чистого token-based API, это вызовет ошибку 419 CSRF.
|
||||||
|
|
||||||
Конфигурация находится в файле `config/sanctum.php`. Основные настройки:
|
### 2.3 Конфигурация Sanctum
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// config/sanctum.php
|
// config/sanctum.php
|
||||||
|
|
@ -153,7 +153,7 @@ app/
|
||||||
|
|
||||||
### 3.2 API Resources
|
### 3.2 API Resources
|
||||||
|
|
||||||
**UserResource** - форматирование данных пользователя:
|
**Laravel Spectrum** автоматически определяет структуру ответа из API Resources.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// app/Http/Resources/UserResource.php
|
// app/Http/Resources/UserResource.php
|
||||||
|
|
@ -178,8 +178,6 @@ class UserResource extends JsonResource
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**PostResource** - форматирование данных поста:
|
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// app/Http/Resources/PostResource.php
|
// app/Http/Resources/PostResource.php
|
||||||
|
|
||||||
|
|
@ -207,7 +205,7 @@ class PostResource extends JsonResource
|
||||||
|
|
||||||
### 3.3 Form Requests
|
### 3.3 Form Requests
|
||||||
|
|
||||||
**RegisterRequest** - валидация регистрации:
|
**Laravel Spectrum** автоматически определяет правила валидации из Form Requests.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// app/Http/Requests/RegisterRequest.php
|
// app/Http/Requests/RegisterRequest.php
|
||||||
|
|
@ -234,8 +232,6 @@ class RegisterRequest extends FormRequest
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**LoginRequest** - валидация входа:
|
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// app/Http/Requests/LoginRequest.php
|
// app/Http/Requests/LoginRequest.php
|
||||||
|
|
||||||
|
|
@ -260,8 +256,6 @@ class LoginRequest extends FormRequest
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**StorePostRequest** - валидация создания поста:
|
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// app/Http/Requests/StorePostRequest.php
|
// app/Http/Requests/StorePostRequest.php
|
||||||
|
|
||||||
|
|
@ -286,32 +280,6 @@ class StorePostRequest extends FormRequest
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**UpdatePostRequest** - валидация обновления поста:
|
|
||||||
|
|
||||||
```php
|
|
||||||
// app/Http/Requests/UpdatePostRequest.php
|
|
||||||
|
|
||||||
namespace App\Http\Requests;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
|
|
||||||
class UpdatePostRequest extends FormRequest
|
|
||||||
{
|
|
||||||
public function authorize(): bool
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function rules(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'title' => ['sometimes', 'string', 'max:255'],
|
|
||||||
'content' => ['sometimes', 'string'],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. API Endpoints
|
## 4. API Endpoints
|
||||||
|
|
@ -325,16 +293,22 @@ use App\Http\Controllers\Api\AuthController;
|
||||||
use App\Http\Controllers\Api\PostController;
|
use App\Http\Controllers\Api\PostController;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
// Swagger Documentation
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| API Routes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Swagger Documentation - редирект на Swagger UI
|
||||||
Route::get('/docs', function () {
|
Route::get('/docs', function () {
|
||||||
return redirect()->to('/docs/index.html');
|
return redirect()->to('/docs/index.html');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Public routes
|
// Public routes (без авторизации)
|
||||||
Route::post('/register', [AuthController::class, 'register'])->name('api.register');
|
Route::post('/register', [AuthController::class, 'register'])->name('api.register');
|
||||||
Route::post('/login', [AuthController::class, 'login'])->name('api.login');
|
Route::post('/login', [AuthController::class, 'login'])->name('api.login');
|
||||||
|
|
||||||
// Protected routes
|
// Protected routes (требуют авторизации)
|
||||||
Route::middleware('auth:sanctum')->group(function () {
|
Route::middleware('auth:sanctum')->group(function () {
|
||||||
// Auth
|
// Auth
|
||||||
Route::post('/logout', [AuthController::class, 'logout'])->name('api.logout');
|
Route::post('/logout', [AuthController::class, 'logout'])->name('api.logout');
|
||||||
|
|
@ -362,7 +336,7 @@ Route::middleware('auth:sanctum')->group(function () {
|
||||||
| GET | `/api/posts/{id}` | Просмотр поста | Да |
|
| GET | `/api/posts/{id}` | Просмотр поста | Да |
|
||||||
| PUT | `/api/posts/{id}` | Обновление поста | Да |
|
| PUT | `/api/posts/{id}` | Обновление поста | Да |
|
||||||
| DELETE | `/api/posts/{id}` | Удаление поста | Да |
|
| DELETE | `/api/posts/{id}` | Удаление поста | Да |
|
||||||
| GET | `/api/docs` | Swagger UI | Нет |
|
| GET | `/api/docs` | OpenAPI спецификация | Нет |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -370,8 +344,6 @@ Route::middleware('auth:sanctum')->group(function () {
|
||||||
|
|
||||||
### 5.1 Регистрация
|
### 5.1 Регистрация
|
||||||
|
|
||||||
**Запрос:**
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://la.test/api/register \
|
curl -X POST http://la.test/api/register \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
|
|
@ -383,26 +355,8 @@ curl -X POST http://la.test/api/register \
|
||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
|
|
||||||
**Ответ:**
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"message": "User registered successfully",
|
|
||||||
"user": {
|
|
||||||
"id": 1,
|
|
||||||
"name": "John Doe",
|
|
||||||
"email": "john@example.com",
|
|
||||||
"role": null,
|
|
||||||
"created_at": "2026-03-20T03:45:00.000000Z"
|
|
||||||
},
|
|
||||||
"token": "1|abc123..."
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5.2 Вход
|
### 5.2 Вход
|
||||||
|
|
||||||
**Запрос:**
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://la.test/api/login \
|
curl -X POST http://la.test/api/login \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
|
|
@ -412,26 +366,8 @@ curl -X POST http://la.test/api/login \
|
||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
|
|
||||||
**Ответ:**
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"message": "Login successful",
|
|
||||||
"user": {
|
|
||||||
"id": 1,
|
|
||||||
"name": "John Doe",
|
|
||||||
"email": "john@example.com",
|
|
||||||
"role": null,
|
|
||||||
"created_at": "2026-03-20T03:45:00.000000Z"
|
|
||||||
},
|
|
||||||
"token": "2|def456..."
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5.3 Создание поста
|
### 5.3 Создание поста
|
||||||
|
|
||||||
**Запрос:**
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://la.test/api/posts \
|
curl -X POST http://la.test/api/posts \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
|
|
@ -442,52 +378,7 @@ curl -X POST http://la.test/api/posts \
|
||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
|
|
||||||
**Ответ:**
|
### 5.4 Выход
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"message": "Post created successfully",
|
|
||||||
"post": {
|
|
||||||
"id": 1,
|
|
||||||
"title": "My First Post",
|
|
||||||
"content": "This is the content of my post.",
|
|
||||||
"user_id": 1,
|
|
||||||
"user": {
|
|
||||||
"id": 1,
|
|
||||||
"name": "John Doe",
|
|
||||||
"email": "john@example.com"
|
|
||||||
},
|
|
||||||
"created_at": "2026-03-20T03:50:00.000000Z",
|
|
||||||
"updated_at": "2026-03-20T03:50:00.000000Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5.4 Обновление поста
|
|
||||||
|
|
||||||
**Запрос:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -X PUT http://la.test/api/posts/1 \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-H "Authorization: Bearer {token}" \
|
|
||||||
-d '{
|
|
||||||
"title": "Updated Title"
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5.5 Удаление поста
|
|
||||||
|
|
||||||
**Запрос:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -X DELETE http://la.test/api/posts/1 \
|
|
||||||
-H "Authorization: Bearer {token}"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5.6 Выход
|
|
||||||
|
|
||||||
**Запрос:**
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://la.test/api/logout \
|
curl -X POST http://la.test/api/logout \
|
||||||
|
|
@ -500,302 +391,152 @@ curl -X POST http://la.test/api/logout \
|
||||||
|
|
||||||
### 6.1 Доступ к документации
|
### 6.1 Доступ к документации
|
||||||
|
|
||||||
Swagger UI доступен по адресу: `{APP_URL}/api/docs`
|
Документация Swagger UI доступна по адресу:
|
||||||
|
|
||||||
|
```
|
||||||
|
{APP_URL}/api/docs
|
||||||
|
```
|
||||||
|
|
||||||
Например: `http://la.test/api/docs`
|
Например: `http://la.test/api/docs`
|
||||||
|
|
||||||
### 6.2 Структура файлов документации
|
### 6.2 Генерация документации
|
||||||
|
|
||||||
|
Сначала сгенерируйте OpenAPI спецификацию:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php artisan spectrum:generate
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 Настройка доступа
|
||||||
|
|
||||||
|
Для работы Swagger UI необходимо:
|
||||||
|
|
||||||
|
**1. Создать символическую ссылку:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ln -sf /home/user/www/lara/storage/app/spectrum /home/user/www/lara/public/spectrum
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. Создать HTML файл Swagger UI:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- public/docs/index.html -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>API Documentation - Swagger UI</title>
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="swagger-ui"></div>
|
||||||
|
<script src="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui-bundle.js"></script>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
SwaggerUIBundle({
|
||||||
|
url: "/spectrum/openapi.json",
|
||||||
|
dom_id: '#swagger-ui',
|
||||||
|
presets: [
|
||||||
|
SwaggerUIBundle.presets.apis
|
||||||
|
],
|
||||||
|
docExpansion: "list",
|
||||||
|
persistAuthorization: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.4 Файлы документации
|
||||||
|
|
||||||
```
|
```
|
||||||
public/
|
public/
|
||||||
└── docs/
|
└── docs/
|
||||||
├── index.html # Swagger UI
|
└── index.html # Swagger UI
|
||||||
└── openapi.yaml # OpenAPI спецификация
|
|
||||||
|
storage/
|
||||||
|
└── app/
|
||||||
|
└── spectrum/
|
||||||
|
└── openapi.json # OpenAPI спецификация
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6.3 Обновление документации
|
### 6.5 Маршрут для документации
|
||||||
|
|
||||||
После добавления новых endpointов перегенерируйте документацию:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
php artisan swagger:generate
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6.4 Конфигурация Spectrum
|
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// config/spectrum.php
|
// routes/api.php
|
||||||
|
|
||||||
return [
|
// Swagger Documentation
|
||||||
'output' => 'public/docs',
|
Route::get('/docs', function () {
|
||||||
'title' => env('APP_NAME', 'Laravel API'),
|
return redirect()->to('/docs/index.html');
|
||||||
'description' => 'API Documentation',
|
});
|
||||||
'version' => '1.0.0',
|
|
||||||
'server_url' => env('APP_URL'),
|
|
||||||
'servers' => [
|
|
||||||
['url' => env('APP_URL'), 'description' => 'Local server'],
|
|
||||||
],
|
|
||||||
'security_schemes' => [
|
|
||||||
'bearerAuth' => [
|
|
||||||
'type' => 'http',
|
|
||||||
'scheme' => 'bearer',
|
|
||||||
'bearerFormat' => 'JWT',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'default_security_scheme' => 'bearerAuth',
|
|
||||||
'paths' => [
|
|
||||||
'controllers' => ['App\\Http\\Controllers\\Api\\'],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. Команды Artisan
|
## 7. Команды Laravel Spectrum
|
||||||
|
|
||||||
### 7.1 Создание пользовательской команды
|
### 7.1 Основные команды
|
||||||
|
|
||||||
#### Структура директорий
|
Laravel Spectrum поставляется с готовыми командами для работы с документацией.
|
||||||
|
|
||||||
Команды Artisan располагаются в директории `app/Console/Commands/`:
|
|
||||||
|
|
||||||
```
|
|
||||||
app/
|
|
||||||
├── Console/
|
|
||||||
│ └── Commands/
|
|
||||||
│ └── GenerateSwagger.php # Наша команда
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Создание команды
|
|
||||||
|
|
||||||
**1. Создайте директорию Commands:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mkdir -p app/Console/Commands
|
|
||||||
```
|
|
||||||
|
|
||||||
**2. Создайте файл команды:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# app/Console/Commands/GenerateSwagger.php
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Пример кода команды
|
|
||||||
|
|
||||||
```php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
|
||||||
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
use Illuminate\Support\Facades\File;
|
|
||||||
use Symfony\Component\Yaml\Yaml;
|
|
||||||
|
|
||||||
class GenerateSwagger extends Command
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Имя и сигнатура команды.
|
|
||||||
* Используется для вызова: php artisan swagger:generate
|
|
||||||
*/
|
|
||||||
protected $signature = 'swagger:generate';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Описание команды.
|
|
||||||
* Показывается в списке команд: php artisan list
|
|
||||||
*/
|
|
||||||
protected $description = 'Generate OpenAPI specification for the API';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Метод execute() - основная логика команды.
|
|
||||||
* Вызывается при выполнении команды.
|
|
||||||
*/
|
|
||||||
public function handle(): int
|
|
||||||
{
|
|
||||||
// Вывод информационного сообщения
|
|
||||||
$this->info('Generating OpenAPI specification...');
|
|
||||||
|
|
||||||
// Создание директории для документации
|
|
||||||
$outputDir = public_path('docs');
|
|
||||||
if (!File::exists($outputDir)) {
|
|
||||||
File::makeDirectory($outputDir, 0755, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Генерация спецификации
|
|
||||||
$spec = $this->generateSpec();
|
|
||||||
|
|
||||||
// Конвертация в YAML формат
|
|
||||||
$yaml = Yaml::dump($spec, 4, 2);
|
|
||||||
|
|
||||||
// Сохранение файла
|
|
||||||
File::put($outputDir . '/openapi.yaml', $yaml);
|
|
||||||
$this->info('OpenAPI specification saved to public/docs/openapi.yaml');
|
|
||||||
|
|
||||||
// Возврат кода успеха
|
|
||||||
return Command::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Метод для генерации структуры OpenAPI спецификации.
|
|
||||||
* Можно создавать YAML или JSON вручную.
|
|
||||||
*/
|
|
||||||
protected function generateSpec(): array
|
|
||||||
{
|
|
||||||
$appUrl = config('app.url', 'http://localhost');
|
|
||||||
|
|
||||||
return [
|
|
||||||
'openapi' => '3.0.0',
|
|
||||||
'info' => [
|
|
||||||
'title' => config('app.name', 'Laravel API'),
|
|
||||||
'description' => 'API Documentation',
|
|
||||||
'version' => '1.0.0',
|
|
||||||
],
|
|
||||||
'servers' => [
|
|
||||||
['url' => $appUrl, 'description' => 'Local server'],
|
|
||||||
],
|
|
||||||
'paths' => $this->generatePaths(),
|
|
||||||
'components' => [
|
|
||||||
'securitySchemes' => [
|
|
||||||
'bearerAuth' => [
|
|
||||||
'type' => 'http',
|
|
||||||
'scheme' => 'bearer',
|
|
||||||
'bearerFormat' => 'JWT',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Генерация секции paths для OpenAPI.
|
|
||||||
*/
|
|
||||||
protected function generatePaths(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'/api/register' => [
|
|
||||||
'post' => [
|
|
||||||
'tags' => ['Auth'],
|
|
||||||
'summary' => 'Register a new user',
|
|
||||||
// ... описание endpoint
|
|
||||||
],
|
|
||||||
],
|
|
||||||
// ... другие endpoints
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Основные компоненты команды
|
|
||||||
|
|
||||||
| Компонент | Описание |
|
|
||||||
|----------|----------|
|
|
||||||
| `$signature` | Имя команды (например, `swagger:generate`) |
|
|
||||||
| `$description` | Описание для списка команд |
|
|
||||||
| `handle()` | Основной метод выполнения команды |
|
|
||||||
| `$this->info()` | Вывод информационного сообщения |
|
|
||||||
| `$this->error()` | Вывод сообщения об ошибке |
|
|
||||||
| `$this->warn()` | Вывод предупреждения |
|
|
||||||
| `$this->question()` | Вывод вопроса |
|
|
||||||
| `Command::SUCCESS` | Код успешного завершения |
|
|
||||||
| `Command::FAILURE` | Код неудачного завершения |
|
|
||||||
|
|
||||||
#### Методы для взаимодействия с пользователем
|
|
||||||
|
|
||||||
```php
|
|
||||||
// Вывод текста
|
|
||||||
$this->info('Сообщение'); // Зеленый текст
|
|
||||||
$this->error('Ошибка'); // Красный текст
|
|
||||||
$this->warn('Внимание'); // Желтый текст
|
|
||||||
$this->line('Текст'); // Обычный текст
|
|
||||||
|
|
||||||
// Запрос подтверждения
|
|
||||||
if ($this->confirm('Продолжить?')) {
|
|
||||||
// пользователь ответил "да"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Выбор из списка
|
|
||||||
$choice = $this->choice('Выберите:', ['opt1', 'opt2', 'opt3'], 0);
|
|
||||||
|
|
||||||
// Ввод текста
|
|
||||||
$name = $this->ask('Введите имя:');
|
|
||||||
$password = $this->secret('Введите пароль:'); // Скрытый ввод
|
|
||||||
|
|
||||||
// Прогресс-бар
|
|
||||||
$bar = $this->output->createProgressBar(100);
|
|
||||||
$bar->start();
|
|
||||||
foreach ($items as $item) {
|
|
||||||
// обработка
|
|
||||||
$bar->advance();
|
|
||||||
}
|
|
||||||
$bar->finish();
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7.2 Список команд
|
|
||||||
|
|
||||||
| Команда | Описание |
|
| Команда | Описание |
|
||||||
|---------|----------|
|
|---------|----------|
|
||||||
| `php artisan swagger:generate` | Генерация OpenAPI спецификации |
|
| `php artisan spectrum:generate` | Генерация OpenAPI документации |
|
||||||
| `php artisan list` | Список всех команд |
|
| `php artisan spectrum:watch` | Режим реального времени (port 8080) |
|
||||||
| `php artisan list api` | Список команд содержащих "api" |
|
| `php artisan spectrum:mock` | Запуск mock сервера (port 8081) |
|
||||||
|
| `php artisan spectrum:cache clear` | Очистка кэша анализа |
|
||||||
|
|
||||||
### 7.3 Пример использования
|
### 7.2 Генерация документации
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Генерация документации
|
# Генерация документации
|
||||||
php artisan swagger:generate
|
php artisan spectrum:generate
|
||||||
|
|
||||||
# Очистка кэша конфигурации
|
|
||||||
php artisan config:clear
|
|
||||||
|
|
||||||
# Очистка кэша маршрутов
|
|
||||||
php artisan route:clear
|
|
||||||
|
|
||||||
# Просмотр списка команд
|
|
||||||
php artisan list
|
|
||||||
|
|
||||||
# Справка по команде
|
|
||||||
php artisan swagger:generate --help
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7.4 Автоматическая регистрация
|
**Вывод:**
|
||||||
|
```
|
||||||
|
🚀 Generating API documentation...
|
||||||
|
🔍 Analyzing routes...
|
||||||
|
Found 9 API routes
|
||||||
|
📝 Generating OpenAPI specification...
|
||||||
|
✅ Documentation generated: /home/user/www/lara/storage/app/spectrum/openapi.json
|
||||||
|
⏱️ Generation completed in 0.17 seconds
|
||||||
|
💾 Cache: 5 files, 7.04 KB
|
||||||
|
✅ Documentation generated successfully!
|
||||||
|
```
|
||||||
|
|
||||||
Laravel автоматически обнаруживает команды в директории `app/Console/Commands`.
|
### 7.3 Режим реального времени
|
||||||
Для ручной регистрации добавьте в `app/Console/Kernel.php`:
|
|
||||||
|
|
||||||
```php
|
```bash
|
||||||
// app/Console/Kernel.php
|
# Запуск режима watch
|
||||||
|
php artisan spectrum:watch
|
||||||
|
```
|
||||||
|
|
||||||
namespace App\Console;
|
- Запускает локальный сервер на `http://localhost:8080`
|
||||||
|
- Автоматически обнаруживает изменения в файлах
|
||||||
|
- Обновляет документацию в реальном времени
|
||||||
|
|
||||||
use Illuminate\Console\Scheduling\Schedule;
|
### 7.4 Mock сервер
|
||||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
|
||||||
|
|
||||||
class Kernel extends ConsoleKernel
|
```bash
|
||||||
{
|
# Запуск mock API сервера
|
||||||
/**
|
php artisan spectrum:mock
|
||||||
* The Artisan commands provided by your application.
|
```
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $commands = [
|
|
||||||
Commands\GenerateSwagger::class,
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
- Запускает mock сервер на `http://localhost:8081`
|
||||||
* Define the application's command schedule.
|
- Генерирует моковые данные на основе спецификации
|
||||||
*/
|
- Позволяет тестировать API без реального бэкенда
|
||||||
protected function schedule(Schedule $schedule): void
|
|
||||||
{
|
|
||||||
// $schedule->command('swagger:generate')->daily();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
### 7.5 Обновление документации
|
||||||
* Register the commands for the application.
|
|
||||||
*/
|
После добавления новых endpointов:
|
||||||
protected function commands(): void
|
|
||||||
{
|
```bash
|
||||||
$this->load(__DIR__.'/Commands');
|
# Очистить кэш и перегенерировать
|
||||||
}
|
php artisan spectrum:cache clear
|
||||||
}
|
php artisan spectrum:generate
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -828,13 +569,14 @@ class PostPolicy
|
||||||
|
|
||||||
### 8.2 Регистрация политики
|
### 8.2 Регистрация политики
|
||||||
|
|
||||||
|
Политики автоматически обнаруживаются Laravel. Для ручной регистрации:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// app/Providers/AuthServiceProvider.php
|
// app/Providers/AuthServiceProvider.php
|
||||||
|
|
||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
use App\Models\Post;
|
use App\Models\Post;
|
||||||
use App\Models\User;
|
|
||||||
use App\Policies\PostPolicy;
|
use App\Policies\PostPolicy;
|
||||||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
||||||
|
|
||||||
|
|
@ -855,8 +597,6 @@ class AuthServiceProvider extends ServiceProvider
|
||||||
|
|
||||||
## 9. Конфигурация .env
|
## 9. Конфигурация .env
|
||||||
|
|
||||||
Убедитесь, что в файле `.env` указаны правильные настройки:
|
|
||||||
|
|
||||||
```env
|
```env
|
||||||
APP_NAME=Laravel
|
APP_NAME=Laravel
|
||||||
APP_ENV=local
|
APP_ENV=local
|
||||||
|
|
@ -866,30 +606,21 @@ APP_URL=http://la.test
|
||||||
DB_CONNECTION=sqlite
|
DB_CONNECTION=sqlite
|
||||||
|
|
||||||
SESSION_DRIVER=database
|
SESSION_DRIVER=database
|
||||||
SANCTUM_STATEFUL_DOMAINS=la.test,localhost,127.0.0.1
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10. Тестирование API
|
## 10. Тестирование
|
||||||
|
|
||||||
### 10.1 Примеры запросов в Swagger UI
|
|
||||||
|
|
||||||
1. Откройте `http://la.test/api/docs`
|
|
||||||
2. Нажмите **Authorize** и введите ваш token
|
|
||||||
3. Тестируйте endpoints прямо в браузере
|
|
||||||
|
|
||||||
### 10.2 Ручное тестирование
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Проверка списка маршрутов
|
# Проверка списка маршрутов
|
||||||
php artisan route:list
|
php artisan route:list --path=api
|
||||||
|
|
||||||
|
# Генерация документации
|
||||||
|
php artisan spectrum:generate
|
||||||
|
|
||||||
# Запуск сервера
|
# Запуск сервера
|
||||||
php artisan serve --host=la.test
|
php artisan serve
|
||||||
|
|
||||||
# Запуск тестов
|
|
||||||
php artisan test
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -899,26 +630,31 @@ php artisan test
|
||||||
### Проблема: 401 Unauthorized
|
### Проблема: 401 Unauthorized
|
||||||
|
|
||||||
**Решение:**
|
**Решение:**
|
||||||
1. Убедитесь, что передаёте правильный токен в заголовке `Authorization`
|
1. Проверьте токен в заголовке `Authorization: Bearer {token}`
|
||||||
2. Проверьте срок действия токена
|
2. Убедитесь, что используете префикс `Bearer`
|
||||||
3. Убедитесь, что используете префикс `Bearer`
|
|
||||||
|
|
||||||
### Проблема: CSRF token mismatch
|
### Проблема: 419 CSRF Error
|
||||||
|
|
||||||
**Решение:**
|
**Решение:**
|
||||||
Для SPA приложений добавьте домен в `SANCTUM_STATEFUL_DOMAINS`:
|
Уберите `statefulApi()` из middleware в `bootstrap/app.php`:
|
||||||
|
|
||||||
```env
|
```php
|
||||||
SANCTUM_STATEFUL_DOMAINS=la.test,localhost,127.0.0.1
|
->withMiddleware(function (Middleware $middleware): void {
|
||||||
|
// Не используйте statefulApi() для token-based API
|
||||||
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
### Проблема: Таблица уже существует
|
### Проблема: Rate limiter not defined
|
||||||
|
|
||||||
**Решение:**
|
**Решение:**
|
||||||
Если миграция `personal_access_tokens` уже выполнена, пропустите её:
|
Не используйте `throttleApi()`:
|
||||||
|
|
||||||
```bash
|
```php
|
||||||
php artisan migrate --path=/database/migrations/2026_03_20_032532_create_personal_access_tokens_table.php --skip
|
// Неправильно
|
||||||
|
$middleware->throttleApi();
|
||||||
|
|
||||||
|
// Правильно (оставить пустым или удалить)
|
||||||
|
$middleware->api();
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -926,13 +662,18 @@ php artisan migrate --path=/database/migrations/2026_03_20_032532_create_persona
|
||||||
## Заключение
|
## Заключение
|
||||||
|
|
||||||
Теперь у вас есть полностью настроенный API с:
|
Теперь у вас есть полностью настроенный API с:
|
||||||
- ✅ Laravel Sanctum для аутентификации
|
|
||||||
- ✅ Token-based авторизация
|
|
||||||
- ✅ API Resources для форматирования ответов
|
|
||||||
- ✅ Form Requests для валидации
|
|
||||||
- ✅ Swagger документация по адресу `/api/docs`
|
|
||||||
- ✅ Политики доступа для постов
|
|
||||||
|
|
||||||
Для получения дополнительной информации обратитесь к официальной документации:
|
- ✅ **Laravel Sanctum** - аутентификация через токены
|
||||||
- [Laravel Sanctum](https://laravel.com/docs/sanctum)
|
- ✅ **wadakatu/laravel-spectrum** - автоматическая генерация Swagger документации
|
||||||
- [wadakatu/laravel-spectrum](https://github.com/wadakatu/laravel-spectrum)
|
- ✅ **API Resources** - форматирование ответов
|
||||||
|
- ✅ **Form Requests** - валидация
|
||||||
|
- ✅ **Swagger документация** - `/api/docs`
|
||||||
|
|
||||||
|
**Команды для работы:**
|
||||||
|
```bash
|
||||||
|
php artisan spectrum:generate # Генерация документации
|
||||||
|
php artisan spectrum:watch # Режим разработки
|
||||||
|
php artisan spectrum:mock # Mock сервер
|
||||||
|
```
|
||||||
|
|
||||||
|
**Документация:** `http://la.test/api/docs`
|
||||||
|
|
|
||||||
|
|
@ -1,252 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
|
||||||
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
use Illuminate\Support\Facades\File;
|
|
||||||
use Symfony\Component\Yaml\Yaml;
|
|
||||||
|
|
||||||
class GenerateSwagger extends Command
|
|
||||||
{
|
|
||||||
protected $signature = 'swagger:generate';
|
|
||||||
protected $description = 'Generate OpenAPI specification for the API';
|
|
||||||
|
|
||||||
public function handle(): int
|
|
||||||
{
|
|
||||||
$this->info('Generating OpenAPI specification...');
|
|
||||||
|
|
||||||
$outputDir = public_path('docs');
|
|
||||||
if (!File::exists($outputDir)) {
|
|
||||||
File::makeDirectory($outputDir, 0755, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$spec = $this->generateSpec();
|
|
||||||
$yaml = Yaml::dump($spec, 4, 2);
|
|
||||||
|
|
||||||
File::put($outputDir . '/openapi.yaml', $yaml);
|
|
||||||
$this->info('OpenAPI specification saved to public/docs/openapi.yaml');
|
|
||||||
|
|
||||||
return Command::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function generateSpec(): array
|
|
||||||
{
|
|
||||||
$appUrl = config('app.url', 'http://localhost');
|
|
||||||
|
|
||||||
return [
|
|
||||||
'openapi' => '3.0.0',
|
|
||||||
'info' => [
|
|
||||||
'title' => config('app.name', 'Laravel API'),
|
|
||||||
'description' => 'API Documentation',
|
|
||||||
'version' => '1.0.0',
|
|
||||||
],
|
|
||||||
'servers' => [
|
|
||||||
['url' => $appUrl, 'description' => 'Local server'],
|
|
||||||
],
|
|
||||||
'paths' => $this->generatePaths(),
|
|
||||||
'components' => [
|
|
||||||
'securitySchemes' => [
|
|
||||||
'bearerAuth' => [
|
|
||||||
'type' => 'http',
|
|
||||||
'scheme' => 'bearer',
|
|
||||||
'bearerFormat' => 'JWT',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'schemas' => $this->generateSchemas(),
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function generatePaths(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'/api/register' => [
|
|
||||||
'post' => [
|
|
||||||
'tags' => ['Auth'],
|
|
||||||
'summary' => 'Register a new user',
|
|
||||||
'requestBody' => [
|
|
||||||
'required' => true,
|
|
||||||
'content' => [
|
|
||||||
'application/json' => [
|
|
||||||
'schema' => [
|
|
||||||
'type' => 'object',
|
|
||||||
'required' => ['name', 'email', 'password', 'password_confirmation'],
|
|
||||||
'properties' => [
|
|
||||||
'name' => ['type' => 'string', 'example' => 'John Doe'],
|
|
||||||
'email' => ['type' => 'string', 'format' => 'email', 'example' => 'john@example.com'],
|
|
||||||
'password' => ['type' => 'string', 'format' => 'password', 'example' => 'password123'],
|
|
||||||
'password_confirmation' => ['type' => 'string', 'format' => 'password', 'example' => 'password123'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'responses' => [
|
|
||||||
'201' => ['description' => 'User registered successfully'],
|
|
||||||
'422' => ['description' => 'Validation error'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'/api/login' => [
|
|
||||||
'post' => [
|
|
||||||
'tags' => ['Auth'],
|
|
||||||
'summary' => 'Login user',
|
|
||||||
'requestBody' => [
|
|
||||||
'required' => true,
|
|
||||||
'content' => [
|
|
||||||
'application/json' => [
|
|
||||||
'schema' => [
|
|
||||||
'type' => 'object',
|
|
||||||
'required' => ['email', 'password'],
|
|
||||||
'properties' => [
|
|
||||||
'email' => ['type' => 'string', 'format' => 'email', 'example' => 'john@example.com'],
|
|
||||||
'password' => ['type' => 'string', 'format' => 'password', 'example' => 'password123'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'responses' => [
|
|
||||||
'200' => ['description' => 'Login successful'],
|
|
||||||
'401' => ['description' => 'Invalid credentials'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'/api/logout' => [
|
|
||||||
'post' => [
|
|
||||||
'tags' => ['Auth'],
|
|
||||||
'summary' => 'Logout user',
|
|
||||||
'security' => [['bearerAuth' => []]],
|
|
||||||
'responses' => [
|
|
||||||
'200' => ['description' => 'Logged out successfully'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'/api/user' => [
|
|
||||||
'get' => [
|
|
||||||
'tags' => ['Auth'],
|
|
||||||
'summary' => 'Get authenticated user',
|
|
||||||
'security' => [['bearerAuth' => []]],
|
|
||||||
'responses' => [
|
|
||||||
'200' => ['description' => 'User data'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'/api/posts' => [
|
|
||||||
'get' => [
|
|
||||||
'tags' => ['Posts'],
|
|
||||||
'summary' => 'Get all posts',
|
|
||||||
'security' => [['bearerAuth' => []]],
|
|
||||||
'responses' => [
|
|
||||||
'200' => ['description' => 'List of posts'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'post' => [
|
|
||||||
'tags' => ['Posts'],
|
|
||||||
'summary' => 'Create a new post',
|
|
||||||
'security' => [['bearerAuth' => []]],
|
|
||||||
'requestBody' => [
|
|
||||||
'required' => true,
|
|
||||||
'content' => [
|
|
||||||
'application/json' => [
|
|
||||||
'schema' => [
|
|
||||||
'type' => 'object',
|
|
||||||
'required' => ['title', 'content'],
|
|
||||||
'properties' => [
|
|
||||||
'title' => ['type' => 'string', 'example' => 'My Post Title'],
|
|
||||||
'content' => ['type' => 'string', 'example' => 'Post content here...'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'responses' => [
|
|
||||||
'201' => ['description' => 'Post created successfully'],
|
|
||||||
'422' => ['description' => 'Validation error'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'/api/posts/{id}' => [
|
|
||||||
'get' => [
|
|
||||||
'tags' => ['Posts'],
|
|
||||||
'summary' => 'Get a post',
|
|
||||||
'security' => [['bearerAuth' => []]],
|
|
||||||
'parameters' => [
|
|
||||||
['name' => 'id', 'in' => 'path', 'required' => true, 'schema' => ['type' => 'integer']],
|
|
||||||
],
|
|
||||||
'responses' => [
|
|
||||||
'200' => ['description' => 'Post data'],
|
|
||||||
'404' => ['description' => 'Post not found'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'put' => [
|
|
||||||
'tags' => ['Posts'],
|
|
||||||
'summary' => 'Update a post',
|
|
||||||
'security' => [['bearerAuth' => []]],
|
|
||||||
'parameters' => [
|
|
||||||
['name' => 'id', 'in' => 'path', 'required' => true, 'schema' => ['type' => 'integer']],
|
|
||||||
],
|
|
||||||
'requestBody' => [
|
|
||||||
'required' => true,
|
|
||||||
'content' => [
|
|
||||||
'application/json' => [
|
|
||||||
'schema' => [
|
|
||||||
'type' => 'object',
|
|
||||||
'properties' => [
|
|
||||||
'title' => ['type' => 'string', 'example' => 'Updated Title'],
|
|
||||||
'content' => ['type' => 'string', 'example' => 'Updated content...'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'responses' => [
|
|
||||||
'200' => ['description' => 'Post updated successfully'],
|
|
||||||
'404' => ['description' => 'Post not found'],
|
|
||||||
'422' => ['description' => 'Validation error'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'delete' => [
|
|
||||||
'tags' => ['Posts'],
|
|
||||||
'summary' => 'Delete a post',
|
|
||||||
'security' => [['bearerAuth' => []]],
|
|
||||||
'parameters' => [
|
|
||||||
['name' => 'id', 'in' => 'path', 'required' => true, 'schema' => ['type' => 'integer']],
|
|
||||||
],
|
|
||||||
'responses' => [
|
|
||||||
'200' => ['description' => 'Post deleted successfully'],
|
|
||||||
'404' => ['description' => 'Post not found'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function generateSchemas(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'User' => [
|
|
||||||
'type' => 'object',
|
|
||||||
'properties' => [
|
|
||||||
'id' => ['type' => 'integer'],
|
|
||||||
'name' => ['type' => 'string'],
|
|
||||||
'email' => ['type' => 'string', 'format' => 'email'],
|
|
||||||
'role' => ['type' => 'string'],
|
|
||||||
'created_at' => ['type' => 'string', 'format' => 'date-time'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'Post' => [
|
|
||||||
'type' => 'object',
|
|
||||||
'properties' => [
|
|
||||||
'id' => ['type' => 'integer'],
|
|
||||||
'title' => ['type' => 'string'],
|
|
||||||
'content' => ['type' => 'string'],
|
|
||||||
'user_id' => ['type' => 'integer'],
|
|
||||||
'user' => ['$ref' => '#/components/schemas/User'],
|
|
||||||
'created_at' => ['type' => 'string', 'format' => 'date-time'],
|
|
||||||
'updated_at' => ['type' => 'string', 'format' => 'date-time'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>API Documentation - Swagger UI</title>
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="swagger-ui"></div>
|
||||||
|
<script src="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui-bundle.js"></script>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
SwaggerUIBundle({
|
||||||
|
url: "/spectrum/openapi.json",
|
||||||
|
dom_id: '#swagger-ui',
|
||||||
|
presets: [
|
||||||
|
SwaggerUIBundle.presets.apis
|
||||||
|
],
|
||||||
|
docExpansion: "list",
|
||||||
|
persistAuthorization: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
<script>
|
<script>
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
SwaggerUIBundle({
|
SwaggerUIBundle({
|
||||||
url: "/docs/openapi.yaml",
|
url: "/spectrum/openapi.json",
|
||||||
dom_id: '#swagger-ui',
|
dom_id: '#swagger-ui',
|
||||||
presets: [
|
presets: [
|
||||||
SwaggerUIBundle.presets.apis
|
SwaggerUIBundle.presets.apis
|
||||||
|
|
@ -24,3 +24,4 @@
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
openapi: 3.0.0
|
|
||||||
info:
|
|
||||||
title: Laravel
|
|
||||||
description: 'API Documentation'
|
|
||||||
version: 1.0.0
|
|
||||||
servers:
|
|
||||||
-
|
|
||||||
url: 'http://la.test'
|
|
||||||
description: 'Local server'
|
|
||||||
paths:
|
|
||||||
/api/register:
|
|
||||||
post:
|
|
||||||
tags: [Auth]
|
|
||||||
summary: 'Register a new user'
|
|
||||||
requestBody: { required: true, content: { application/json: { schema: { type: object, required: [name, email, password, password_confirmation], properties: { name: { type: string, example: 'John Doe' }, email: { type: string, format: email, example: john@example.com }, password: { type: string, format: password, example: password123 }, password_confirmation: { type: string, format: password, example: password123 } } } } } }
|
|
||||||
responses: { 201: { description: 'User registered successfully' }, 422: { description: 'Validation error' } }
|
|
||||||
/api/login:
|
|
||||||
post:
|
|
||||||
tags: [Auth]
|
|
||||||
summary: 'Login user'
|
|
||||||
requestBody: { required: true, content: { application/json: { schema: { type: object, required: [email, password], properties: { email: { type: string, format: email, example: john@example.com }, password: { type: string, format: password, example: password123 } } } } } }
|
|
||||||
responses: { 200: { description: 'Login successful' }, 401: { description: 'Invalid credentials' } }
|
|
||||||
/api/logout:
|
|
||||||
post:
|
|
||||||
tags: [Auth]
|
|
||||||
summary: 'Logout user'
|
|
||||||
security: [{ bearerAuth: { } }]
|
|
||||||
responses: { 200: { description: 'Logged out successfully' } }
|
|
||||||
/api/user:
|
|
||||||
get:
|
|
||||||
tags: [Auth]
|
|
||||||
summary: 'Get authenticated user'
|
|
||||||
security: [{ bearerAuth: { } }]
|
|
||||||
responses: { 200: { description: 'User data' } }
|
|
||||||
/api/posts:
|
|
||||||
get:
|
|
||||||
tags: [Posts]
|
|
||||||
summary: 'Get all posts'
|
|
||||||
security: [{ bearerAuth: { } }]
|
|
||||||
responses: { 200: { description: 'List of posts' } }
|
|
||||||
post:
|
|
||||||
tags: [Posts]
|
|
||||||
summary: 'Create a new post'
|
|
||||||
security: [{ bearerAuth: { } }]
|
|
||||||
requestBody: { required: true, content: { application/json: { schema: { type: object, required: [title, content], properties: { title: { type: string, example: 'My Post Title' }, content: { type: string, example: 'Post content here...' } } } } } }
|
|
||||||
responses: { 201: { description: 'Post created successfully' }, 422: { description: 'Validation error' } }
|
|
||||||
'/api/posts/{id}':
|
|
||||||
get:
|
|
||||||
tags: [Posts]
|
|
||||||
summary: 'Get a post'
|
|
||||||
security: [{ bearerAuth: { } }]
|
|
||||||
parameters: [{ name: id, in: path, required: true, schema: { type: integer } }]
|
|
||||||
responses: { 200: { description: 'Post data' }, 404: { description: 'Post not found' } }
|
|
||||||
put:
|
|
||||||
tags: [Posts]
|
|
||||||
summary: 'Update a post'
|
|
||||||
security: [{ bearerAuth: { } }]
|
|
||||||
parameters: [{ name: id, in: path, required: true, schema: { type: integer } }]
|
|
||||||
requestBody: { required: true, content: { application/json: { schema: { type: object, properties: { title: { type: string, example: 'Updated Title' }, content: { type: string, example: 'Updated content...' } } } } } }
|
|
||||||
responses: { 200: { description: 'Post updated successfully' }, 404: { description: 'Post not found' }, 422: { description: 'Validation error' } }
|
|
||||||
delete:
|
|
||||||
tags: [Posts]
|
|
||||||
summary: 'Delete a post'
|
|
||||||
security: [{ bearerAuth: { } }]
|
|
||||||
parameters: [{ name: id, in: path, required: true, schema: { type: integer } }]
|
|
||||||
responses: { 200: { description: 'Post deleted successfully' }, 404: { description: 'Post not found' } }
|
|
||||||
components:
|
|
||||||
securitySchemes:
|
|
||||||
bearerAuth:
|
|
||||||
type: http
|
|
||||||
scheme: bearer
|
|
||||||
bearerFormat: JWT
|
|
||||||
schemas:
|
|
||||||
User:
|
|
||||||
type: object
|
|
||||||
properties: { id: { type: integer }, name: { type: string }, email: { type: string, format: email }, role: { type: string }, created_at: { type: string, format: date-time } }
|
|
||||||
Post:
|
|
||||||
type: object
|
|
||||||
properties: { id: { type: integer }, title: { type: string }, content: { type: string }, user_id: { type: integer }, user: { $ref: '#/components/schemas/User' }, created_at: { type: string, format: date-time }, updated_at: { type: string, format: date-time } }
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
/home/user/www/lara/storage/app/spectrum
|
||||||
Loading…
Reference in New Issue