VueRouter make HTTP request within beforeEach - vue.js

I am attempting to make an AXIOS request within router.beforeEach. However, it looks like the request is being made with my next destination URL being prepended; if trying to access /client/create, the beforeEach appears to prepend '/client/create' to the request.
Instead of '/api/participant/test/{some_id}' the request is being sent to '/client/create/api/participant/{some_id}'.
I'm not quite sure why this is happening. The documentation indicates that you could use a getPost() method to make requests:
beforeRouteEnter (to, from, next) {
getPost(to.params.id, (err, post) => {
next(vm => vm.setData(err, post))
})
},
However it seems the getPost() method is unrecognized, which could be because of the beforeEach call (the documentation does not show that this could be used with this particular method).
Here is the code with the AXIOS request.
router.beforeEach((to, from, next) => {
console.log(to.params.id);
// Check to see if the cookie exists
if (document.cookie.match(/^(.*;)?\s*participant_token\s*=\s*[^;]+(.*)?$/)) {
axios.get('api/participant/test/' + to.params.id)
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.log(error);
});
}
Any ideas on how this can be avoided? I imagine one could use beforeRouteEnter for each of the routes I have set up, but this would be a more elegant solution.

It should be
axios.get('/api/participant/test/' + to.params.id)
(with forward slash character at the beginner).
The more properly way to set baseURL in axios config
For example:
axios.defaults.baseURL = 'your base url';

First, there is no built-in getPost method in Vue.js. Documentation has mentioned it just as an illustration purpose.
Also, use root relative URL instead of relative URL that you are trying to use.
axios.get('/api/participant/test/' + to.params.id)
You are trying to use relative URL which is causing a problem for you. The more generic way would be to set default base URL in Axios global config.

Related

how solve 404 error in axios post request in vue?

