Change Apollo endpoint in Apollo provider - vue.js

Is there a way to change the Apollo endpoint after having created the Apollo client? I would like to have the user to input their own endpoint.

httpEndpoint can be a function, and it is called on each query.
As #wrod7 mentioned, you could use localStorage, but global variable should be enought
// vue-apollo.js
export { defaultOptions }
// main.js
import { createProvider, defaultOptions } from './vue-apollo'
window.apolloEndpoint = defaultOptions.httpEndpoint
new Vue({
router,
apolloProvider: createProvider({
cache,
httpEndpoint: () => window.apolloEndpoint,
}),
render: h => h(App),
}).$mount('#app')
and you can set apolloEndpoint anywhere you like, i am using window. to make eslint happy
httpEndpoint is called with current query, so you can conditionally return endpoint based on operationName
vue-apollo got support for multiple clients, it might be useful if you want to override endpoint only on some queries, but i thinks this offtopic

I am doing this on one of my applications. I store the URL string in localstorage or asyncstorage on mobile. you can check for the string when the app loads and have the user enter one if there isn't a url string stored. the application would have to refresh after entering the url and saving it to localstorage.

Related

Nuxtjs store undefined in middleware on refresh

I'm using nuxt js for my web app, I need to keep the store when I refresh the page, even in middleware or the page itself.
I'm using vuex-persistedstate;
import createPersistedState from "vuex-persistedstate";
export default ({ store }) => {
if (process.client) {
window.onNuxtReady(() => {
createPersistedState({})(store);
});
}
};
One of the solutions that I tried is to use cookies in the store, but my data is very huge and I need it in the local storage.
I think it's something related to SSR or server middleware, I tried a lot to figure out how to solve it, but nth is working.
It is impossible because we are not able to access localStorage when component is rendering on the server side. You should either turn off ssr to use localStorage or try to reduce the size of your data to put it in cookies.

Update all clients after a change in vuex state

I am using vue2 syntax and vuex , versions : vue/cli 4.5.13 and vue#2.6.14 and vuex 3.6.2
I have a simple to do project , for adding todos in a list, based on the 2019 vue tutorial by traversy.
I have a simple form ij my component to add a to do
<form #submit.prevent="onSubmit" >
and in my vuex store I have
const state = {
todos:''
};
const getters = {
allTodos: (state) => {return state.todos}
};
const actions = {
async addTodo({commit}, title){
const res = await axios.post('https://jsonplaceholder.typicode.com/todos', {
title,
completed:false
});
commit('newTodo', res.data);
}
};
const mutations = {
newTodo:(state, todo)=>(
state.todos.unshift(todo)
)
};
Is there a way to update all clients that view the todos, without clients have to refresh nothing, as soon as a new todo is added in the state, using only vuex/vue?
Thank you
Is there a way to update all clients that view the todos, without clients have to refresh nothing, as soon as a new todo is added in the state, using only vuex/vue?
No, it is not possible.
There is no link between all your clients. All your Vue/VueX code lives in a single client. Here's what you need to do to get where you want to go, and its a long way from here:
Build a backend server. Here's a Node.js guide
Build an APi in your server. Your clients will make requests to this server to get all todos, and post new todos to the server. Here's an express.js guide
You need a database to store your todos in the server. You can use something like MongoDB or an ORM like Sequelize for node.js.
Now you can either write a code to periodically request the server for todos in the background and update it in your vue components, or you can use a pub/sub library like pusher. Pusher uses WebSockets under the hood for maintaining a persistent bidirectional connection. If you want to, you can implement this on your own, you can read about it here, thanks to #Aurora for the link to the tutorial.
Here's a consolidated guide for doing all this:
https://pusher.com/tutorials/realtime-app-vuejs/
Is there a way to update all clients that view the todos, without clients have to refresh nothing, as soon as a new todo is added in the state, using only vuex/vue?
There's a couple of errors in your code:
change todos:'' to todos:[]
change state.todos.unshift(todo) to state.todos.push(todo)
This way, every time that you call addTodo action, all components connected to allTodos getter will show the latest todos
NOTE:
Vuex/Vue are reactive. So in every page that you see using that showcomponent will show you the last update. If you want to show in every USER CONNECTED, of course you don't need http request, you need WEBSOCKETS

Values disappearing after refresh

