Skip to main content
Документация API

Api документация. Менеджер финансов на Laravel 8

Каждому проекту, не зависимо от размера, нужна документация. Это может быть как подробное ТЗ, требования пользовательские/бизнес/системные. Но еще, если вы разрабатываете 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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *