Каждому проекту, не зависимо от размера, нужна документация. Это может быть как подробное ТЗ, требования пользовательские/бизнес/системные. Но еще, если вы разрабатываете Restful Api, нужна документация для API, с примерами запросов и ответов. Сегодня мы добавим к проекту генератор документации и напишем её для методов входа и регистрации.
Установка пакета darkaonline/l5-swagger
Устанавливаем пакет darkaonline/l5-swagger командой composer require "darkaonline/l5-swagger"
. Этот пакет является неким контейнером, который связывает swagger-php
с фреймворком Laravel и даёт нам возможность работать с его функционалом.
После установки, нам доступна консольная команда для генерации документации php artisan l5-swagger:generate
и маршрут, по которому мы можем её просматривать — /api/documentation
.
Но установкой нужных пакетов всё не обходится, теперь нам нужно еще и описать запросы и ответы.
Для базового знакомства, можете почитать документацию по свагеру, а мы приступим к описанию.
Документирование API
Вся документация описывается в аннотациях к классам и методам, это можно делать напрямую в контроллерах, либо вынести в отдельные классы — схемы, модели, запросы.
Создадим директорию в папке app
и назовём её ApiDoc
, на самом деле именование не важно, swagger будет сканировать всю директорию и выстраивать свою структуру.
Я решил разнести файлы с описанием по директориям, которые отражают тот контекст, в котором работают. Например, если описываем аутентификацию, то создадим директорию Auth
в папке app/ApiDoc
.
Описание /api/login
В директории app/ApiDoc/Auth
создадим файл с именем LoginRequest.php
и класс LoginSuccessResponse.php
. Первый файл будет описывать тело запроса, а класс — описывает ответ при успешном логине.
app/ApiDoc/Auth/LoginRequest.php
<?php /** * @OA\RequestBody( * request="LoginRequest", * description="Auth request fields", * @OA\JsonContent( * type="object", * required={"email", "password"}, * @OA\Property(property="email", type="string", example="[email protected]"), * @OA\Property(property="password", type="string", example="qwerty"), * ) * ) */
Разберем этот код:
@OA\RequestBody
— указываем, что мы собираемся описывать тело ответа.request="LoginRequest"
— название запроса, оно нам понадобиться дальше.description
— тут понятно.@OA\JsonContent
— описание схемы запроса(имена полей и примеры).type="object"
— говорит о том, что это json объект.required={"email", "password"}
— указываем какие поля должны быть обязательны.@OA\Property(property="email", type="string", example="[email protected]")
— описание свойства.
app/ApiDoc/Auth/LoginSuccessResponse.php
<?php namespace App\ApiDoc\Auth; /** * Class LoginSuccessResponse * @package App\ApiDoc\Auth * @OA\Schema( * description="Success auth response", * title="Auth response" * ) */ class LoginSuccessResponse { /** * @var string * @OA\Property(type="string", example="random string") */ public $token; }
Аннотации очень похожи, на те, что мы разбирали выше, но с использованием класса.
Для продолжения, нам нужно описать еще 2 ответа, это ответ на проваленную авторизацию/аутентификацию и ошибки валидации.
app/ApiDoc/Base/UnauthenticatedResponse.php
<?php namespace App\ApiDoc\Base; /** * Class UnauthenticatedResponse * @package App\ApiDoc\Base * @OA\Schema( * description="Unauthenticated response schema", * title="Unauthenticated response" * ) */ class UnauthenticatedResponse { /** * @var string * @OA\Property(type="string", example="Unauthenticated.") */ public $message; }
app/ApiDoc/Base/ValidationResponse.php
<?php namespace App\ApiDoc\Base; /** * Class ValidationResponse * @package App\ApiDoc\Base * @OA\Schema( * description="Validation errors response", * title="Validation errors response" * ) */ class ValidationResponse { /** * @var string * @OA\Property( * format="string", * title="Message", * description="Validation message", * example="The given data was invalid." * ) */ public $message; /** * @OA\Property( * type="object", * title="Validation errors", * description="Validation errors object", * @OA\Property(property="field1", type="array", @OA\Items(example="The field1 field is required.")), * @OA\Property(property="field2", type="array", @OA\Items(example="The field2 field is required.")) * ) */ public $errors; }
Всё готово для описания метода аутентификации, переходим в наш контроллер `app/Http/Controllers/Auth/LoginController.php` и приводим к следующему виду:
<?php namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use App\Http\Requests\LoginUserRequest; use Illuminate\Http\Response; use Illuminate\Support\Facades\Auth; /** * Class LoginController * @package App\Http\Controllers\Auth * @OA\Tag(name="Auth") */ class LoginController extends Controller { /** * @param LoginUserRequest $request * @return \Illuminate\Http\JsonResponse * @OA\Post( * path="/api/login", * tags={"Auth"}, * operationId="login", * @OA\RequestBody(ref="#/components/requestBodies/LoginRequest"), * @OA\Response( * response=200, * description="Success auth response", * @OA\JsonContent(ref="#/components/schemas/LoginSuccessResponse") * ), * @OA\Response( * response=401, * description="User not authorized. Wrong email or password.", * @OA\JsonContent(ref="#/components/schemas/UnauthenticatedResponse") * ), * @OA\Response( * response=422, * description="Validation errors.", * @OA\JsonContent(ref="#/components/schemas/ValidationResponse") * ) * ) */ public function login(LoginUserRequest $request) { if (Auth::attempt($request->validated())) { $token = Auth::user()->createToken('api'); return response()->json([ 'token' => $token->plainTextToken ]); } return response()->json([ 'message' => 'Unauthenticated.' ], Response::HTTP_UNAUTHORIZED); } }
Дописали много странного и непонятного, сейчас быстро разберем.
@OA\Post
— Указываем, что это должен быть POST запрос.path="/api/login"
— это урл, понятно.@OA\RequestBody(ref="#/components/requestBodies/LoginRequest")
— тело запроса. Мы используем ссылку на тот запрос, что описывали выше.@OA\Response
— Описываем ответ, их может быть несколько.@OA\JsonContent(ref="#/components/schemas/LoginSuccessResponse")
— здесь описываем тело ответа, так же используем ссылку на уже готовое описание.
Теперь аналогично делаем для контроллера регистрации.
Описание /api/registration
app/ApiDoc/Registration/RegistrationRequest.php
<?php /** * @OA\RequestBody( * request="RegistrationRequest", * description="Registration request body", * @OA\JsonContent( * type="object", * @OA\Property(property="name", type="string", example="John Doe"), * @OA\Property(property="email", type="string", example="[email protected]"), * @OA\Property(property="password", type="string", example="qwerty"), * @OA\Property(property="password_confirmation", type="string", example="qwerty"), * ) * ) */
app/Http/Controllers/Auth/RegistrationController.php
<?php namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use App\Http\Requests\RegisterUserRequest; use App\Models\User; use Illuminate\Http\Request; use Illuminate\Http\Response; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Log; /** * Class RegistrationController * @package App\Http\Controllers\Auth * @OA\Tag(name="Auth") */ class RegistrationController extends Controller { /** * @param RegisterUserRequest $request * @return \Illuminate\Http\JsonResponse * @OA\Post( * path="/api/registration", * tags={"Auth"}, * operationId="registration", * @OA\RequestBody(ref="#/components/requestBodies/RegistrationRequest"), * @OA\Response( * response=200, * description="User successfully registered", * ), * @OA\Response( * response=500, * description="Server error" * ), * @OA\Response( * response=422, * description="Validation errors.", * @OA\JsonContent(ref="#/components/schemas/ValidationResponse") * ) * ) */ public function registration(RegisterUserRequest $request) { try { User::create([ 'name' => $request->name, 'email' => $request->email, 'password' => Hash::make($request->password) ]); return response()->json([], Response::HTTP_OK); } catch (\Exception $e) { Log::error($e->getMessage(), ['trace' => $e->getTraceAsString()]); return response()->json([], Response::HTTP_INTERNAL_SERVER_ERROR); } } }
Осталось только запустить команду php artisan l5-swagger:generate
и перейти по адресу http://вашСайт/api/documentation
. Если вы все правильно сделали, должны увидеть подобную страницу:

Если что-то не получается, всегда можете посмотреть в репозитории — https://gitlab.com/oneshkip/finmanager