i want send request to an api but i have 404 erro and i have nothing in network
can you help me?
my code:
loginMethod() {
const config = {
userName: "test#gmail.com",
password: "1234test",
};
return new Promise((resolve) => {
ApiService.post("api/authentication/login", config)
.then(({ data }) => {
console.log(data);
resolve(data);
})
.catch(({ response }) => {
console.log(response);
});
});
},
and ApiService function:
post(resource, params) {
console.log(params);
const headers = {
"E-Access-Key": "bb08ce8",
};
return Vue.axios.post(`${resource}`, params, { headers: headers });
},
Based only on what I can see in your code, you are not telling axios the complete URL if I'm right about it, and you didn't declare it somewhere else do this:
axios.post('yourdomain.com/api/authentication/login',params)
or
axios({
url:'yourdomain.com/api/authentication/login',
method:post,
data:{}
})
or
in your main js file or any other file that you import axios (if you are sharing an instance of it globali):
axios({baseurl:'yourdomain.com'})
and then you don't need to write the complete url everywhere and just insert the part you need like you are doing now and axios will join that address with the baseurl,I hope it helps
I guess the URL "api/authentication/login" might be wrong and the correct one would be "/api/authentication/login" that starts with /.
404 error means the resource referred by the URL does not exist. It happens when the server has deleted the resource, or you requested a wrong URL accidentally, or any wrong ways (e.g. GET vs POST)
To make sure if you were requesting to the correct URL (and to find where you're requesting actually), open Google Chrome DevTools > Network panel. You might need reload.
The url api/xxx is relatively solved from the URL currently you are at. If you were at the page http://example.com/foo/bar, the requested URL becomes http://example.com/foo/bar/api/xxx. Starting with / means root so http://example.com/api/xxx.
This answer might help to understand the URL system: https://stackoverflow.com/a/21828923/3990900
"404" means your API Endpoint is not found. You need to declare the location of your API Endpoint exactly. For example: http://localhost:8080/api/authentication/login.

How to use Nuxt $auth inside an axios plugin (How to add Token to all axios requests)

Im looking to use $auth inside my Nuxt project, specially inside an axios plugin.
Here is my code:
plugins/api.js
export default function ({ $axios }, inject) {
const api = $axios.create({
headers: {
common: {
Accept: 'text/plain, */*',
},
},
})
// Set baseURL to something different
api.setBaseURL('http://localhost:4100/')
// Inject to context as $api
inject('api', api)
}
Now the problem comes when I try to use $auth from #nuxtjs/auth-next package.
As stated in the docs:
This module globally injects $auth instance, meaning that you can
access it anywhere using this.$auth. For plugins, asyncData, fetch,
nuxtServerInit and Middleware, you can access it from context.$auth.
I tried the following:
This results in $auth being undefined
export default function ({ $axios, $auth }, inject) {
This one was near
export default function ({ $axios, app }, inject) {
console.log(app) //This one logs $auth in the object logged
console.log(app.$auth) // I don't understand why but this one returns undefined
My main goal here is to make use of this.$auth.strategy.token.get()and pass it (if the token exists of course) to the headers of every request made using this.$api
I have been looking for similar questions and answers but none has helped me to solve this, I could just add the token every time I write this.$api but that would increase the code unnecessarily.
Thanks in advance to all the people for your time and help.
EDIT:
Okay, now I made a test. and the next code is actually logging the $auth object correctly, it seems some time is needed to make it work but now Im afraid that using setTimeout could cause an error because I can't know exactly how much time is needed for $auth to be available.
export default function ({ $axios, app }, inject) {
setTimeout(() => {
console.log('After timeout', app.$auth)
}, 50)
EDIT 2:
So now I have made more tests, and using 0 milliseconds instead of 50 works too, so I will use setTimeout with 0 milliseconds for now, I hope anyone find a better solution or explain why $auth is not available before using setTimeout so I can decide what to do with my code.
EDIT 3:
After trying to wrap all my previous code inside setTimeout I noticed that the code fails, so that isn't a solution.
I have found a solution so I will post it so that every person that could have the same problem in the future can solve it.
It turns out that I could easily solve it using interceptors.
export default function ({ $axios, app }, inject) {
// At this point app.$auth is undefined. (Unless you use setTimeout but that is not a solution)
//Create axios instance
const api = $axios.create({
headers: {
common: {
Accept: 'application/json', //accept json
},
},
})
// Here is the magic, onRequest is an interceptor, so every request made will go trough this, and then we try to access app.$auth inside it, it is defined
api.onRequest((config) => {
// Here we check if user is logged in
if (app.$auth.loggedIn) {
// If the user is logged in we can now get the token, we get something like `Bearer yourTokenJ9F0JFODJ` but we only need the string without the word **Bearer**, So we split the string using the space as a separator and we access the second position of the array **[1]**
const token = app.$auth.strategy.token.get().split(' ')[1]
api.setToken(token, 'Bearer') // Here we specify the token and now it works!!
}
})
// Set baseURL to something different
api.setBaseURL('http://localhost:4100/')
// Inject to context as $api
inject('api', api)
}
Also Nuxt Auth itself has provided a solution for this issue:
https://auth.nuxtjs.org/recipes/extend/

Why does the use() method still executed after get() has handled a request successfully in express.js?

I have this express.js code:
app.get('/', (req, res) => {
res.render('homePage', { title: 'Express' });
});
app.use((req, res) => {
console.log('use() is executed');
res.end();
});
If the request is handled by the get() method, use() is not supposed to execute. But I noticed that it still execute even though everything was fine and the page is rendered. Did I do something wrong or did I miss something? Thanks.
From Express Doc:
Link: http://expressjs.com/en/4x/api.html#app.use
app.use([path,] callback [, callback...])
Mounts the specified middleware function or functions at the specified path: the middleware function is executed when the base of the requested path matches the path.
app.use() register the function as middleware, and you didn't specify the path. That's why it will run every time when any route is called.
The placement of the middlewares will change the execution order. However, they don't change the fact that the middleware will be executed as, well middlewares, which will be executed before the actual functions with in the routes.

Using vue router BeforeRouteEnter method to wait for http request to complete

Hi I'm trying to make it so that when a user opens a page it won't open until the data from the server is successfully retrieved so that it won't appear after 0.5s or so after the user enters.
To do this I read that I need to use BeforeRouteEnter but I'm having trouble finding information on how to properly use this, especially with waiting for my REST API to complete its request.
Here's the method I want to wait to complete before routing to my new component:
async getThread() {
const response = await postsService.fetchOneThread({
id: this.blockId,
topic: this.topicId,
thread: this.postId
});
this.thread = response.data;
}
so once this.thread = response.data only then do I want the page to display.
An important thing to note is that I am also passing through URL parameters to get the data which is the topic/black/post ID.
Here is my getUrlParam method also
url() {
let x = this.$route.params.topic.split('-');
this.topicId = x[0];
let y = this.$route.params.id.split('-');
this.blockId = y[0];
let post = this.$route.params.thread.split('-');
this.postId = post[1];
this.getThread();
}
Thanks
You need to move getThread inside beforeRouteEnter
beforeRouteEnter: (to, from, next) => {
postsService.fetchOneThread({
id: this.blockId,
topic: this.topicId,
thread: this.postId
}).then( response => {
//store the data somewhere accessible
next()
})
},
A few notes:
I don't think beforeRouteEnter can be async, so I'm using then to get the response
the component is not yet ready, so you can't access it yet, you need to save the information some other place so it can be read by the component. I'd suggest using Vuex for this.
If you decide to use Vuex than you need to add a mutation and call it from the promise's callback.
store.commit('ADD_THREAD', response.data)

res.render for routes on page reload?

(Using MEAN with UI Router)
The following code sends a json response for the route defined. This works fine when the template is rendered with UI Router; however, if I reload the page, because the response only contains json, I am left with an empty page rendering no html, only the json response.
router.get('/posts/:post', function(req, res, next) {
req.post.populate('comments', function(err, post) {
if (err) { return next(err); }
res.json(post);
});
});
Assuming this is a standard issue, how can I best allow this page to res.render('index') when the page is reloaded and respond with the json response? Should I,
Create a separate route for the json response which is called as a post promise with UI Router
Have the /posts/:post route simply respond with res.render('index')?
Thank you for any responses, not sure what the usual practise is for such issues!
It took me a while to find a working solution to this due to many of the examples online having different directory structures. I placed a catch all at the end of my routes so that url requests to any UI Router states would not be met with a 404, but instead always return the index.html file.
app.all('/*', function(req, res, next) {
// Just send the index.html for other files to support HTML5Mode
res.sendFile('index.html', { root: __dirname });
});
Then I added prefixes to my express routes, e.g. /api/posts/:post etc. Apparently express routes should not clash with any of the angular defined routes. Thanks to NormySan on reddit for informing me about this.