Laravel Sanctum Breeze with Next JS - laravel

I just installed this https://github.com/laravel/breeze-next repository and as expected everything works fine as documented. Login, Logout and registration work fine.
Now after login, I want to protect the API routes, but it throws errors as 401 when I try to access the protected route even after login.
Here is AXIOS setup as given in Repo,
import Axios from 'axios'
const axios = Axios.create({
baseURL: process.env.NEXT_PUBLIC_BACKEND_URL,
headers: {
'X-Requested-With': 'XMLHttpRequest',
},
withCredentials: true,
})
export default axios
I just added a server call with Axios with \api\test
export async function getStaticProps() {
const response = await axios.get(`/api/test`);
return {
props: {
customers: response.data
},
}
}
This is API in laravel.
Route::middleware(['auth:sanctum'])->get('/test', function () {
return response()->json([
'val' => 1,
'msg' => 'successfully',
]);
});
If I remove middleware, it works fine. But when added middleware auth sanctum, it always shows 401 error.
Server Error
Error: Request failed with status code 401
This error happened while generating the page. Any console logs will be displayed in the terminal window.
So I can give authentication in SPA with sanctum?

Have you already added sanctum to your kernel.php?
By default \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,in your Kernel.php is commented out.
It should be look like that:
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],

I was facing the same problem and instead using getStaticProps function I was able to resolve using useEffect() using the axios setup provinding by the repo, so you could try this way instead.
Assuming your directories structure pages/test.js, in your case would be:
import axios from "../lib/axios";
import {useEffect, useState} from "react";
import AppLayout from "../components/Layouts/AppLayout";
const Test = () => {
const [customers, setCustomers] = useState()
useEffect(() => {
axios
.get("/api/tests")
.then((response) => {
setCustomers(response.data);
})
.catch((error) => console.error(error));
}, []);
return (
<AppLayout
header='Customers'
>
<Head>
<title>Customers</title>
</Head>
<div className="py-12">
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div className="p-6 bg-white border-b border-slate-200">
{customers.map((customer, index) => (
<div key={customer.val}>
<div>
{customer.val}
{customer.message}
</div>
</div>
))}
</div>
</div>
</div>
</div>
</AppLayout>
)
}
And if you need to create a detail view with the same method within this directory structure test/[id].js:
import axios from "../../lib/axios";
import AppLayout from "../../components/Layouts/AppLayout";
import Head from "next/head";
import {useEffect, useState} from "react";
import {useRouter} from "next/router";
const Profiles = () => {
const [customer, setCustomer] = useState()
// Use router to get the id from the url your visiting
const router = useRouter();
useEffect(() => {
if(!router.isReady) return;
axios
.get(`/api/tests/${router.query.id}`) // Here we accessing the url parameter from useRouter()
.then((response) => {
setCustomer(response.data);
})
.catch((error) => console.error(error));
}, [router.isReady]);
return (
<AppLayout
header='Customer'
>
<Head>
<title>Customer</title>
</Head>
<div className="py-12">
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div className="p-6 bg-white border-b border-slate-200">
<div>
{customer.val}
{customer.message}
</div>
</div>
</div>
</div>
</div>
</AppLayout>
)
}
credits:
Use axios within useEffect How do I fix the 401 Unauthorized error with Laravel Sanctum and React?
Get url parameter from useRouter() https://github.com/vercel/next.js/discussions/12661#discussioncomment-360764

Related

Alpinejs x-if is not being triggered

I have data that I am pulling from ajax. And I want this data display only when it is successfully pulled.
import Alpine from 'alpinejs'
import axios from 'axios'
const http = axios.create({
baseURL: 'url',
})
window.axios = http
window.Alpine = Alpine
document.addEventListener('alpine:init', () => {
Alpine.data('cart', () => ({
items: null,
init(){
window.axios.get('wc/store/cart')
.then(({data})=>{
this.items = data
console.log(this.items)
}).catch(error => {
console.log(error.toString())
})
},
}))
})
Alpine.start()
Now I am using this in my template
<div x-data="cart">
<template x-if="items">
<h1>Shopping Cart</h1>
<!-- display items here -->
</template
</div>
The thing is, the h1 element is displayed but not the data from ajax.
Am I doing anything wrong. I am pretty confidence this should work.
You're not displaying your items. Keep in mind that template tags require a single root element only.
<div x-data="card">
<template x-if="items">
<div>
<h1>Shopping Cart</h1>
<template x-for="item in items">
<div>
<h2 x-text="item.text"></h2>
</div>
</template>
</div>
</template>
</div>

How to use my custom API with Vue Metronic template Axios

