Using async api into main.js of vue js - vue.js

In main.js, from vue project app, I am setting a socket io url using the return of an API.
const url = getAPIAddress(params); //API promises
My problem is that main.js has no async function. So I can´t use async/await.
How could I do that? Or Is there a better way to do it?
//main.js sample
import VueSocketIOExt from "vue-socket.io-extended";
import io from "socket.io-client";
import getAPIAddress from "getAPIAddress";
const url = getAPIAddress(params); //API promises
const socket = io(url, { autoConnect: false });
Vue.use(VueSocketIOExt, socket, { store });
Vue.config.productionTip = false;
Vue.use(VuetifyDialog, {
context: {
vuetify,
},
});

Hello you should try something like :
(async () => {
const url = await getAPIAddress(params); //API promises
// the rest of the code
})();

Related

How to import a utility function that sets cookies into multiple Vue components

I have several components that I need to check if the user logged on/has valid access token
I currently do check this inside a Vue component method using the contents of isLoggedOut function below. I am thinking that I might need to create an external js file and import this js everywhere that I need to check of credentials. So js function will look sthg like below. However this function also resets the cookies in the component. see this.$cookies. I don't think this is possible due to scoping.
So how can I import functions (like from a utility js file) that also changes this objects? Or is there a better way of what avoiding code duplication in Vue/check for log out in multiple components using same code
import axios from "axios";
function isLoggedOut() {
axios.defaults.withCredentials = true;
const isLoggedOut = True;
const path = `/user_authentication/protected`;
axios
.get(path, { withCredentials: true })
.then((response) => {
message = response.data["user"];
isLoggedOut = false;
return isLoggedOut;
})
.catch((error) => {
console.error(error);
this.$cookies.remove("csrf_access_token");
isLoggedOut = true;
return isLoggedOut;
});
}
Create an index.ts file in a folder named utils and export the funtion isLoggedOut.
Pass the Vue app to the function isLoggedOut as a prop and call the vue methods.
import Vue from 'vue'
import axios from "axios";
export function isLoggedOut(app: Vue) {
axios.defaults.withCredentials = true;
const isLoggedOut = True;
const path = `/user_authentication/protected`;
axios
.get(path, { withCredentials: true })
.then((response) => {
message = response.data["user"];
isLoggedOut = false;
return isLoggedOut;
})
.catch((error) => {
console.error(error);
app.$cookies.remove("csrf_access_token");
isLoggedOut = true;
return isLoggedOut;
});
}
Component
import { isLoggedOut } from '~/utils'
export default {
methods: {
logOut() {
// Passing the Vue app
isLoggedOut(this)
}
}
}

Quasar Axios request wrong URL (Double URL)

The Error Image
when i send request via axios with url axios concatenate url of api
with the url of the quasar dev server how can i neglect this
concatenation and send the API url only there is any configuration for
baseUrl of axios with quasar ?
src/boot
import axios from 'axios'
export default async ({ Vue }) => {
axios.defaults.baseURL = 'http//:localhost:3000/'
Vue.prototype.$axios = axios
}
the componennt :
this.$axios({
url : 'backend/spots/all',
}).then(response=>{
this.allSlots = response.data
})
According Quasar documentation you can try it as below:
// src/boot/axios.js
const axiosInstance = axios.create({
baseURL: 'http//:localhost:3000'
})
export default async ({ Vue }) => {
Vue.prototype.$axios = axiosInstance
...
}
export { axiosInstance }
to use in some vue | js file:
import { axiosInstance } from 'src/boot/axios'
axiosInstance.get('/some-endpoint')
I am not sure, but can you try to change axios.defaults.baseURL = 'http//:localhost:3000/' to axios.defaults.baseURL = 'http://localhost:3000/' (change colon place) ?
For anyone reading this.
According to quasar axios boot file documentation you can try a more cleaner way...
import Vue from 'vue'
import axios from 'axios'
// we add it to Vue prototype
// so we can reference it in Vue files as this.$axios
// without the need to import axios or use vue-axios
Vue.prototype.$axios = axios
// can also create an axios instance specifically for the backend API
const api = axios.create({ baseURL: 'https://api.example.com' })
Vue.prototype.$api = api
export { axios, api }
I was having the same issue, in quasar.config.js under build I had
env: ctx.dev ? { // so on dev we'll have
API: JSON.stringify('https://my.staging.api/v1/')
} : { // and on build (production):
API: JSON.stringify('https://my.api/v1/')
},
removing JSON.stringify solved the issue
env: ctx.dev ? { // so on dev we'll have
API: 'https://my.staging.api/v1/'
} : { // and on build (production):
API: 'https://my.api/v1/'
},

