Параметр запроса проверки Laravel и POST маршрута API - PullRequest
0 голосов
/ 09 ноября 2018

У меня небольшая проблема с проверкой запроса формы и с тем, как обработать ее с помощью одного маршрута API.

Ресурс, который мне нужно создать, зависит от другого ресурса.

(Здесь EmailSettings принадлежит Арендатору)

Таким образом, мой маршрут должен выглядеть примерно так: / api / tenants / {id} / email_settings

И мой запрос проверки ожидает несколько полей, включая tenantId:

public function rules() {
    return [
        'email' => 'bail|required|email|unique:email_settings,email',
        'name' => 'bail|required',
        'username' => 'bail|required',
        'password' => 'bail|required'
        'imapHost' => 'bail|required',
        'imapPort' => 'bail|required',
        'imapEncryption' => 'bail|required',
        'imapValidateCert' => 'bail|required',
        'smtpHost' => 'bail|required',
        'smtpPort' => 'bail|required',
        'smtpEncryption' => 'bail|required',
        'tenantId' => 'bail|required',
    ];
}

И я отправляю запрос так:

try {
    const response = await this.tenantForm.post('/api/tenants')
    let newTenant = helpers.getNewResourceFromResponseHeaderLocation(response)
    let tenantId = parseInt(newTenant.id);
    try {
        await this.emailSettingsForm.post('/api/tenants/' + tenantId + '/email_settings')
        this.requestAllTenants()
    } catch ({response}) {
        $('.second.modal').modal({blurring: true, closable: false}).modal('show');
    }
} catch ({response}) {
    $('.first.modal').modal({blurring: true}).modal('show');
}

Таким образом, tenantId передается в качестве параметра, а не в теле запроса для соблюдения соглашения REST. Но проблема в моем контроллере: когда я объединяю данные для создания ресурса, проверка уже проводилась только для данных тела до слияния.

public function store(EmailSettingValidation $request, $tenant_id) {
    $emailSetting = $this->emailSettingService->create(
        array_merge($request->all(), compact($tenant_id))
    );
    return $this->response->created($emailSetting);
}

Так, как лучше всего обращаться с ним правильно?

  • Передать идентификатор в теле? Кажется грязным
  • Использовать Validator для проверки вручную? Я предпочел бы сохранить форму проверки
  • Удалить правило tenantId и проверить его вручную?

Есть предложения? Спасибо

Ответы [ 3 ]

0 голосов
/ 09 ноября 2018

Итак, решение, которое я нашел для запуска 404, следующее:

  • Удалить tenantId из проверки EmailSettings
  • Добавить провайдера для добавления пользовательской ошибки, когда возникает исключение ModelNotFoundException, как здесь Нет результатов запроса для модели в Laravel с Dingo - как сделать RESTful-ответ при сбое?
  • Попробуйте сгенерировать это исключение с помощью метода findOrFail, если недопустимый идентификатор:

    public function store(EmailSettingValidation $request, $tenant_id) {
        Tenant::findOrFail($tenant_id);
        $emailSetting = $this->emailSettingService->create(
            array_merge($request->all(), ['tenantId' => $tenant_id])
        );
        return $this->response->created($emailSetting);
    }
    
0 голосов
/ 09 ноября 2018

У Трэвиса Бритса и Guillaumehanotel есть половина вашего ответа, но вы все еще не нашли детали.

От Travis Britz - Да, включите tenant_id в URI, чтобы он вводился в контроллер. От Guillaumehanotel - также использовал Eloquent findOrFail в этом Id в вашем контроллере (или в любом другом классе, который используется контроллером для этого, например, в репозитории или классе обслуживания).

Последний кусок, который вы пропустили, хотя и обрабатывает ошибку. Вы можете сделать это в контроллере, если хотите, но я обычно предпочитаю установить для всей моей системы правило, что Illuminate\Database\Eloquent\ModelNotFoundException Исключения, которые выходят из findOrFail(), всегда должны приводить к 404.

Перейти к app/Exceptions/Handler.php. Я почти уверен, что Laravel автоматически сгенерирует версию этого файла для мяса и картофеля, но если у вас ее еще нет, она должна выглядеть примерно так:

<?php

namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

/**
 * Class Handler
 * @package App\Exceptions
 */
class Handler extends ExceptionHandler
{
    /**
     * Render an exception into an HTTP response.
     *
     * For our API, we need to override the call
     * to the parent.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Exception $e
     * @return \Illuminate\Http\Response
     */
    public function render($request, Exception $error)
    {
        $exception = [
            'title' => 'Internal Error',
            'message' => $error->getMessage();
        ];
        $statusCode = 500;
        $headers = [
            'Content-Type', 'application/json'
        ];

        return response()->json($exception, $statusCode, $headers, JSON_PRETTY_PRINT);
    }
}

Laravel в основном имеет общесистемную try/catch, которая сначала отправляет сюда все ошибки. Вот как ошибки отображаются в том, что браузер может интерпретировать, когда вы находитесь в режиме отладки, а не просто убивать процесс напрямую. Это также дает вам возможность применить несколько специальных правил.

Итак, все, что вам нужно сделать, это указать Handler::render() изменить код ошибки по умолчанию, который возникает, когда он обнаруживает тип ошибки, который может исходить только от findOrFail(). (Именно из-за этого всегда полезно создавать собственные «именованные исключения», даже если они абсолютно ничего не делают, кроме как наследуют базовый класс \Exception.)

Просто добавьте это как раз перед тем, как render() вернет что-либо:

if ($error instanceof Illuminate\Database\Eloquent\ModelNotFoundException) {
    $statusCode = 404;
}
0 голосов
/ 09 ноября 2018

Если вы определите свой маршрут API следующим образом:

Roue::post('tenants/{tenant}/emails_settings', 'Controller@store');

и измените ваш метод контроллера, чтобы напечатать подсказку модели с соответствующим именем переменной:

public function store(EmailSettingValidation $request, Tenant $tenant) {}

Laravel автоматически найдет Арендатора по ID и вставит его в контроллер, выдав исключение ModelNotFoundException (404), если он не существует. Это должно позаботиться о проверке идентификатора.

Авторизация это другое дело.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...