Стандартные ответы API с использованием интерфейса Responsable

Стандартные ответы API с использованием интерфейса Responsable

Введение

Представьте себе, что вы работаете с приложением, в котором каждая конечная точка возвращает данные об успешных и ошибочных вызовах по-разному. Если это маленькое и простое приложение, поддерживаемое одним человеком, это может быть немного проще, но если приложение начнет расти и к команде начнет присоединяться все больше людей, то за небольшой промежуток времени поддержка и улучшение приложения станет полным хаосом. приложение.

Наличие стандартизированной структуры ответов вашего приложения может очень помочь в повышении его качества и удобства сопровождения. В этой статье мы узнаем простой способ сделать это с помощью классов Laravel Responsable.

Что такое ответственные классы Laravel?

У Laravel есть интерфейс: Illuminate\Contracts\Support\Responsable его можно использовать для создания классов, которые можно преобразовать в HTTP-ответы. Это действительно простой интерфейс, имеющий только один метод:

namespace Illuminate\Contracts\Support;

interface Responsable
{
    /**
     * Create an HTTP response that represents the object.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function toResponse($request);
}

Создание пользовательских классов ответов

Создание пользовательских классов Response дает нам много возможностей, но нам нужно быть осторожными в том, как их использовать. Я уже видел множество баз кода и множество статей, объясняющих, как использовать пользовательские классы Response для форматирования данных и применения некоторой логики к данным перед их отправкой, но лично я не думаю, что это хороший способ использования этой функции. По моему мнению, форматирование кода и логика должны находиться на другом уровне приложения.

Но с помощью этой функции мы можем сделать одну замечательную вещь — создавать стандартизированные ответы для наших приложений. Наличие этого в наших приложениях может значительно улучшить их качество и удобство сопровождения, поскольку вы уже знаете структуру, которую следует ожидать от вашего приложения.

В разделах ниже мы создадим два разных класса пользовательских ответов: один для успешных ответов API, а другой — для неудачных ответов API.

Создание ответа об успехе API

Представьте, что в вашем приложении ваши конечные точки всегда возвращают необходимые для этого данные, но они также могут возвращать некоторые метаданные, которые могут содержать сообщение или уведомление для отображения пользователю, информацию о нумерации страниц и т. д. Имея это в виду, мы можем создать простой пользовательский класс Response, который всегда будет возвращать два свойства в ваших ответах: data и metadata. Пользовательский класс Response будет выглядеть примерно так:

namespace App\Http\Responses;

use Illuminate\Contracts\Support\Responsable;
use Illuminate\Http\Response;

class ApiSuccessResponse implements Responsable
{
    /**
     * @param  mixed  $data
     * @param  array  $metadata
     * @param  int  $code
     * @param  array  $headers
     */
    public function __construct(
        private mixed $data,
        private array $metadata,
        private int $code = Response::HTTP_OK,
        private array $headers = []
    ) {}

    /**
     * @param  $request
     * @return \Symfony\Component\HttpFoundation\Response|void
     */
    public function toResponse($request)
    {
        return response()->json(
            [
                'data' => $this->data,
                'metadata' => $this->metadata,
            ],
            $this->code,
            $this->headers
        );
    }
}

С помощью этого класса мы можем гарантировать, что:

  • Ответ всегда будет в формате JSON.
  • Мы всегда будем возвращать свойства data и metadata.
  • При необходимости мы можем настроить HTTP-код и заголовки.

Теперь вы можете использовать этот ответ для своих конечных точек

class UserController extends Controller
{
    public function store(CreateUserRequest $request): JsonResponse
    {
        $user = $this->service->create($request->all());
        return new ApiSuccessResponse(
            ['message' => 'User was created successfully'],
            Response::HTTP_CREATED
        );
    }
}

Можно доработать класс, добавив статический метод создания экземпляра класса и добавить метод для формирования данных ответа:

<?php

namespace App\Http\Responses;

use Illuminate\Contracts\Support\Responsable;
use Illuminate\Http\Resources\Json\JsonResource;
use Symfony\Component\HttpFoundation\Response;

class ApiSuccessResponse implements Responsable
{