Once I log in I set username and loggedIn value, I import the values to my component, it works but after refreshing the page this goes back to original value, why is this happening?
I didn't have this issue when Using vuex in vue 2. Do I really have to store this data in localStorage? Wtf.
const loggedIn = ref(false);
const userName = ref('');
export default function useAuth() {
const login = async ({ email, password }) => {
try {
const result = await AuthService.login({ email: email, password: password });
userName.value = result.data.nick;
loggedIn.value = true;
}
}
return {login, loggedIn, userName}
}
A browser does not automatically store the current memory of a JavaScript application. On a page refresh, the complete page is re-rendered and a new "application" is loaded. You can influence this behavior when you store your state on the back-end site (push relevant data to back-end via API and store it there e.g. in a database) or you can store your state in the browser's storage. This can be as a cookie, session/local storage and IndexedDB. Depending on your needs, you can then retrieve the relevant state from the back-end or your locally stored data on page load. If you are using Vuex, there are plugins which allow you to do this automatically. You can still use Vuex with Vue3 (use useStore() instead of this.$store).
If you are using just the plain composition API, the in-memory variables won't be saved. You can, however, easily watch the variables and set the values to the local store by yourself. See e.g. this example where a new variable is created with the value from the local storage (on page load), a watcher is defined where the value is going to be set to the storage and then finally the variable is returned from this module.

Vue call API key on header

My API KEY = 2356yhtujkiw
I am using AXIOS on VUEJS as for get/post request.
API document says to add that API key as on header of all requests.
I tried setting it as axios.defaults.headers.common['header'] = '2356yhtujkiw'; but it did not work.
What's the proper way to define API KEY on header ?
it can get confusing when you're starting out, and certain terms, like header could mean different things depending on context.
There are several ways you can achieve axios calls in vue.
There's the "easy" one, where you add stuff right into a component
you can integrate it into vuex
create a custom helper/wrapper function (to use in a component or vuex)
use a the vue axios plugin
On top of that there's more than one ways to implement axios
reuse global instance
create new instance for every call
without seeing your code it's hard to know which way you're using it, but I'm going to try to give steps for a way that should make it easy enough to replicate
create a api.js in your src folder with:
import axios from 'axios'
let TOKEN = null;
export default {
setHeader(val){
TOKEN = val;
},
fetchUsers: () => {
const instance = axios.create({
baseURL: 'https://api.example.com',
headers: {
header: TOKEN
}
});
// or: instance.defaults.headers.common['header'] = TOKEN;
return instance.get('/users')
.then((result) => {
this.users = result.data
})
}
}
In a component, or Vuex, you can then...
import api from '../api.js'
// set header
api.setHeader('abc123')
// make api call
api.fetchUsers().then(r=> {console.log(r)});
This (though untested code) should work...
It's not the cleanest way of using it, but should be easy to implement in existing code.
TL;DR;
The reason axios.defaults.headers.common['header'] = '2356yhtujkiw'; doesn't work is likely because you've already created the instance, and are re-using it. Updating the default would only apply for subsequent instances created. The example above gets around that, by not using any defaults, and just inserting the headers in every new instance, which is created for every new call.

Refresh token Vuex before enter in Routing

I have an frontend Web app interfaces with API built in Laravel with Passport.
My problem is when I refresh my page (in SPA written with Vuejs/Vuex) I should refresh my token, for refresh session with my Api.
I tried in main.js but he problem is that the request is async and the response arrived after routing.
main.js
if (localStorage.getItem('refresh_token')) {
store.dispatch('refresh_token').then(function(response){
console.log(response);
});
}
new Vue({
router,
store,
env,
render: h => h(App)
}).$mount('#app')
The function refresh token, make a call to my Api, and with response set the new token and the new refresh token.
But my problem is that I make this call in this way I can make the first async call in my "dashboard" with old token and then with the new.
So I've tried in different ways but I don't know if there is a best practice.
So my question is:
Where I should refresh token in Vuejs App with vuex store?
I suggest putting this in the mounted property of you toplevel Vue component. If you have other components that depend on your token being refreshed, you can couple this with a state variable in your store that signals the refresh is completed. For example, with a top level component App.vue:
...
mounted () {
store.dispatch('refresh_token')
}
...
Adding the state variable to your vueex store:
const store = new Vuex.Store({
state: {
sessionRefreshed: false
},
..
mutations: {
[REFRESH_TOKEN] (state) {
// existing mutations, and..
state.sessionRefreshed = true
},
},
..
actions: {
refreshToken ({ commit }) {
myAsyncFetchToken().then(() => commit(REFRESH_TOKEN))
},
}
This ensures your entire application is aware of the state of your refresh without forcing it to be synchronous. Then if you have components which require the token to be refreshed, you can show loading widgets, placeholders, etc., and use a watcher to do things when the state changes.
How about using router#beforeEach guard? I use it to figure out if authentication token is stored in a cookie before accessing any "restricted" component. If token is not set I redirect to /login.
I realize that my scenario is exactly what you are are asking for but I hope you can use it to augment your implementation.