ExpressJS with NuxtJS middleware passing post data to page

Can someone help me understand how to pass data from post request to the nuxt page that is loaded. I dont know how to send the data to the page that will be loaded.
I want to be able to process the POST request, then send that data for usage on the following page. I am open to suggestions but I can't find proper documentation, tutorials or examples to accomplish this task.
I don't want to use axios here (with JSON type response), because I would prefer to send POST data and load new page. Therefor if page is reloaded, POST data must be submitted again.
const express = require('express')
const bodyParser = require('body-parser')
const { Nuxt, Builder } = require('nuxt')
const app = express()
const host = process.env.HOST || '127.0.0.1'
const port = process.env.PORT || 3000
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
app.set('port', port)
// Import and Set Nuxt.js options
let config = require('../nuxt.config.js')
config.dev = !(process.env.NODE_ENV === 'production')
async function start() {
// Init Nuxt.js
const nuxt = new Nuxt(config)
// Build only in dev mode
if (config.dev) {
const builder = new Builder(nuxt)
await builder.build()
}
// Routes added
app.post('/events/booking', function (req, res, next) {
console.log('REQUEST:', req.body)
res.set('eventId', req.body.eventId)
res.set('moreData', ['some', 'more', 'data'])
next()
})
// Give nuxt middleware to express
app.use(nuxt.render)
// Listen the server
app.listen(port, host)
console.log('Server listening on http://' + host + ':' + port) // eslint-disable-line no-console
}
start()
I believe the source of your issue is the disconnect between Nuxt's implementation of Express, the deprecation/version-conflicts of bodyParser middleware and/or the Node event system.
I would personally take a step back by removing the custom express routing, handle the body parsing yourself in the middleware and take advantage of the Vuex store.
store/index.js
export const state = () => ({
postBody: null,
postError: null
})
export const mutations = {
postBody: (state, postBody) => {
state.postBody = postBody;
},
postError: (state, postError) => {
state.postError = postError;
},
}
export const getters = {
postBody: state => state.postBody,
postError: state => state.postError,
}
middleware/index.js
export default ({req, store}) => {
if (process.server && req && req.method === 'POST') {
return new Promise((resolve, reject) => {
req.on('data', data => resolve(store.commit('postBody', JSON.parse(data))));
req.on('error', data => reject(store.commit('postError', JSON.parse(data))));
})
}
}
pages/index.vue
<template>
<div>
<h1>Test page</h1>
<div v-if="postBody">
<h2>post body</h2>
<p>{{postBody}}</p>
</div>
<div v-if="postError">
<h2>post error</h2>
<p>{{postError}}</p>
</div>
<div v-if="!postError && !postBody">
Please post JSON data to this URL to see a response
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
middleware: 'post-data',
computed: mapGetters({
postBody: 'postBody',
postError: 'postError'
})
}
</script>
Below is a live and working example project of the above. POST JSON data using a client app (Postman, web form, etc) to see the posted data rendered on the page.
Live Code: https://glitch.com/edit/#!/terrific-velociraptor
Live Example: https://terrific-velociraptor.glitch.me/

How to test catch function with Jest

How to test catch from function like this:
getApi () {
const URL = '/api/division?key='
axios.get(URL)
.then((response) => {
this.counter = response.data
})
.catch(err => {
alert(err)
})
}
I'm using axios and vue js with testing JEST. Hope any solution, thanks :')
Try axios-mock-adapter, which can mock the results of axios.get() calls, allowing you to simulate a network error/timeout for a specific request (thus invoking the catch callback in your code):
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
const mock = new MockAdapter(axios);
mock.onGet(`/* URL used by component */`).networkError();
Example unit tests for getApi():
it("does not modify username from network error", async () => {
mock.onGet(`/* URL used by component */`).networkError();
await wrapper.vm.getApi();
expect(wrapper.vm.username).toBe(INIT_USERNAME);
});
it("does not modify username from network timeout", async () => {
mock.onGet(`/* URL used by component */`).timeout();
await wrapper.vm.getApi();
expect(wrapper.vm.username).toBe(INIT_USERNAME);
});
demo

