how to use env variables in nuxt 3 outside of setup scripts - axios

So the problem is that I would like to use Axios instance. Because:
new useFetch is only possible to use inside of components aka setup scrips. https://v3.nuxtjs.org/guide/features/data-fetching/
community axios module is only possible inside of nuxt2 https://github.com/nuxt-community/axios-module/issues/536 and are nor supported in nuxt3
I need to make calls in pinia actions(store) to my backend service.
nuxt.config.js
import { defineNuxtConfig } from "nuxt";
export default defineNuxtConfig({
runtimeConfig: {
public: {
apiBase: process.env.API_BASE_URL ?? "http://localhost:8080/api/v1",
},
},
env: {
apiBase: process.env.API_BASE_URL ?? "http://localhost:8080/api/v1",
},
buildModules: ["#pinia/nuxt"],
});
and here is instance.js
import axios, { AxiosResponse } from "axios";
const instance = axios.create({
baseURL: process.env.API_BASE_URL,
});
instance.interceptors.response.use((response: AxiosResponse) => {
return response.data;
});
export default instance;
So it does see the envs on server-side as I can console log them but on client I do receive can't read of undefined

You can access your env variables using a composable and the useRuntimeConfig method.
Something like this for instance:
// file composables/use-axios-instance.ts
import axios, { AxiosResponse } from "axios";
let instance = null;
export const useAxiosInstance = () => {
const { API_BASE_URL } = useRuntimeConfig();
if (!instance) {
instance = axios.create({
baseURL: API_BASE_URL,
});
instance.interceptors.response.use((response: AxiosResponse) => {
return response.data;
});
}
return instance;
};
Then you can access to your axios instance using const axios = useAxiosInstance();

Related

Call api with axios since my component and my store

I'm new to Vue 3 (cli) and I'm not at all comfortable with front-end technology, so I'm having a hard time understanding the information I'm reading.
I succeeded in creating a registration/login interface with an api and JWT. The user information needs to be persisted everywhere in the project I'm doing to train myself, so I configured axios in my store.
store/index.js
import { createStore } from 'vuex'
import axios from 'axios';
const api = axios.create({
baseURL: 'http://127.0.0.1:7000'
});
let user = localStorage.getItem('user');
if(null === user) {
user = {uuid: '', token: ''};
} else {
try {
user = JSON.parse(user);
api.defaults.headers.common['Authorization'] = 'Bearer ' + user.token;
} catch (e) {
user = {uuid: '', token: ''};
}
}
export default createStore({
state: {
status: '',
user: user,
userInfos: {},
},
mutations: {
[...]
},
getters: {
},
actions: {
[...]
},
modules: {
}
})
I would like to be able to use api from my components. I have had several approaches:
1 - I have imported axios into my component, but this is not correct at all, as I will need axios in all my components.
2 - I've looked at different documentations that explain how to configure axios globally, but no two are the same and I couldn't get anything to work.
3 - I've tried calling api through strangenesses like this.$store.api in my methods, but obviously this is abused.
Can anyone help me understand what is the right way to use axios from my components and from the store with only one configuration? Knowing that I need to be able to keep my headers up to date for authentication with the Bearer Token (a mutation updates it in the store at user login).
main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap/dist/js/bootstrap.js'
import { library } from '#fortawesome/fontawesome-svg-core'
import { FontAwesomeIcon } from '#fortawesome/vue-fontawesome'
import { faMedal } from '#fortawesome/free-solid-svg-icons'
import { faLaptopMedical } from '#fortawesome/free-solid-svg-icons'
import { faCookieBite } from '#fortawesome/free-solid-svg-icons'
import { faCoins } from '#fortawesome/free-solid-svg-icons'
import { faHourglassStart } from '#fortawesome/free-solid-svg-icons'
import { faUpRightFromSquare } from '#fortawesome/free-solid-svg-icons'
import { faInfo } from '#fortawesome/free-solid-svg-icons'
import { faGears } from '#fortawesome/free-solid-svg-icons'
library.add(
faMedal,
faCoins,
faLaptopMedical,
faCookieBite,
faHourglassStart,
faUpRightFromSquare,
faInfo,
faGears
);
createApp(App)
.component('font-awesome-icon', FontAwesomeIcon)
.use(store)
.use(router)
.mount('#app')
Thank you very much for your help.
If you're creating a new app, I would use Pinia, which is really the next version of VueX. Don't put the user in localStorage, but in a store that you can access from all views and components.
So Axios setup in composables/myaxiosfile.js
// src/stores/oneStore.js
import { defineStore } from "pinia";
// Possibly import and deconstruct functions from #/api.js and use
// those functions in the "actions" section of the store,
// updating the state according to the answer of the api call.
export const useOneStore = defineStore("oneStore", {
state: () => {
return {
user: true
}
}
// actions
// getters
})
and in a component :
import { useOneStore } from '../stores/oneStore';
const oneStore = useOneStore()
I don't know if this is the right way, but by doing so, it allows me to use the store api in my components.
store/index.js
state: {
api: {},
[...]
},
mutations: {
setApi: function (state, api) {
state.api = api;
},
connexionUser: function (state, user) {
state.user = user;
api.defaults.headers.common['Authorization'] = 'Bearer ' + user.token;
state.api = api;
},
[...]
},
actions: {
setApi: ({commit}) => {
commit('setApi', api);
},
[...]
},
App.vue
mounted() {
this.$store.dispatch('setApi');
[...]
}
Like this, offline, it loads api which is set at the top of my store (see in my question) and when I log in, I update api in state to have JWT authentication.

