Getting error 401 while fetching data with axios in Laravel - laravel

I am trying to fetch some reports with axios in Laravel. I tested it in Postman and everything is fine.
But here I got error 401.
Here is my code:
#Reports.vue file
<template>
<div>
<h1>All reports: </h1>
<div v-for="report in reports" v-bind:key="report.id">
<p>{{ report.description }}</p>
</div>
</div>
</template>
<script>
export default {
name: "Reports",
data () {
return {
reports : [],
}
},
mounted() {
this.fetchReports();
},
methods : {
async fetchReports() {
const {data} = await axios.get('/api/report');
this.reports = data.data;
},
}
}
</script>
#ReportController#index
public function index()
{
$reports = Report::all();
return ReportResource::collection($reports);
}
#api.php
Route::group(['middleware' => 'auth:api'], function () {
Route::apiResource('/report', 'API\ReportController');
});
Thanks in advance. If You need more informations, I will post them.

Laravels auth:api middleware require you to pass Bearer token or ?api_token= url param with your request
Source
And I don't see you passing token with your axios request

Related

How to redirect from inertia post call to laravel back to inertia with new data

i have laravel+vue+inertia situation;
in my VUE component i'm having Form that sends post request to Laravel backend:
<form #submit.prevent="submit">
<button type="submit">GO</button>
</form>
also:
function submit() {
Inertia.post("/api/myMethodInController")
}
in Laravel controller i fetch some data which i want to send back to page where request came from. My controller function ends with:
return Inertia::render('ComponentWhereRequestIsSentFrom', ['data'=>$myData]);
ok. I'm now getting Laravel data in my VUE component (via props), but my URL stays at POST target:
mydomain.com/api/myMethodInController
what can i do to redirect to initial URL, but with new data?
tnx a lot!
Y
1: Set a redirect back with myVariable data in the controller.
return redirect()->back()->with([
'myVariable' => 'foo',
])
2: Define it in HandleInertiaRequests middleware.
public function share(Request $request)
{
return array_merge(parent::share($request), [
'flash' => [
'myVariable' => fn () => $request->session()->get('myVariable'),
],
]);
}
3: Get it in the component.
<template>
{{ $page.props.flash.myVariable }}
</template>
<script setup>
import { usePage } from '#inertiajs/inertia-vue3'
const myVariable = usePage().props.value.flash.myVariable
</script>

Axios gives undefined while accessing data at Vue's componenet in Laravel

I'm using Laravel and Vue's component, and when i try to access the banners property from response returned by axios in vue component it gives me undefined.
I am accessing the perperty like response.data.banners
I'm returning data from controller in following way:
public function getBanners(Request $request){
return response()->json(['
banners'=> BannerImage::active()->get()
]);
}
Here is how i am accessing axios response
<script>
export default {
data: function() {
return {
banners: []
}
},
mounted() {
axios.get("getBanners").then((res)=> {
console.log(res);
console.log(res.data);
console.log(res.data.banners);
this.banners = res.data.banners;
});
console.log('Component mounted.')
}
}
</script>
Response by axios
All is working before accessing the banners property. Is there anything i am not doing correct ?
You have an linebreak ↩ between ' and banners, which is shown in the console line 2 "↩ banners":
Problem
public function getBanners(Request $request){
return response()->json([' // <-- ↩ line break
banners'=> BannerImage::active()->get()
]);
}
Correct
public function getBanners(Request $request) {
return response()->json([
'banners' => BannerImage::active()->get()
]);
}

Laravel cashier stripe issue with 3d secure cards not redirection to confirmation page

