Call Laravel 8 login API with VueJS 3 App

Viewed 777

I'm new to programming with VueJs, and I'm making a simple app that allows the user to login and once authenticated show a list of services in a table.

I manage authentication through Laravel, then I expose APIs (tested with Insomnia and working correctly) that I call from my VueJS application.

So I made in my Vue project a component called LoginPage.vue and in which I call the API for login. To do this I have read documentation and examples online.

I have this problem, when I fill in the login form and click on the Login button on the browser opening the developer tools, in the console I have error 404.

Having no experience with vue I cannot understand what the problem may be.

I appreciate any advice or suggestions

  • LoginPage.vue
<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <p>Compila il form sottostante con le tue credenziali per effettuare il login</p>
    <div>
      <form v-on:submit.prevent="loginForm">
        <div class="form-group">
          <input
            type="text"
            class="form-control"
            placeholder="Immetti la tua mail"
            id="mail"
            v-model="mail"
          >
        </div>
        <div class="form-group">
          <input
            type="password"
            class="form-control"
            placeholder="Immetti la tua password"
            id="psw"
            v-model="psw"
          >
        </div>
          <button class="btn btn-primary">Login</button>
      </form>
    </div>
    <p>oppure accedi con la tua identit&agrave; digitale SPID</p>
    <div> TODO - SPID BUTTON HERE</div>
  </div>
</template>

<script>

export default {
  name: "LoginPage",
  props: {
    msg: String,
  },
  data() {
    return {
      info: null
    };
  },
  created() {
    // Simple POST request with a JSON body using fetch
    const requestOptions = {
      method: "POST",
      headers: { "Content-Type": "application/json" }
    };
    fetch("http://localhost:8000/api/login", requestOptions)
      .then(response => response.json())
      .then(data => (this.info = data));
  }
};

</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

EDIT:

I've modified my code like the code below, and now it works well, I place the code here that works correctly, hoping it will be of help to others as well

  • LoginPage.vue
<template>
  <div class="hello">
    <h1 style="font-size: 28px">{{ msg }}</h1>
    <p>
      Compila il form sottostante con le tue credenziali per effettuare il login
    </p>
    <div>
      <form class="login-form" @submit.prevent="doLogin">
        <div class="form-field">
          <input type="text" placeholder="email" v-model="user.email" />
        </div>
        <div class="form-field">
          <input
            type="password"
            placeholder="password"
            v-model="user.password"
          />
        </div>
        <div class="form-action">
          <button class="login-btn" type="submit">Submit</button>
        </div>
      </form>

      <span v-if="loading && !show">Loading...</span>
      <div v-else-if="show">
        <p>Login success: {{ successMessage }}</p>
        <p>Token: {{ token }}</p>
      </div>
    </div>
    <p>oppure accedi con la tua identit&agrave; digitale SPID</p>
    <div>TODO - SPID BUTTON HERE</div>
  </div>
</template>

<script>
export default {
  name: "LoginPage",
  props: {
    msg: String,
  },
  data() {
    return {
      user: {
        email: '',
        password: ''
      },
      show: false,
      loading: false,
      successMessage: '',
      token: ''
    }
  },
  methods: {
  async postData(url = '', data = {}) {
    const response = await fetch(url, {
      method: 'POST', // *GET, POST, PUT, DELETE, etc.
      headers: {
        'Content-Type': 'application/json'
      },
        body: JSON.stringify(data)
     });
     
     
     return response.json(); // parses JSON response into native JavaScript objects
    },
    doLogin() {
    this.loading = true
       this.postData('http://localhost:8000/api/login', this.user)
        .then(data => {
          this.token = data['data'].token;
          this.successMessage = 'Login avvenuto correttamente';
          this.loading = false;
          this.show = true;
        });
    
    }
  }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

1 Answers

First of all you have your api call in the created lifecycle hook and what you want is to bind the api call to the button clicked in your form. I also don't see any models in your data object. You are using the fetch api wrong, let me explain:

The steps:

  1. Setup the correct markup for a form
  2. Make the user object with the keys email and password and put that in your data object.
  3. When you use submit.prevent you will need to add a button in the form with the type submit
  4. Create a function in the methods object of Vuejs and add that to submit.prevent in your form

Here is an example with a test api:

const template = `
<div>
  <form class="login-form" @submit.prevent="doLogin">
  <div class="form-field">
    <input type="text" placeholder="Email" v-model="user.email" />
  </div>
  <div class="form-field">
    <input type="password" placeholder="Wachtwoord" v-model="user.password" />
  </div>
  <div class="form-action">
    <button class="login-btn" type="submit">Submit</button>
  </div>
</form>

<span v-if="loading && !show">Loading...</span>
<div v-else-if="show">
<p>Login success: {{ successMessage }}</p>
<p>Token: {{ token }} </p>
</div>
</div>
`;

const LoginForm = {
  name: 'LoginForm',
  data() {
    return {
      user: {
        email: 'eve.holt@reqres.in',
        password: 'cityslicka'
      },
      show: false,
      loading: false,
      successMessage: '',
      token: ''
    }
  },
  template,
  methods: {
  async postData(url = '', data = {}) {
    const response = await fetch(url, {
      method: 'POST', // *GET, POST, PUT, DELETE, etc.
      headers: {
        'Content-Type': 'application/json'
      },
        body: JSON.stringify(data)
     });
     
     
     return response.json(); // parses JSON response into native JavaScript objects
    },
    doLogin() {
    this.loading = true
       this.postData('https://reqres.in/api/login', this.user)
        .then(data => {
          const { token } = data;
          this.token = token;
          this.successMessage = 'Yes sir!';
          this.loading = false;
          this.show = true;
        });
    
    }
  }
};

new Vue({
  el: '#root',
  components: { LoginForm },
  template: `<LoginForm />`
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="root"></div>

Related