    /**
     * @param array|JsonResource $data
     * @param int $code
     * @param array $headers
     */
    public function __construct(
        private readonly array|JsonResource $data = [],
        private readonly int                $code = Response::HTTP_OK,
        private readonly array              $headers = []
    )
    {
        //
    }

    /**
     * @param array|JsonResource $data
     * @param int $code
     * @param array $headers
     * @return ApiSuccessResponse
     */
    public static function make(
        array|JsonResource $data = [],
        int                $code = Response::HTTP_OK,
        array              $headers = []
    ): ApiSuccessResponse
    {
        return new self($data, $code, $headers);
    }

    /**
     * @param  $request
     * @return Response
     */
    public function toResponse($request): Response
    {
        return response()->json(
            $this->makeContent(),
            $this->code,
            $this->headers
        );
    }

    /**
     * @return array
     */
    private function makeContent(): array
    {
        return array_merge([
            'success' => true,
        ], $this->data);
    }
}

Пример использования:

<?php

namespace App\Http\Controllers;

use App\Http\Responses\ApiSuccessResponse;
use Illuminate\Contracts\Support\Responsable;

class UserController extends Controller
{
    public function store(CreateUserRequest $request): Responsable
    {
        $user = User::create($request->all());
				
        return ApiSuccessResponse::make([
            'user' => $user,
       ]);
    }
}

Создание ответа об ошибке API

Представьте, что в вашем приложении вы хотите всегда возвращать сообщение об ошибке, если что-то идет не так, но вы также хотите добавить некоторую отладочную информацию, если для параметра debug установлено значение true. Имея это в виду, мы можем создать еще один простой собственный класс Response, который будет делать это:

namespace App\Http\Responses;

use Illuminate\Contracts\Support\Responsable;
use Illuminate\Http\Response;
use Throwable;

class ApiErrorResponse implements Responsable
{
    public function __construct(
        private string $message,
        private ?Throwable $exception = null,
        private int $code = Response::HTTP_INTERNAL_SERVER_ERROR,
        private array $headers = []
    ) {}

    /**
     * @param  $request
     * @return \Symfony\Component\HttpFoundation\Response|void
     */
    public function toResponse($request)
    {
        $response = ['message' => $this->message];

        if (! is_null($this->exception) && config('app.debug')) {
            $response['debug'] = [
                'message' => $this->exception->getMessage(),
                'file'    => $this->exception->getFile(),
                'line'    => $this->exception->getLine(),
                'trace'   => $this->exception->getTraceAsString()
            ];
        }

        return response()->json($response, $this->code, $this->headers);
    }
}

С помощью этого класса мы можем гарантировать, что:

  • Ответ всегда будет в формате JSON.
  • Мы всегда вернем messageимущество.
  • Информация об отладке будет добавлена при необходимости.
  • При необходимости мы можем настроить HTTP-код и заголовки.

Теперь вы можете использовать этот ответ для своих конечных точек:

class UserController extends Controller
{
    public function store(CreateUserRequest $request): JsonResponse
    {
        try {
            $user = User::create($request->all());
				
            return ApiSuccessResponse::make([
                'user' => $user,
            ]);
        } catch (Throwable $exception) {
            return new ApiErrorResponse(
                'An error occurred while trying to create the user',
                $exception
            );
        }
    }
}

Заключение

В этой статье мы узнали, как использовать классы Laravel Responsable для создания стандартизированных ответов API для наших приложений, чтобы улучшить их качество и удобство обслуживания. Примеры в этой статье предназначены только для того, чтобы показать, как использовать эту функцию, но вы можете настроить собственные классы ответов в соответствии с потребностями ваших проектов.

Похожие статьи

Генератор QR Code на Laravel

Это оболочка для генератора QR-кодов для PHP, автономной библиотеки для создания QR-кодов в форматах PNG и SVG.

Дублирование и клонирование записей с Laravel

Вам когда-нибудь приходилось дублировать или клонировать запись базы данных? Laravel предоставляет для этого очень удобную функцию.

Подключение к Yandex.Cloud MySQL на Laravel

При развертывании базы данных на серверах Yandex.Cloud может возникнуть проблема с подключением к ней Laravel. Managed Service for MySQL предоставляет два варианта подключения.

Copyright © 2026 PHP Blog - шпаргалки программиста