In my nuxt 3 App, for data fetching I wanna set a baseURL for all my API calls. As I get this baseURL from enviroment variable. How to set the the baseURL?
I warp the useFetch with composables, but then I can't get the baseURL as useRuntimeConfig() is not accessable there.
// My composables function
const baseURL = "how to get baseURL from process.env";
export const myFetch = async (url: string) => {
const options = {
baseURL: baseURL,
};
return await useFetch(url, options);
}
You can access the runtime config by doing so
export default () => {
const config = useRuntimeConfig()
console.log(config)
}
As shown here: https://github.com/nuxt/framework/discussions/3215#discussioncomment-3088206
Related
Is it possible to use global onRequest handler to $fetch with Nuxt3, to add specific data on each request?
With nuxt2 and axios it was simple
/plugins/axios.js
export default function ({ $axios, store, req }) {
$axios.onRequest((config) => {
if (config.data) {
config.data.test = '123';
} else {
config.data = { test: '123' };
}
return config;
});
}
But how achieve same goal on Nuxt3 and $fetch?
Ok, so Nuxt3 $fetch documentation says:
Nuxt uses ofetch to expose globally the $fetch helper...
When we jump into ofetch documentation we can see the Interceptors section. This gives us some options to do what you are trying to achieve. My suggestion is this:
Create a http composable (or anyother name you wish):
// composables/use-http.js
const opts = {
async onRequest({ request, options }) {
// Add your specific data here
options.query = { t: '1234' }
options.headers = { 'Authorization': 'my_token' }
}
}
export default () => $fetch.create(opts)
And here we are making usage of the onRequest interceptor from ofetch
onRequest is called as soon as ofetch is being called, allowing to modify options or just do simple logging.
There you can add any data you want, if you need you can create the logic to pass parameters to this composable and so on...
Now, to actually fetch the data (use the composable):
const http = useHttp() // useHttp is auto-imported
const data = await http('/url') // will trigger the interceptor
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)
}
}
}
I'm working with vue-router and Vue 3. I have a view where I'd like to take the router url and use it to call a method to access an API. This method returns a promise I can use to populate my page. When calling my method with 'route.params.id', it says that the parameter is undefined. When I do console.log(route.params.id), it displays correctly in console. I've tried using a computed property instead, but I had the same issue.
Setup code:
import { ref } from "vue";
import MovieApiService from "../api/MovieApiService";
import { useRoute } from "vue-router";
export default {
setup() {
const movie = ref([]);
const route = useRoute();
MovieApiService.getMovie(route.params.id).then((response) => {
movie.value = response.data.results;
});
return {
movie,
};
},
method: {},
};
Method being called:
static getMovie(body: GetMovieByTmdbId) {
return axios.get(
`https://api.themoviedb.org/3/movie/${body.id}?api_key=${apiKey}`
);
}
Here's what I tried to compute the property instead, with the same result.
setup() {
const route = useRoute();
const id = computed(()=>{return route.params.id})
const movie = ref([]);
getMovie(id).then((response) => {
movie.value = response.data.results;
console.log(movie.value);
});
How should I ensure this value is available when I call my method?
You are giving route.params.id as a variable to getMovie(body).
You are then using body.id in your URL. This would equal route.params.id.id which is not defined.
Use body in your URL, or change the parameter to id so is makes more sense.
Like this:
...
const route = useRoute();
MovieApiService.getMovie(route.params.id).then((response) => {
movie.value = response.data.results;
});
...
const getMovie = (id) => {
return axios.get(
`https://api.themoviedb.org/3/movie/${id}?api_key=${apiKey}`
);
}
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
})();
In my Nuxt project I have a file named "apiAccess.js" in the root folder. This file simply exports a bunch of functions that make Ajax calls to the server API. This file is imported in any page that needs access to the server API. I need to send a JWT token with each of these api requests, and I have stored that token in the Vuex store.
I need to access the JWT token from the Vuex store within this "apiAccess.js" file. Unfortuntaely, this.$store is not recognized within this file. How do I access the Vuex store from within this file? Or should I have done something differently?
Here's a snippet from the apiAccessjs file where I try to access the store:
import axios from 'axios'
const client = axios.create({
baseURL: 'http://localhost:3000/api',
json: true,
headers: { Authorization: 'Bearer' + this.$store.state.auth.token }
})
After i readed this post i used this generic structure:
// generic actions file
import {
SET_DATA_CONTEXT,
SET_ITEM_CONTEXT
} from '#/types/mutations'
// PAGEACTIONS
export const getDataContext = api => async function ({ commit }) {
const data = await this[api].get()
commit(SET_DATA_CONTEXT, data)
}
export const getItemContext = api => async function ({ commit }, id) {
const data = await this[api].getById(id)
commit(SET_ITEM_CONTEXT, data)
}
export const createItemContext = api => async function ({}, form) {
await this[api].create(form)
}
export const updateItemContext = api => async function ({}, form) {
await this[api].update(form)
}
export const deleteItemContext = api => async function ({}, id) {
await this[api].delete(id)
}
and for any store i used actions from my generic file:
// any store file
import {
getDataContext,
getItemContext,
createItemContext,
updateItemContext,
deleteItemContext,
setDynamicModal
} from '#/use/store.actions'
const API = '$rasterLayerAPI'
export const state = () => ({
dataContext: [],
itemContext: {},
})
export const actions = {
createItemContext: createItemContext(API),
getDataContext: getDataContext(API),
getItemContext: getItemContext(API),
updateItemContext: updateItemContext(API),
deleteItemContext: deleteItemContext(API),
}
because I had many stores with similar features.
and the same for mutations i used generic mutations functions.