I want to try the invoicing API in vuejs.
The code example I want to apply is
// Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
const stripe = require('stripe')(
'sk_test_51M6ZtzIWDjpHNQK1pihAHQGM9Hh7aGVggo7yICRvYNUPqmHA2nIB9OLU6UrVmnWU8Spzcl1ZkPdRZu6zYCSVO7fi008peIrX1g'
);
const customer = await stripe.customers.create({
email: 'jenny.rosen#example.com',
payment_method: 'pm_card_visa',
invoice_settings: {default_payment_method: 'pm_card_visa'},
});
This does'nt work and I get the error
Require is not defined
How to change this piece of code ?
Related
I have a SvelteKit app and am using Firebase and Node to do simple Google SSO auth. I am using an API that requires the IDToken of the currently signed in user to authenticate requests. Ideally I'd like to use the +page.ts load function to load in the data, something like this:
export const load = (async () => {
// Get user, token
const auth = getAuth();
const user = auth.currentUser;
const token = await user?.getIDToken();
if (!token) throw error(401, "Could not authenticate");
// Use token to get data needed to load page
const data = api.requestData(token);
return { data };
}) satisfies PageLoad;
export const ssr = false;
The issue is that user is always null when this function executes. I imagine this is because this is called before the page loads and Firebase hasn't had a way to access the session and get the current user.
My question is, what approach do I take to solve this without simply requesting the data after the page is rendered? Is there a way to authenticate the user server side? Thanks so much.
Problem Solved
If you're struggling with the same issue, look at the accepted answer which is one way to achieve it by using serverMiddleware
I'm using an API which required a private key. I've stored the key inside a .env file, and called it in the nuxt configuration file, like this :
privateRuntimeConfig: {
secretKey: process.env.MY_SECRET_KEY
},
My API call is done inside the asyncData() hook on my index page. It works fine when i load this page, or reload it, but everytime i use the navigation to come back to this page, i end up with an error (I use a buffer to convert my API key to base64)
First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.
After some research and debugging, i found out that my private key wasn't available at the time, and the "secret" value used in my api call was "undefined".
The thing I don't get is why is this working on initial load / reload but not on page navigation ? And is there a way to fix it without using a backend ? (SSR for SEO and the ability to use private keys without exposing them are the main reasons why i used Nuxt for my project)
Here is my code :
async asyncData({ $content, store, $config }) {
const secret = Buffer.from($config.secretKey).toString('base64')
const request = await fetch('https://app.snipcart.com/api/products', {
headers: {
'Authorization': `Basic ${secret}`,
'Accept': 'application/json'
}
})
const result = await request.json()
store.commit('products/addProducts', result)
const stocks = store.getters['products/getProducts']
return { stocks }
},
Update
Looking at the #nuxtjs/snipcart module's key key and since it's a buildModules, you can totally put it there since it will be available only during the build (on Node.js only)!
For more info, Snipcart do have a lot of blog posts, this one based on Nuxt may help clearing things up: https://www.storyblok.com/tp/how-to-build-a-shop-with-nuxt-storyblok-and-snipcart
You do have your key initially because you're reaching the server when you enter the page or hard refresh it.
If you navigate after the hydration, it will be a client side navigation so you will not be able to have access to the private key. At the end, if your key is really private (nowadays, some API provide keys that can be exposed), you'll need to work around it in some ways.
Looking at Snipcart: https://docs.snipcart.com/v3/api-reference/authentication, it clearly states that the key should be available in
Appear in your compiled front-end assets (HTML, JavaScript)
Meanwhile, if you need to make another call to your backend (trying to access something else than products), you'll need to make a second call.
With Nuxt2, you cannot reach for the backend each time as of right now since you will stay in an SPA context (Nuxt is a server then client Vue app basically). But you could write down the token into a cookie or even better, use a backend as a proxy to hide this specific key (or even a serverless function).
Some more info can be found on my other answer here: https://stackoverflow.com/a/69575243/8816585
Thanks #kissu for your (very) quick answer :)
So, based on what you said and your other answer on the subject, i've made a server Middleware in Nuxt in my server folder.
server/snipcart.js
const bodyParser = require('body-parser')
const axios = require('axios')
const app = require('express')()
app.use(bodyParser.json())
app.all('/getProducts', (request, response) => {
const url = 'https://app.snipcart.com/api/products'
const secret = Buffer.from(process.env.SNIPCART_SECRET).toString('base64')
const config = {
headers: {
'Authorization': `Basic ${secret}`,
'Accept': 'application/json'
}
}
axios
.get(url, config)
.then(res => {
const products = {}
res.data.items.forEach(
item => {
const productId = item.userDefinedId.replace(/-/g, '')
const stocks = {}
item.variants.forEach(
variant => {
const size = variant.variation[0].option
const stock = variant.stock
stocks[size] = stock
}
)
products[productId] = stocks
}
)
response.json(products)
})
.catch( err => response.json(err) )
})
module.exports = app
Correct me if i'm wrong, but I think that's basically the same as using a server as a proxy right ? Based on Nuxt lifecycle hooks, the serverMiddleware one is only run on the server, so my API key shouldn't be exposed to the client ? (I still need to do some refactoring to clean the code, but at least it's working) (https://nuxtjs.org/docs/concepts/nuxt-lifecycle/#server & https://nuxtjs.org/docs/configuration-glossary/configuration-servermiddleware/)
nuxt.config.js
serverMiddleware: [
{ path: "/server", handler: "~/server/snipcart.js" }
]
index.vue (where my snipcart API call was previously made, i guess now I should move this call directly from the product card component where the data is needed) :
async asyncData({ $content, store, $axios }) {
await $axios
.get('/server/getProducts')
.then(res => store.commit('products/addProducts', res.data))
.catch(err => console.log(err))
const stocks = store.getters['products/getProducts']
return {stocks, masterplanProducts }
},
PS : Snipcart does provide a public API key, but the use is very limited. In order to access the remaining stock for each product, i have to use the private key (which allows for some other operations, like removing products / accessing orders and such)
UPDATE :
It's not working when the website is fists accessed from any other page than the one one where the API call is, since the store won't have any data from the API call)
Okay, now I feel dumb. I found a way to make it work. I guess taking the time to explain my problem helped me understand how to solve it.
For those who encounter a similar issue, i fixed it by wrapping my API call with a If statement.
if ($config.secretKey) {
const secret = Buffer.from($config.secretKey).toString('base64')
const request = await fetch('https://app.snipcart.com/api/products', {
headers: {
'Authorization': `Basic ${secret}`,
'Accept': 'application/json'
}
})
const result = await request.json()
store.commit('products/addProducts', result)
}
const stocks = store.getters['products/getProducts']
This way, i can just skip the API call and access values from my vuex store.
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.
i saw something similar here: How do you authenticate a VueJS app with Azure AD?
but it did not work for me...
my problem is that after authenticating the user at login - i still needed to get the users security groups and that information was not received using the graph-api described in the above mentioned post
thank you for any help
it was something that took me a long time to figure out so im posting my findings here, hopfully this will help someone:
this was a hard one for me so im posting here - hopfully this will save some time to someone:
my problem was that i need not only to authenticate my vuejs app with azure-ad, but i need also to get the security groups to which the user is belonging to.
to achive this, this is what i done:
i used the vue-adal sample app mentioned above( you can find it in: https://github.com/survirtual/vue-adal ) - under sample folder.
but i still had to make some changes to make it behave the way i need. the problam was that after logging in with my user the sample app used windows.net graph api for retrieving user info with the token from the user authentication, so i had to change in main.js this:
const graphApiBase = `https://graph.windows.net`
const graphApiResource = '00000002-0000-0000-c000-000000000000'
to this:
const graphApiBase = `https://graph.microsoft.com/v1.0`
const graphApiResource = '00000003-0000-0000-c000-000000000000'
in addition, inside the return url component i had to change the axios query to get the security groups to which the user belongs to..so i changed this (in the home.vue file):
async getUserInfo () {
let res = await this.$graphApi.get(`me`, {
params: {
'api-version': 1.6
}
})
to this:
async getUserInfo () {
let res = await this.$graphApi.post(`/me/getMemberGroups`, {
securityEnabledOnly: true
})
console.log(res)
return res.data
}
and then the data that i received back from the api contained the security groups to which the user belongs to...
I am using https://github.com/marlove/react-native-geocoding to get coordinates in react-native.
Sample code
`Geocoder.from("visakhapatnam,andhra pradesh,india")
.then(json => {
var location = json.results[0].geometry.location;
console.log("location",location)
})
.catch(error => console.warn("routeMap Err",error));`
I am getting error
{"code": 4, "message": "Error from the server while geocoding. The received datas are in the error's 'origin' field. Check it for more informations.", "origin": {"error_message": "You must enable Billing on the Google Cloud Project at https://console.cloud.google.com/project/_/billing/enable Learn more at https://developers.google.com/maps/gmp-get-started", "results": [], "status": "REQUEST_DENIED"}}
To use the Geocoding API you must have an API key. The API key is a unique identifier that is used to authenticate requests associated with your project for usage and billing purposes.
To get an API key:
Visit the Google Cloud Platform Console.
Click the project drop-down and select or create the project for
which you want to add an API key.
Click the menu button and select APIs & Services > Credentials.
On the Credentials page, click Create credentials > API key. The API
key created dialog displays your newly created API key.
Click Close. The new API key is listed on the Credentials page under
API keys.
(Remember to restrict the API key before using it in production.)
OR You need try enable billing like an error message.
Go to the Payment Account Management page in the Google Cloud
Platform Console and log in.
Select the My Projects tab to display the list of projects and the
payment accounts associated with each project.
In the list of projects, locate the project for which you want to
re-enable payments, and then click the menu (more_vert) next to it.
Select Change payment and select the destination payment account you
want.
did you provide api key to geocoded like this
Geocoder.init('your api key'); // use a valid API key
I had this problem because my google cloud free trial plan ended. When I upgraded to Blaze plan the error stopped happening.
Try this:
import React, {useEffect} from 'react';
import Geocoder from 'react-native-geocoding';
import {keys} from '../env';
First ensure your billing info and geocoding API are properly setup
and enabled.Then set up code to grant permission to avert future
issues
const _getCurrentPosition = async () => {
Geocoder.init(keys.GOOGLE_MAP_APIKEY); // initialized with a valid API key
const status = await locationPermission(); // write the function
if (status === 'granted') {
const location = await getCurrentLocation(); // write the function
console.log('Location Permission granted!');
console.log({currentLoc: location});
Geocoder.from({
latitude: location.latitude,
longitude: location.longitude,
})
.then(addressJson => {
const _location = addressJson.results[0].formatted_address;
console.log('location_', _location);
})
.catch(error => console.warn(error));
//or for non-geometry positions (plain addresses)
//**IMPORTANT** make sure the address is valid to avoid errors
//one way to do this is to first google a valid address
Geocoder.from("visakhapatnam")
.then(addressJson => {
const _location = addressJson.results[0].geometry.location;
console.log('location_', _location);
})
.catch(error => console.warn(error));
} else {
console.log('Permission not grantedd!');
}
};
useEffect(() => {
_getCurrentPosition();
}, []);
Don't forget to ALWAYS consult the documentation: https://www.npmjs.com/package/react-native-geocoding