Search code examples
phplaravelrestvalidation

Laravel Validation Request and API route POST parameter


I'm facing a little issue with Form Request Validation and how to handle it with one API route.

The resource that I need to create depends on an other resource.

(Here an EmailSettings belongs to a Tenant)

So the look of my route should be something like : /api/tenants/{id}/email_settings

And my request validation expects several fields including the 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',
    ];
}

And I send the request like this :

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');
}

So the tenantId is passed as a parameter and not in the request body to respect the REST convention. But the problem is in my Controller, when I merge the data to create the resource, the validation has already took place only on body data before the merge.

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

So what is the best way to handle it properly?

  • Pass the id in the body? Seems messy
  • Use Validator to validate manually? I would prefer to keep Form Validation
  • Remove the tenantId rule and check it manually?

Any suggestions?


Solution

  • So the solution I found to trigger 404 is the following :

    • Remove the tenantId from EmailSettings Validation
    • Add a provider to add a custom error when the exception 'ModelNotFoundException' occurs like here No query results for model in Laravel with Dingo - how to make a RESTful response on failure?
    • Try to throw this Exception with the findOrFail method if invalid ID :

      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);
      }