Using VUEX necessary with NODE.js REST Backend

I´m not very experienced with Frontend/Backend Architecture, but i created a simple REST Backend with NODE.js and want to build up a Frontend based on Vue.js and Framework7.
So do you recommend using VUEX there? Or how do you deal with the sessions or the different requests you sending to the Backend?
Thanks a lot!
You don't have to use Vuex, but I'd suggest using Vuex. Here's an example using Vuex and rest api.
In store/actions.js
import {
fetchSomething,
} from '../api/index.js';
export const actions = {
getSomething({ commit }) {
fetchSomething().then((something) => {
commit('UPATED_SOMETHING', something);
});
},
}
In api/index.js
export const fetchSomething = () => {
const url = 'Some endpoint';
return new Promise((resolve) => {
axios.get(url).then((res) => {
const data = res.data;
resolve(data);
}).catch((err) => {
console.log(err);
})
})
}
In store/mutations.js
export const mutations = {
UPATED_SOMETHING(state, data) {
state.something = data;
},
}
In store/index.js
import { getters } from './getters'
import { actions } from './actions'
import { mutations } from './mutations'
// initial state
const state = {
something: null,
}
export default {
state,
getters,
actions,
mutations,
}
In store/getters.js
export const getters = {
getSomething: state => {
return state.something;
},
}

Next JS connection with Apollo and MongoDB

I am new to Next.js and using this example from Next.js https://github.com/zeit/next.js/tree/master/examples/api-routes-apollo-server-and-client.
However, the example is silent on MongoDB integration (also I could not find any other example for the same). I have been able to make database-connection but NOT able to use it in resolvers.
My Code
pages/api/graphql.js
import { ApolloServer } from 'apollo-server-micro'
import { schema } from '../../apollo/schema'
const MongoClient = require('mongodb').MongoClient;
let db
const apolloServer = new ApolloServer({
schema,
context: async () => {
if (!db) {
try {
const client = await MongoClient.connect(uri)
db = await client.db('dbName')
const post = await Posts.findOne()
console.log(post)
// It's working fine here
}
catch (e) {
// handle any errors
}
}
return { db }
},
})
export const config = {
api: {
bodyParser: false,
},
}
export default apolloServer.createHandler({ path: '/api/graphql' })
apollo/schema.js
import {makeExecutableSchema} from 'graphql-tools';
import {typeDefs} from './type-defs';
import {resolvers} from './resolvers';
export const schema = makeExecutableSchema({
typeDefs,
resolvers
});
apollo/resolvers.js
const Items = require('./connector').Items;
export const resolvers = {
Query: {
viewer(_parent, _args, _context, _info) {
//want to populate values here, using database connection
return { id: 1, name: 'John Smith', status: 'cached' }
},
...
}
}
I am stuck in the resolvers.js part. Don't know how to get the cached database connection inside resolvers.js. If I create a new database connection file, top-level await is not supported there, so how do I proceed?
If context is a function, whatever you return from the function will be available as the context parameter in your resolver. So if you're returning { db }, that's what your context parameter will be -- in other words, you can access it as context.db inside your resolver.