Im struggling to get a Laravel Cashier Strip integration to work with 3d secure cards.
I have go it setup so subscription works and is showing up in my stripe dashboard and everything it getting to my local database.
But when I test with cards that needs strong authntication as 3ds they get the status of incomplete in my stripe dashboard.
I get the cashier.payment response page in my console log. but isn't Cashier supposed to redirect to this confirmation window?
My code is as follows
In my subscription controller i have
public function index() {
$data = [
'intent' => auth()->user()->createSetupIntent(),
// 'plans' => $available_plans
];
return view('artists.subscription')->with($data);
}
public function checkout(Request $request) {
$user = auth()->user();
$paymentMethod = $request->payment_method;
$planId = 'monthly_sub';
// SCA
try {
$subscription = $user->newSubscription('monthly', $planId)->create($paymentMethod);
} catch (IncompletePayment $exception) {
return redirect()->route(
'cashier.payment',
[$exception->payment->id, 'redirect' => route('front')]
);
}
// return response(['status' => 'Success']);
}
and in my stripe js file I have this
const stripe = Stripe('stripe_key'); // i have my test key here
const elements = stripe.elements();
const cardElement = elements.create('card',{hidePostalCode: true});
cardElement.mount('#card-element');
const cardHolderName = document.getElementById('card-holder-name');
const cardButton = document.getElementById('card-button');
const clientSecret = cardButton.dataset.secret;
cardButton.addEventListener('click', async (e) => {
const { setupIntent, error } = await stripe.confirmCardSetup(
clientSecret, {
payment_method: {
card: cardElement,
billing_details: { name: cardHolderName.value }
}
}
);
axios.post('checkout', {
payment_method: setupIntent.payment_method
}).then(response => {
console.log(response.request.responseURL)
})
.catch(error => {
console.log(error.response)
});
});
My blade view is
#extends('layouts.app')
#section('head')
#php
// dd($intent);
#endphp
<script src="https://js.stripe.com/v3/"></script>
<link href="{{ asset('css/stripe.css') }}" rel="stylesheet">
#endsection
#section('content')
<input id="card-holder-name" type="text">
<!-- Stripe Elements Placeholder -->
<div id="card-element"></div>
<button id="card-button" data-secret="{{ $intent->client_secret }}">
subscribe
</button>
#endsection
#section('js')
<script src="{{ asset('js/stripe.js') }}" type="text/javascript"></script>
#endsection
Everything seems to be working but I just get the 3ds confirmation page as a response in my console. How do I get laravel to redirect and open that page for the user?
I think the issue is the order of events, your code should wait for 3DS to be called and completed before calling back to your code after the result is handed back to you. Using this regulator card [1] you should be able to test that with some small changes like this (I had to remove some things but this should be a reference):
stripe.confirmCardSetup(
"seti_xxx", {
payment_method: {
card: card,
billing_details: { name: "Name" }
}
}).then(function(result) {
// Check the result status here!!
axios.post('checkout', {
payment_method: result.setupIntent.payment_method
}).then(response => {
console.log(response.request.responseURL)
}).catch(error => {
console.log(error.response)
});
});
Hope this helps!
[1] https://stripe.com/docs/testing#regulatory-cards

Tag search in laravel vue

I've made a search function to show related projects based on chosen tag and I'm getting results with wrong values
What I've done so far
Create controller function and return results as json
Create route in app.js
Create new component to show results
made axios request to send data to controller and redirect to new component for results
Code
controller
public function areas(Request $request){
$areas = Project::where('area', $request->area)->where('published', '=', 'y')->get();
return response()->json($areas, 200);
}
route in api.php
Route::get('areasearch', 'Api\SearchController#areas');
route in app.js
import AreasPage from './components/areassearch.vue'
{
path: '/areas',
name: 'areas',
props: true,
component: AreasPage,
},
search script + component link
// link
<a v-model.lazy="area" #click="areasearch">{{project.area}}</a>
//script
methods: {
//search in areas
areasearch() {
axios.get('/api/areasearch', {
params: {
area: this.area
}
})
.then(response => {
this.$router.push({
name: 'areas',
params: {
areas: response.data
}
})
})
.catch(error => {});
},
},
results component
<template>
<div>
<navbar></navbar>
<template v-if="areas.length > 0">
<div class="container-fluid counters">
<div class="row text-center">
<div v-for="area in areas" :key="area.id" :to="`/projects/${area.slug}`">
<li>{{area.title}}</li>
</div>
</div>
</div>
</template>
<template v-else>
<p>Sorry there is no area for you, try search new query.</p>
</template>
<footerss></footerss>
</div>
</template>
<script>
import navbar from './navbar.vue';
import footerss from './footer.vue';
export default {
props: ['areas'],
components: {
navbar,
footerss
},
}
</script>
Issue
My link is not behave as a link (is like text when i move mouse over it)
For example if I search for area Jakarta most of results I get is projects where their area column is null.
Any idea?
For the link part, you are using v-model on an anchors, v-model is mainly for inputs, selects, textareas. So
<a v-model.lazy="area" #click="areasearch">{{project.area}}</a>
Should be
<span class="my-link" #click="areasearch(project.area)">{{project.area}}</span>
Use a span, and a class for that span, then on click call your method, i don't know if thats the correct variable for your axios call, btw. it could be project.area.id, or something else...
As for it looking like a link, i assume you are familiar with cursor:pointer css rule.
Your axios part should look something like this:
areasearch(thearea) {
axios.get('/api/areasearch', {
params: {
area: thearea
}
})
.then(response => {
this.$router.push({
name: 'areas',
params: {
areas: response.data
}
})
})
.catch(error => {});
},
As for the controller part:
public function areas(Request $request){
$auxAreas = explode("+", $request->area);
$areas = Project::whereNotNull('area')
->whereIn('area', $auxAreas)
->where('published', '=', 'y')
->get();
return response()->json($areas, 200);
}
first for the wrong result issue try this:
public function areas(Request $request){
$areas = Project::whereNotNull('area')
->where([
['area', $request->area],
['published', '=', 'y']
])->get();
return response()->json($areas, 200);
}