I've trouble when using Template Metronic Vue (demo 7).
I've difficult with using login/register default Metronic Template, so I want to make my custom Login/register and another method CRUD with Laravel MIX API, But when I requested API with Axios, the request always catch Error.
is there any special method when I access custom API in Metronic templates?
In this code, I want to try console.log(). This is code :
<b-form class="form" #submit.stop.prevent="onSubmit">
<b-form-input
class="form-control form-control-solid h-auto py-5 px-6"
type="email"
v-model="this.form.email"
></b-form-input>
<b-form-input
class="form-control form-control-solid h-auto py-5 px-6"
type="password"
v-model="this.form.password"
></b-form-input>
<button type="submit" class="btn btn-primary font-weight-bold px-9 py-4 my-3 font-size-3">
Sign In
</button>
</b-form>
<script>
import axios from 'axios'
export default {
name: 'login',
data() {
return {
form: {
email: '',
password: ''
}
}
},
methods: {
onLogin() {
axios.post('http://localhost:8000/api/getUser')
.then(response =>
console.log(response)
})
.catch(error => {
console.log('error created')
console.log(error)
})
}
}
}
</script>
postman
console
To use this code you should remove two things:
Remove MockService initialization from the main.js
// Remove this to disable mock API
MockService.init();
Remove API initialization from the main.js
// API service init
ApiService.init();

Unknown custom element: <app-home> - did you register the component correctly? For recursive components, make sure to provide the "name" option

I have this problem but i try some solutions in web but and i can't resolve it: Unknown custom element:
- did you register the component correctly? For recursive components, make sure to provide the "name" option.
The problem appears to be in those fils :
Please I need help as soon as possible
routes.js:
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../components/Home.vue";
import PostDetails from "../components/PostDetails.vue";
Vue.use(VueRouter);
const routes = [{
path: "/",
component: Home,
name: "Home"
},
{
path: "/post/:slug",
component: PostDetails,
name: "postDetails"
}
];
const router = new VueRouter({
routes: routes,
hashbang: false,
mode: "history"
});
export default router;
app.js:
import Vue from "vue";
import VueRouter from "vue-router";
require('./bootstrap');
window.Vue = require('vue');
Vue.component(key.split('/').pop().split('.')[0], files(key).default))
Vue.component('app-home', require('./AppHome.vue'));
import router from "./routes/routes.js";
const app = new Vue({
el: '#app',
vuetify,
render: h => h(App),
router: router,
});
AppHome.vue:
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
export default {
};
</script>
Home.vue:
<template>
<div class="container">
<div class="row my-4">
<div class="col-md-8">
<div class="card">
<div class="card-header">Articles</div>
<div
class="card-body"
:key="index"
v-for="(post, index) in posts.data"
>
<div class="media">
<img
:src="post.photo"
class="rounded img-fluid mr-2 shadow-sm"
alt=""
srcset=""
/>
<div class="media-body text-justify">
<router-link :to="post.path">
<h3>{{ index }}:{{ post.title }}</h3>
</router-link>
<p>
<span class="textdefaut">
{{ post.user.name }}
</span>
<span class="text-danger">
{{ post.added }}
</span>
</p>
<p class="lead text-justify">
{{ post.body.substr(0, 200) }}...
</p>
<hr />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
posts: {},
};
},
created() {
this.getPosts();
},
methods: {
getPosts() {
axios
.get("/api/posts")
.then((response) => {
console.log(response.data);
this.posts = response.data;
})
.catch((err) => console.log(err));
},
},
};
</script>
Post Details:
<template>
<div>
Posts details , This shows that the route is really working!!
<router-link to="/Home"><a>Back to the root</a></router-link>
</div>
</telpmate>
<script>
export default {
data () {
return {
message: 'Hoera!!!!'
};
}
};
</script>
If all of your Vuejs components (including AppHome.vue) are in /resources/js/components directory, you must change:
Vue.component('app-home', require('./AppHome.vue'));
by
Vue.component('app-home', require('./components/AppHome.vue'));
...in your app.js
Try to append .default option:
Vue.component('app-home', require('./components/AppHome.vue').default);

Laravel 6 + Vue.js Failed to mount component: template or render function not defined