How to use axios in Vue2 project created with vue-cli3

I created a new vue project using the command vue create axe using vue-cli-3.0.016beta. Then installed axios using npm install axios --save. In the main.js file I imported axios as shown below.
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios'
Vue.config.productionTip = false
Vue.use(axios)
new Vue({
render: h => h(App)
}).$mount('#app')
There is not a bit of code change other than this. Still I get an error like the following:
Unhandled promise rejection
TypeError
​
columnNumber: 7
​
fileName: "http://localhost:8080/app.js line 1065 > eval"
​
lineNumber: 57
​
message: "parsed is undefined"
​
stack: "isURLSameOrigin#webpack-internal:///./node_modules/axios/lib/helpers/isURLSameOrigin.js:57:7\ndispatchXhrRequest#webpack-internal:///./node_modules/axios/lib/adapters/xhr.js:109:50\nPromise#webpack-internal:///./node_modules/core-js/modules/es6.promise.js:177:7\nxhrAdapter#webpack-internal:///./node_modules/axios/lib/adapters/xhr.js:12:10\ndispatchRequest#webpack-internal:///./node_modules/axios/lib/core/dispatchRequest.js:59:10\nrun#webpack-internal:///./node_modules/core-js/modules/es6.promise.js:75:22\nnotify/<#webpack-internal:///./node_modules/core-js/modules/es6.promise.js:92:30\nflush#webpack-internal:///./node_modules/core-js/modules/_microtask.js:18:9\n"
​
__proto__: Object { stack: "", … }
I want to axios globally to use interceptors, hence calling it here in main.js. But if I use it in a view-page there is no error!
is this a bug or I'm doing it wrong? Kindly help me to fix this and use axios globally.
Thanks
so the error I see is here
Vue.use(axios)
Vue.use expects a vue installable plugin.
You could have a look at vue-axios
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
but I would highly discourage it.
It's best to create your own ApiHandler.js file that handles all the remote stuff separately, and you can easily call from anywhere including vue components and vuex.
here is the beginning of my class
<script>
import axios from 'axios';
class ApiHandler{
constructor(apiUrl) {
this.axios = axios;
this.apiUrl = apiUrl || ''; // this line allow passing a custom endpoint for testing
this.config = {
headers: { 'Cache-Control': 'no-cache' }, // can setup to prevent all caching
baseURL: this.apiUrl,
};
}
/**
* #param {Object} payload
* #param {String} payload.username
* #param {String} payload.password
*/
login({ username, password }) {
return new Promise((resolve, reject) => {
this.axios.post('/api/login', { username: username.toLowerCase(), password }, this.config)
.then((response) => {
if (response.code === 200 && response.body && response.body.token) {
resolve(response.body.token);
} else {
reject('Bad Login');
}
})
.catch((err) => {
reject('internal error');
});
});
}
}
</script>
you can then call this from anywhere by...
<script>
import ApiHandler from '../lib/ApiHandler';
const apiRequest = new ApiRequest();
// and then anywhere in the script
let payload = {
username:'someuser',
password:'somepassword',
};
apiRequest.login(payload)
.then(()=>{
// yay - I'm logged in
})
.catch(err => {
// oh oh, display error
})
</script>
this gives you much more flexibility and allows you to separate the remote actions and allows doing first-leg response handling separate of your component, which allows more re-usability.
instead of
Vue.use(axios);
you should
Vue.prototype.$axios = axios;
then you can use it globally
login() {
this.$axios.post('<host>/api/login', data)
.then((res) => { // dosomething })
.catch((err) => { // dosomething });
}
if you want to add globally interceptors with axios, you can
// Add a request interceptor
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Do something with response data
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
// and
Vue.prototype.$axios = axios;