How to configure API URL running on localhost on port 8080 in nuxt js?

I have the following vue file. My REST API base URL is http://localhost:8080/api/. When I access http://localhost:8080/api/dfc/system/docbases directly, I get the response as shown.
["gr_swy","SubWayX_DEMO"]
But I want to get the response through nuxt js which is running on http://localhost:3000/restapi/. I tried to follow all the articles, but not able to figure out where I'm doing wrong.
<template>
<div class="container">
{{docbases}}
</div>
</template>
<script>
import axios from "axios";
#import axios from "../../.nuxt/axios"; (tried both)
export default {
methods: {
// asyncData({ req, params }) {
// return axios.get("http://localhost:8080/api/dfc/system/docbases")
// .then(res => {
// return { docbases: res.data };
// }).catch((e) => {
// error({ statusCode: 404, message: 'Not found' })
// })
// },
async asyncData ({ params }) {
const { data } = await axios.get('http://localhost:8080/api/dfc/system/docbases');
return { docbases: data }
}
},
head: {
title: "D2Rest"
}
};
</script>
My nuxt.config.js is like this: I tried changeOrigin with true and false both. Can you please help me what extra things I need to configure?
axios: {
proxy: true,
},
env: {
baseUrl: process.env.BASE_URL || 'http://localhost:3000'
},
proxy: {
'/api/': {
target: 'http://localhost:8080/',
pathRewrite: { "^/api": "" },
changeOrigin: false,
prependPath: false
}
},
Based on your configuration, I'm assuming you're using the Nuxt Axios module...
The problem seems to be that you're importing Axios unnecessarily, thus bypassing your axios configuration in nuxt.config.js. The Nuxt Axios module docs describe its usage in components:
export default {
async asyncData({ $axios }) {
const ip = await $axios.$get('http://icanhazip.com')
return { ip }
}
}
Note the destructured parameter $axios. Use that parameter instead of importing your own instance of axios (i.e., don't do import axios from 'axios'), which is not the same as the one configured by Nuxt. No other imports are needed for $axios.
Proxy URL
Another problem is that your explicitly requesting the proxy address in the URL, but that should be excluded:
// const { data } = await $axios.get('http://localhost:8080/api/dfc/system/docbases'); // DON'T DO THIS
const { data } = await $axios.get('/api/dfc/system/docbases');
Sorry, I didn't enable Cross Origin in my java code. I have enabled now and it's resolved.
#CrossOrigin(origins = "http://localhost:3000")

currentUser fetched in Authentication with Torii?

Trying to change a torii authenticator to return an account id from the response, so it's available in the session for fetching the account.
In trying to adapt the example to the torii authenticator, I have this starting point (obviously wrong, hitting on my js knowledge limits):
import Ember from 'ember';
import Torii from 'simple-auth-torii/authenticators/torii';
import Configuration from 'simple-auth-oauth2/configuration';
export default Torii.extend({
authenticate: function(credentials) {
return this._super(provider).then((authResponse) => {
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.$.ajax({
url: Configuration.serverTokenEndpoint,
type: 'POST',
data: { 'auth_code': authResponse.authorizationCode }
}).then(function(response) {
Ember.run(function() {
// all properties this promise resolves
// with will be available through the session
resolve({ access_token: response.access_token, account_id: response.account_id });
});
}, function(xhr, status, error) {
Ember.run(function() {
reject(xhr.responseText);
});
});
});
});
}
});
Ember doesn't complain with any errors, but of course facebook's auth dialog doesn't pop. Lost at this point, any pointers would be greatly appreciated.
Update
This is the provider code, which was working before changing the authenticator to try and return the account_id as well:
import Ember from 'ember';
import FacebookOauth2 from 'torii/providers/facebook-oauth2';
let { resolve } = Ember.RSVP;
export default FacebookOauth2.extend({
fetch(data) {
return resolve(data);
},
close() {
return resolve();
}
});
This is the previous, working authenticator:
import Ember from 'ember';
import Torii from 'simple-auth-torii/authenticators/torii';
import Configuration from 'simple-auth-oauth2/configuration';
export default Torii.extend({
authenticate(provider) {
return this._super(provider).then((authResponse) => {
return Ember.$.post(Configuration.serverTokenEndpoint, { 'auth_code': authResponse.authorizationCode }).then(function(response) {
return { 'access_token': response['access_token'], provider };
});
});
}
});