2

I am trying to build a simple contact form with Vue 3 and Laravel 8 but am struggling connecting the frontend with the backend. Right now my code produces a 422 (Unprocessable Entity) response but I don't know why and how to investigate. The response occurs indipendent of the passed data values. For example name = null and name = myname produce the same error.

contact.vue:

<template>
  <section class="contact">
    <form @submit.prevent="storeContact" method="post">
      <input type="text" placeholder="Name" v-model="user.name">
      <input type="text" placeholder="Email" v-model="user.email">
      <input type="text" placeholder="Message" v-model="user.message">
      <button action="post" type="submit">Submit</button>
    </form>
  </section>
</template>


<script>
import {ref} from "vue";

export default {
  setup() {
    let success = false;
    let error = false;
    let user = ref({
      name: null,
      email: null,
      message: null
    });
    function storeContact() {
      axios.post('/contact', Object.values(user.value)
      )
        .then((res) => {
          success = true;
        })
        .catch((error) => {
          error = true;
        })
    };
    return {
      success,
      error,
      user,
      storeContact
    }
  }
}
</script>

web.php:

<?php

use Illuminate\Support\Facades\Route;


Route::get('/', function () {
    return view('welcome');
});

Route::post('/contact', 'App\Http\Controllers\ContactController@submit');

ContactController.php:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ContactController extends Controller
{
  public function submit(Request $request) {
    $this->validate($request, [
      'name' => 'required',
      'email' => 'required | email',
      'message' => 'required'
    ]);
    return response()->json(null, 200);
  }
}

Browser console error:

app.js:17263 POST http://localhost:3000/contact 422 (Unprocessable Entity)

Laravel log has no entry. Does this mean it is a frontend problem?

Edit:

The response in the dev tools network tab shows:

{"message":"The given data was invalid.","errors":{"name":["The name field is required."],"email":["The email field is required."],"message":["The message field is required."]}}

Changing these parameters to text/values brings no change.

Edit2:

These issues have been ruled out:

Missing CSRF-Token: nope, csrf token is present in the network tab (XSRF).

null passed: nope, it doesn't matter what I pass, the result is the same.

Artur Müller Romanov
  • 4,417
  • 10
  • 73
  • 132

3 Answers3

1

As @Mohammed Naguib mentioned, 422 is returned when the validation fails. Based on your validation code - all the properties are required.

$this->validate($request, [
  'name' => 'required',
  'email' => 'required | email',
  'message' => 'required'
]);

So I'll suggest to divide the debugging process into 2.

(1) - Does the front-end sends the data?

on contact.vue, prior to sending the post request. use console.debug to the user object and check the data you send.

   let user = ref({
      name: null,
      email: null,
      message: null
    });
    function storeContact() {
      console.debug(user);
      console.debug(Object.values(user.value));

      axios.post('/contact', Object.values(user.value)

Check the console on the developers tools and check what is the output of the console.debug command for the user object and for the values you send on the request.

If one of the properties is null - something is wrong with the front end.

(2) - Backend

Remove the $this->validate() function and simply var_dump the $request object. Do you see the relevant properties (name, email, address) and do they have the desired values?

My guess:

if i'm not mistaken Object.values(user.value) creates an array with the values so the properties names would be missing from the request.

Ofir Baruch
  • 10,323
  • 2
  • 26
  • 39
0

You're having this issue because you are posting without the CSRF token to the server. Here is a similar case on how to resolve this issue.

How to pass laravel CSRF token value to vue

You will need to copy the CSRF token from the DOM to the header of your axios request or append it to the common headers. Once done, your POST request will be processable. Alternatively to confirm this, you can go to the file app/Http/Middleware/VerifyCsrfToken.php and add your path to the 'except' array

<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
        '/contact'
    ];
}
Nimantha
  • 6,405
  • 6
  • 28
  • 69
Jordan Casey
  • 955
  • 9
  • 16
  • I have `` in `welcome.blade.php. Does this not provide a `csrf token`? In addition I am working on the `php artisan dev server`. Is it necessary to provide `csrf tokens` on dev servers? – Artur Müller Romanov Oct 01 '21 at 15:01
  • To confirm, you can check your network and see if the CSRF token is passed in the body or header(I expect here) however if you don't see it then try including it by hand with one of the references from the article above. As for the dev server, I am unsure but would expect it would act the same to not confuse you with a production environment – Jordan Casey Oct 01 '21 at 15:03
  • do you mean the `X-XSRF-TOKEN: eyJ.....` in `network`/`Headers`? I can't find a `CSRF token` in `Headers` and I don't have a `body` tab. – Artur Müller Romanov Oct 01 '21 at 15:09
  • Ahh I see that you're also not passing anything in your object value reference. The null values in let user = ref({ name: null, email: null, message: null }); will actually have to be set to real values. My answer is not correct for your issue. I would recommend binding acutal values. Dropping the ref for now and then remove the Object.values() function and only passing the user object as user.value isnt defined Happy Coding – Jordan Casey Oct 01 '21 at 15:15
  • Even if I remove all variables (from `script` and from `ContactController.php`) and `ref` and only pass `name = whatever` the same error is given. – Artur Müller Romanov Oct 01 '21 at 15:21
  • Let's confirm it is infact not a js error by using postman to hit your endpoint. Ensure that you include the name, email and message as well as set the header csrf token. If you can do these things, we will check out the frontend – Jordan Casey Oct 01 '21 at 15:26
  • I think I have done so. How do I check, if the `csrf token` is indeed included? I still don't see it in `network tab Headers` – Artur Müller Romanov Oct 01 '21 at 15:41
  • You can click the post request on the network tab to see. In post man, you can add it under the Headers tab – Jordan Casey Oct 01 '21 at 15:53
  • also I found this in a laracast discussion: `"Csrf token exist by default on either the bootstrap.js or app.js file. You dont have to explicitly add it on any vue component."`. A comment in my `Bootstrap.js` says: `"This library automatically handles sending the CSRF token as a header based on the value of the "XSRF" token cookie."`. The XSRF token is present in my `network tab`, so it was present all along. – Artur Müller Romanov Oct 01 '21 at 15:57
0

Turns out I had a typo in axios.post:

changing axios.post('/contact', Object.values(user.value)) to axios.post('/contact', user.value)

and putting the data as not null fixed my problem.

Thank you for all the help guys.

Artur Müller Romanov
  • 4,417
  • 10
  • 73
  • 132