title: What causes the data validation error in this Laravel API?
body: <p>I am working on a registration form with Laravel 8 and Vue 3. The back-end is an API.</p>
  <p>In the <code>users</code> table migration file I have:</p>
  <pre><code>class CreateUsersTable extends Migration {
  
   public function up()
   {
    Schema::create('users', function (Blueprint $table) {
        $table-&gt;id();
        $table-&gt;string('first_name');
        $table-&gt;string('last_name');
        $table-&gt;string('email')-&gt;unique();
        $table-&gt;timestamp('email_verified_at')-&gt;nullable();
        $table-&gt;string('password');
        $table-&gt;unsignedInteger('country_id')-&gt;nullable();
        $table-&gt;foreign('country_id')-&gt;references('id')-&gt;on('countries');
        $table-&gt;rememberToken();
        $table-&gt;timestamps();
     });
   }
   // More code here
  }
  </code></pre>
  <p>As can be seen above, the id in the <code>countries</code> table is a foreign key in the <code>users</code> table.</p>
  <p>I have this piece of code in the <strong>AuthController</strong> to register a new user:</p>
  <pre><code>class AuthController extends Controller {
      
      public function countries()
      {
          return country::all('id', 'name', 'code');
      }
      
      public function register(Request $request) {
  
          $rules = [
              'first_name' =&gt; 'required|string',
              'last_name' =&gt; 'required|string',
              'email' =&gt; 'required|email|unique:users,email',
              'password' =&gt; 'required|string|confirmed',
              'country_id' =&gt; 'required|exists:countries',
              'accept' =&gt; 'accepted',
          ];
  
          $customMessages = [
              'first_name.required' =&gt; 'First name is required.',
              'last_name.required' =&gt; 'Last name is required.',
              'email.required' =&gt; 'A valid email is required.',
              'email.email' =&gt; 'The email address you provided is not valid.',
              'password.required' =&gt; 'A password is required.',
              'password.confirmed' =&gt; 'The passwords do NOT match.',
              'country_id.required' =&gt; 'Please choose a country.',
              'accept.accepted' =&gt; 'You must accept the terms and conditions.'
          ];
  
          $fields = $request-&gt;validate($rules, $customMessages);
      
          $user = User::create([
              'first_name' =&gt; $fields['first_name'],
              'last_name' =&gt; $fields['last_name'],
              'email' =&gt; $fields['email'],
              'password' =&gt; bcrypt($fields['password']),
              'country_id' =&gt; $fields['country_id']
          ]);
  
          $token = $user-&gt;createToken('secret-token')-&gt;plainTextToken;
  
          $response = [
              'countries' =&gt; $this-&gt;countries(),
              'user' =&gt; $user,
              'token' =&gt; $token
          ];
  
          return response($response, 201);
      }
   }
  </code></pre>
  <p>On the front-end, I have:</p>
  <pre><code>const registrationForm = {
    data() {
      return {
        apiUrl: 'http://myapp.test/api',
        formSubmitted: false,
        countries: [],
        fields: {
          first_name: '',
          last_name: '',
          email: '',
          password: '',
          country_id: null,
        },
        errors: {},
      };
    },
    methods: {
      // get Countries
      async getCountries(){
        try {
          const response = await axios
            .get(`${this.apiUrl}/register`)
            .catch((error) =&gt; {
              console.log(error.response.data);
            });
  
          // Populate countries array
          this.countries = response.data.countries;
  
        } catch (error) {
          console.log(error);
        }
      },
  
      registerUser(){
        // Do Registrarion
        axios.post(`${this.apiUrl}/register`, this.fields).then(() =&gt;{
          // Show success message
          this.formSubmitted = true;
  
          // Clear the fields
          this.fields = {}
  
        }).catch((error) =&gt;{
          if (error.response.status == 422) {
            this.errors = error.response.data.errors;
          }
        });
      }
    },
    async created() {
      await this.getCountries();
    }
  };
  
  Vue.createApp(registrationForm).mount(&quot;#myForm&quot;);
  </code></pre>
  <p>In the Vue template:</p>
  <pre><code>&lt;form id=&quot;myForm&quot;&gt;
      &lt;div v-if=&quot;formSubmitted&quot; class=&quot;alert alert-success alert-dismissible&quot;&gt;
        &lt;button type=&quot;button&quot; class=&quot;close&quot; data-dismiss=&quot;alert&quot;&gt;&amp;times;&lt;/button&gt;
        Your account was created :)
      &lt;/div&gt;
  
      &lt;div class=&quot;form-group&quot; :class=&quot;{ 'has-error': errors.first_name }&quot;&gt;
      &lt;input type=&quot;text&quot; class=&quot;form-control&quot; placeholder=&quot;First name&quot; v-model=&quot;fields.first_name&quot;&gt;
      &lt;span v-if=&quot;errors.first_name&quot; class=&quot;error-message&quot;&gt;{{ errors.first_name[0] }}&lt;/span&gt;
    &lt;/div&gt;
  
    &lt;div class=&quot;form-group&quot; :class=&quot;{ 'has-error': errors.last_name }&quot;&gt;
      &lt;input type=&quot;text&quot; class=&quot;form-control&quot; placeholder=&quot;Last name&quot; v-model=&quot;fields.last_name&quot;&gt;
      &lt;span v-if=&quot;errors.last_name&quot; class=&quot;error-message&quot;&gt;{{ errors.last_name[0] }}&lt;/span&gt;
    &lt;/div&gt;
  
    &lt;div class=&quot;form-group&quot; :class=&quot;{ 'has-error': errors.email }&quot;&gt;
      &lt;input type=&quot;email&quot; class=&quot;form-control&quot; placeholder=&quot;Enter email&quot; v-model=&quot;fields.email&quot;&gt;
      &lt;span v-if=&quot;errors.email&quot; class=&quot;error-message&quot;&gt;{{ errors.email[0] }}&lt;/span&gt;
    &lt;/div&gt;
  
    &lt;div class=&quot;form-group&quot; :class=&quot;{ 'has-error': errors.password }&quot;&gt;
      &lt;input type=&quot;password&quot; class=&quot;form-control&quot; placeholder=&quot;Enter password&quot; v-model=&quot;fields.password&quot;&gt;
      &lt;span v-if=&quot;errors.password&quot; class=&quot;error-message&quot;&gt;{{ errors.password[0] }}&lt;/span&gt;
    &lt;/div&gt;
  
    &lt;div class=&quot;form-group&quot; :class=&quot;{ 'has-error': errors.password_confirmation }&quot;&gt;
      &lt;input type=&quot;password&quot; class=&quot;form-control&quot; placeholder=&quot;Confirm password&quot; v-model=&quot;fields.password_confirmation&quot;&gt;
      &lt;span v-if=&quot;errors.password_confirmation&quot; class=&quot;error-message&quot;&gt;{{ errors.password_confirmation[0] }}&lt;/span&gt;
    &lt;/div&gt;
  
    &lt;div class=&quot;form-group&quot;&gt;
      &lt;select class=&quot;form-control&quot; v-model=&quot;fields.country_id&quot;&gt;
         &lt;option value=&quot;0&quot;&gt;Select your country&lt;/option&gt;
         &lt;option v-for=&quot;country in countries&quot; :value=&quot;country.id&quot;&gt;{{ country.name }}&lt;/option&gt;
      &lt;/select&gt;
    &lt;/div&gt;
  
    &lt;div class=&quot;form-group accept pl-1&quot; :class=&quot;{ 'has-error': errors.accept }&quot;&gt;
      &lt;input type=&quot;checkbox&quot; name=&quot;accept&quot; v-model=&quot;fields.accept&quot;&gt;
      &lt;p&gt;I accept &lt;a href=&quot;#&quot; class=&quot;text-link&quot;&gt;The Terms and Conditions&lt;/a&gt;&lt;/p&gt;
      &lt;span v-if=&quot;errors &amp;&amp; errors.accept&quot; class=&quot;error-message&quot;&gt;{{ errors.accept[0] }}&lt;/span&gt;
    &lt;/div&gt;
  
    &lt;div class=&quot;form-group mb-0&quot;&gt;
      &lt;button @click.prevent=&quot;registerUser&quot; type=&quot;submit&quot; class=&quot;btn btn-sm btn-success btn-block&quot;&gt;Register&lt;/button&gt;
    &lt;/div&gt;
  &lt;/form&gt;
  </code></pre>
  <h3>The problem</h3>
  <p>For a reason I was unable to figure out, the app throws this error in the browser (Network tab), with status code <em>422 Unprocessable Content</em>:</p>
  <blockquote>
  <p>The given data was invalid</p>
  </blockquote>
  <h3>Question</h3>
  <p>What am I doing wrong?</p>