Perhaps someone could help me? I'm trying to create a little chat app from here and I am have trouble displaying the Vue components.
The dev tools console gives me:
Failed to mount component: template or render function not defined.
I am using Laravel 6
Appreciate any help on this one! thanks :)
I have tried deleting the node_modules folder and rebuilding, after adding .default - with no luck.
app.js
require('./bootstrap');
window.Vue = require('vue');
/**
* The following block of code may be used to automatically register your
* Vue components. It will recursively scan this directory for the Vue
* components and automatically register them with their "basename".
*
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
*/
const files = require.context('./', true, /\.vue$/i)
files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
Vue.component('chat-messages', require('./components/ChatMessages.vue').default);
Vue.component('chat-form', require('./components/ChatForm.vue').default);
import Vue from 'vue'
const app = new Vue({
el: '#app',
data: {
messages: []
},
created() {
this.fetchMessages();
Echo.private('chat')
.listen('MessageSent', (e) => {
this.messages.push({
message: e.message.message,
user: e.user
});
});
},
methods: {
fetchMessages() {
axios.get('/messages').then(response => {
this.messages = response.data;
});
},
addMessage(message) {
this.messages.push(message);
axios.post('/messages', message).then(response => {
console.log(response.data);
});
}
}
});
and my two components:
ChatForm.vue
<template>
<div class="input-group">
<input id="btn-input" type="text" name="message" class="form-control input-sm" placeholder="Type your message here..." v-model="newMessage" #keyup.enter="sendMessage">
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" id="btn-chat" #click="sendMessage">
Send
</button>
</span>
</div>
</template>
<script>
export default {
props: ['user'],
data() {
return {
newMessage: ''
}
},
methods: {
sendMessage() {
this.$emit('messagesent', {
user: this.user,
message: this.newMessage
});
this.newMessage = ''
}
}
}
</script>
ChatMessage.vue
<template>
<ul class="chat">
<li class="left clearfix" v-for="message in messages" v-bind:key="message">
<div class="chat-body clearfix">
<div class="header">
<strong class="primary-font">
{{ message.user.name }}
</strong>
</div>
<p>
{{ message.message }}
</p>
</div>
</li>
</ul>
</template>
<script>
export default {
props: ['messages']
};
</script>
This might help you to solve your problem, if not just tell me to find new solution. first remove this in your app.js
const files = require.context('./', true, /\.vue$/i)
files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
Next, remove also this code, you already imported vue twice.
import Vue from 'vue'

vue components wont load

I try to work with vuejs in laravel, I installed npm vue-router vue-axios but when i try to load my page i get console error like: ReferenceError: CreateCategory is not defined and empty page.
here is my app.js:
require('./bootstrap');
window.Vue = require('vue');
import VueRouter from 'vue-router';
Vue.use(VueRouter);
import VueAxios from 'vue-axios';
import axios from 'axios';
Vue.use(VueAxios, axios);
import App from './App.vue';
Vue.component('CreateCategory', require('./components/CreateCategory.vue'));
Vue.component('DisplayCategory', require('./components/DisplayCategory.vue'));
Vue.component('EditCategory', require('./components/EditCategory.vue'));
const routes = [
{
name: 'CreateCategory',
path: '/categories/create',
component: CreateCategory
},
{
name: 'DisplayCategory',
path: '/',
component: DisplayCategory
},
{
name: 'EditCategory',
path: '/edit/:id',
component: EditCategory
}
];
const router = new VueRouter({ mode: 'history', routes: routes});
new Vue(Vue.util.extend({ router }, App)).$mount('#app');
// const app = new Vue({
// router,
// render: h => h(App)
// });
// const app = new Vue({
// el: '#app'
// });
PS: I read articles about component in router and I already tried with .default that won't work neither they only good of that was i didn't get console error.
UPDATE
my CreateCategory.vue component:
<template>
<div>
<h1>Create A Category</h1>
<form v-on:submit.prevent="addCategory">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Category Title:</label>
<input type="text" class="form-control" v-model="category.title">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Category Status:</label>
<input type="text" class="form-control col-md-6" v-model="category.status" />
</div>
</div>
</div><br />
<div class="form-group">
<button class="btn btn-primary">Add Category</button>
</div>
</form>
</div>
</template>
<script>
export default {
data(){
return{
category:{}
}
},
methods: {
addCategory(){
let uri = 'http://localhost/vuetjd/public/categories';
this.axios.post(uri, this.category).then((response) => {
this.$router.push({title: 'DisplayCategory'})
})
}
}
}
</script>
CreateCategory.vue is a Single File Component.
In there, you must have a export default {}, where {} is actually the Component Object.
What you have to do, is that, you need to import the CreateCategory.vue and then assign it, like so:
import CreateCategory from './components/CreateCategory.vue';
const routes = [
{
name: 'CreateCategory',
path: '/categories/create',
component: CreateCategory
}
];
now this will work.
you have to do the same for DisplayCategory and EditCategory.
I found what is the issue, I'm suppose to run php artisan serve to be able to see my data. if just open my url i'll get blanck page but with serve i get my data as well.

Resources