Call AJAX with Vue.js and Vue resource in Laravel

I'm making AJAX request in Laravel with Vue.js and Vue resource.
I have view:
{{Form::open(['method' => 'post', 'class' => 'form-inline', 'id' => 'main-form'])}}
{{Form::text('param1', null, ['id' => 'param1', 'class' => 'form-control'])}}
{{Form::text('param2', null, ['id' => 'param2', 'class' => 'form-control'])}}
<input #click="sendIt($event)" type="submit" value="Check prices" class="btn btn-success btn-theme" />
{{Form::close()}}
I have js:
var Vue = require('vue');
var VueResource = require('vue-resource');
Vue.use(VueResource);
Vue.http.headers.common['X-CSRF-TOKEN'] = $('meta[name=_token]').attr('content');
const app = new Vue({
el: '#app',
methods: {
sendIt: function (e)
{
e.preventDefault();
var token = $('[name="_token"]').val();
this.$http.post('/data').then((response) => {
console.log(response);
}, (response) => {
console.log(response);
});
}
}
Route:
Route::post('/data', 'MainController#data');
And controller:
public function data()
{
$msg = $this->test(); //method that retrieves data from db
return response()->json(['msg'=> $msg], 200);
}
It gives me post 500 internal server error
In response I have this headers:
Cache-Control
Content-Type
Date
Phpdebugbar-Id
Server
Status
Transfer-Encoding
X-Powered-By
In network in my data site I have response headers without token, request headers with token and I have token in Request Payload.
If I change method to get I have same error but if I change method to get and if I remove from my controller part of code where I retrieve data from db and just pass string to json (example:
$msg = 'test';
return response()->json(['msg'=> $msg], 200);
I have success and I can output test on page.
So I'm not sure if it's some problem with token or something else.
I tried and this:
var token = $('[name="_token"]').val();
this.$http.post('/prices', {_token:token})
but nothing. Same error again.
If I add this:
http: {
headers: {
X-CSRF-TOKEN: document.querySelector('#token').getAttribute('content')
}
},
I have syntax error on page load.
If I change to this:
http: {
headers: {
Authorization: document.querySelector('#token').getAttribute('content')
}
}
I got internal server error again.
And this is my token in main view:
<meta name="csrf-token" id="token" content="{{ csrf_token() }}">
<script>
window.Laravel = <?php echo json_encode([
'csrfToken' => csrf_token(),
]); ?>
</script>
EDIT:
This part works if I add quotes around x-csrf-token but still I have token mismatch error.
http: {
headers: {
'X-CSRF-TOKEN': document.querySelector('#token').getAttribute('content')
}
},
I could be mistaken but in your example at the top you have:
Vue.http.headers.common['X-CSRF-TOKEN'] = $('meta[name=_token]').attr('content');
However, in your main view file you have:
<meta name="csrf-token" id="token" content="{{ csrf_token() }}">
You should be able to simply change $('meta[name=_token]') to $('meta[name=csrf-token]') (so they match).
Furthermore, the reason you had a syntax error with X-CSRF-TOKEN: ... is because you can't use hyphens in key names unless you wrap them in quotes i.e. 'X-CSRF-TOKEN': ....
Hope this helps!

Resources