Стандартные ответы 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 для наших приложений, чтобы улучшить их качество и удобство обслуживания. Примеры в этой статье предназначены только для того, чтобы показать, как использовать эту функцию, но вы можете настроить собственные классы ответов в соответствии с потребностями ваших проектов.

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

Контейнер свойств

Контейнер свойств — фундаментальный шаблон проектирования, который служит для обеспечения возможности динамического расширения свойств уже созданного объекта класса.

IDE Helper генератор

Этот пакет создает вспомогательные файлы, которые позволяют вашей среде IDE обеспечить точное автозаполнение. Генерация выполняется на основе файлов вашего проекта, поэтому они всегда актуальны.

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

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

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