I am trying to set up stripe.js with my app. I have literally every single thing done and when the purchase is complete stripe passes the client to a success page. The problem I am having is that stripe seems to be resetting my application (the props + state from previously rendered components before stripe.js' checkout are not being passed through) in order to properly show the appropriate data on this success page i need the state from previous components.
I am using stripe's redirectToCheckout function and it redirects out of the app .maybe a serverless function from JAMstack could send the data between stripe? Someone please let me know! Here is some of my code below for the stripe part of my app. There isn't really a specific part of my code to show that would help answering this question tbh. It's a fundamental question of whether there is a way to not have stripe reset my app thus losing previous state after redirecttoCheckout function.
The response (or data on products and session etc) is coming from a serverless netlify function. which is why i mentioned it above. Maybe that could be a possible help
//client sides
import {loadStripe} from "#stripe/stripe-js"
export async function handleFormSubmission(event) {
event.preventDefault();
const form = new FormData(event.target);
const data = {
sku: form.get('sku'),
quantity: Number(form.get('quantity')),
};
const response = await fetch('/.netlify/functions/create-checkout', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
}).then((res) => res.json())
const stripe=await loadStripe(response.publishableKey);
const {err}=await stripe.redirectToCheckout({
sessionId:response.sessionId
})
if(err){
console.log(err)
}
}
//client sides
import {loadStripe} from "#stripe/stripe-js"
export async function handleFormSubmission(event) {
event.preventDefault();
const form = new FormData(event.target);
const data = {
sku: form.get('sku'),
quantity: Number(form.get('quantity')),
};
const response = await fetch('/.netlify/functions/create-checkout', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
}).then((res) => res.json())
const stripe=await loadStripe(response.publishableKey);
const {err}=await stripe.redirectToCheckout({
sessionId:response.sessionId
})
if(err){
console.log(err)
}
}
Related
This question already has an answer here:
Express routes parameters
(1 answer)
Closed last month.
I'm trying to send a POST to my server, in order to edit a user's details. I've made sure it's sending to the right URL, however get a 404 response. GET requests work fine, however my POST doesn't seem to get through for whatever reason. I've been searching for solutions for a while, with no luck hence posting here!
user.js (server side)
userRoutes.route('/user/update/:id').post(function (req, response) {
let db_connect = dbo.getDb("preview");
let myquery = { _id: ObjectId(req.params.id) };
let newValues = {
$set: {
name: req.body.name,
user_name: req.body.user_name
},
};
db_connect
.collection("users")
.updateOne(myquery, newValues, function (err, res) {
if (err) throw err;
console.log('user updated');
response.json(res);
})
});
middleware
export const updateUser = async (id, userDetails) => {
const endpoint = `${serverIp}/user/update/?id=${id}`;
try {
const response = await fetch(endpoint, {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(userDetails)
})
const result = await response.json();
return result;
} catch (error) {
console.log(error)
}
}
and a simple function to handle submitting
function handleSave() {
const newUserDetails = {
name: accountHolder,
user_name: accountUsername
};
updateUser(userId, newUserDetails);
}
Under networking in dev tools I can see the URL is indeed correct, so I can't see why this isn't working
chrome dev tools
Any help would be greatly appreciate it!
I've tried sending a basic response (i.e. a string instead of object), changing the endpoint, and more all to no avail
It seems like you are passing the id as a query param and not as part of the path
const endpoint = `${serverIp}/user/update/?id=${id}`;
^
What I can see from first glance is that in server-side you are using request parameter for id, but in the client you're sending id as a request query
I built a React web app that allows users the calculate their meal's nutrition.
Users enter an ingredient in the IngredientForm component, triggering the fetchFirebaseNutrition function.
const fetchFirebaseNutrition = (ingredientName) => {
const axios = require('axios');
const options = {
method: 'GET',
url: 'http://localhost:5001/nutrition-calculator-6db9d/us-central1/fetchAPINutrition',
params: { ingredient: ingredientName },
};
return axios
.request(options)
.then((response) => {
console.log(response);
})
.catch((error) => {
console.error(error);
return setIsAPIConnectionDown(true);
});
};
fetchFirebaseNutrition makes a get request to to my Firebase function, fetchAPINutrition, with the relevant ingredient. Then, fetchAPINutrition makes a get request to an API for the nutrition data. I'm using the Firebase function to conceal the API key for when I deploy my web app.
exports.fetchAPINutrition = functions.https.onRequest((req, res) => {
const axios = require('axios');
const ingredient = req.query.ingredient;
const options = {
method: 'GET',
url: 'https://calorieninjas.p.rapidapi.com/v1/nutrition',
params: { query: ingredient },
headers: {
'X-RapidAPI-Host': 'calorieninjas.p.rapidapi.com',
'X-RapidAPI-Key': process.env.REACT_APP_RAPID_API_KEY,
},
};
return axios
.request(options)
.then((response) => {
console.log(response.data);
return response.data;
})
.catch((error) => {
console.error(error);
});
});
fetchAPINutrition works... kind of. When I make a request to the function from the front-end, I can see on the Firebase Emulator that fetchAPINutrition is successfully getting the data from the API. See the
Firebase Emulator Logs.
However, the function just times out afterwards. So, fetchFirebaseNutrition never receives the API data and just returns an Axios Network Error message.
How can I stop my Firebase function from timing out and return the API data to the front-end?
Any help would be immensely appreciated!
HTTPS functions expect a return, which you don't. Instead, you are returning a promise without waiting for it to complete.
You need to return a result.
res.status(200).send(response.data);
In this case;
axios
.request(options)
.then((response) => {
res.status(200).send(response.data);
})
.catch((error) => {
console.error(error);
res.status(500).send("Error");
});
Here is the code for my server which works fine. I am trying to achieve this with netlify's serverless functions which I have pasted further below.
CODE ON STANDARD SERVER-HEROKU
const ratingController = {};
const Rating = require("../models/ratingModel");
ratingController.getAllRatings = async function (req, res) {
const rating = await Rating.find();
res.status(200).json({
status: "success",
data: rating,
});
};
ratingController.createOneRating = async function (req, res) {
console.log(req.body);
req.body.userIp = req.headers["x-forwarded-for"];
const rating = await Rating.create(req.body);
// const rating = new Rating(req.body);
// await rating.save();
res.status(200).json({
status: "success",
data: {
rating,
},
});
};
PART 1 - GET REQUEST
Here's my code for the getAllRatings and it works fine
SERVERLESS FUNCTION - NETLIFY
const { MongoClient } = require("mongodb");
require("dotenv").config();
exports.handler = async function getData(event, context) {
const client = await MongoClient.connect(process.env.DB, {
useUnifiedTopology: true,
useNewUrlParser: true,
});
const db = client.db();
try {
const slug = event.queryStringParameters.id;
const data = await db.collection("collectionName").find({ slug }).toArray();
client.close();
return {
statusCode: 200,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
status: "success",
data: data,
}),
};
} catch (error) {
console.log(error);
return {
statusCode: 400,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
status: "fail",
message: error.message,
}),
};
}
};
My first question for the above is
Just because it works may not mean it's the right way to do it.. I had a few concerns if calling the database each time there's a call is correct and then placing the code the way I have, if it's the way it should be. It's all based on testing and random research. There's no real method being followed so would appreciate some guidance on a more efficient method to do this.
Normally on a regular server the database connection is done just once.. and here I seem to be doing it every time and I am a bit confused if that's ok or not..
PART 2 - POST REQUEST
Here's my code for the POST request createOneRating
SERVERLESS FUNCTION - NETLIFY
const { MongoClient } = require("mongodb");
require("dotenv").config();
exports.handler = async function createRating(event, context) {
const client = await MongoClient.connect(process.env.DB, {
useUnifiedTopology: true,
useNewUrlParser: true,
});
const db = client.db();
try {
console.log(event);
const rating = await db.collection("ratings").insertOne(event.body);
client.close();
return {
statusCode: 200,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
status: "success",
data: rating,
}),
};
} catch (error) {
console.log(error);
return {
statusCode: 400,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
status: "fail",
message: error.message,
}),
};
}
};
This one does not work as it says
{
"status": "fail",
"message": "Cannot create property '_id' on string ''"
}
And I guess that's because event.body is not where the data is.. but I am not sure how to get the POST data in a serverless deployment.
So my second question is
How do I retrieve the data sent by a POST request. As there's no request parameter I am a bit confused.
Also I'd like to add the IP of the user so other than the POST data I'd also need some help on how to do this
req.body.userIp = req.headers["x-forwarded-for"];
Based on my own research, I have answers to the questions and am placing them here for my own reference and for those who might face a similar situation in the future.
Question 1 : Is it ok to make a database connection on every call that's made to a serverless function
It seems it's ok to do this and for those, like me, who thought that maybe it was not the right way to do it, it's definitely not the wrong way. Maybe there's an efficient way to do this and I'd be open to learn more about this if possible. But for now, it's good to know that it's not wrong to connect to the database each time you make a call.
Question 2: How to make a POST request on a serverless as there's no request parameter
I was not aware that the event parameter is in fact a replacement for the request parameter and that the headers and body are properties of the event object and can be accessed in the same way ie event.body and event.headers. Here's a link that could save you some time to confirm this.
(https://docs.netlify.com/functions/build-with-javascript/#synchronous-function-format)
And if you, like me, don't know if a serverless function can be defined as GET or POST or run into an issue where the POST request gets converted into a GET when making a function call here's a link that would help.
How to define Netlify function endpoint as POST?
i am new at react native. I fetch data on Firebase but i want to fetch it JSON file. My JSON file like this: enter image description here
how can i change firebase url to my php json url?
PLEASE HELP ME
This is my code:
return async (dispatch, getState) => {
// any async code you want!
// const userId = getState().auth.userId;
try {
const response = await fetch(
'https://shopapp-f9964.firebaseio.com/products.json'
);
if (!response.ok) {
throw new Error('Something went wrong!');
}
const resData = await response.json();
const loadedProducts = [];
for (const key in resData) {
console.log(resData[key].description);
loadedProducts.push(
new Product(
0,
0,
resData[key].product_image,
resData[key].description,
resData[key].price,
)
);
}
dispatch({
type: SET_PRODUCTS,
products: loadedProducts,
//userProducts: loadedProducts.filter(prod => prod.ownerId === userId)
});
} catch (err) {
// send to custom analytics server
throw err;
}
};
Here is the way to get from API (or Json response).
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
}),
});
Here is the official docs, it really helps for you to understand data from JSON file
https://reactnative.dev/docs/network
here is the working example on Snack
https://snack.expo.io/#asad_4561/b21f6d?session_id=snack-session-EGg1r5WPo&preview=true&platform=web&iframeId=g11cgnoglm&supportedPlatforms=ios,android,web&name=Fetch%20Example&description=Example%20usage&waitForData=true
Here is some good refs for your problem, by reading them your problems will be solved:
Medium: This is very good
RN docs
Another Good ref
I seem to be having an issue with getting the expected response from a fetch call within a firebase cloud function. I'm sure it's due to my lack of knowledge on how the responses, promises, etc. work.
I'm trying to use atlassian crowd's rest api for SSO. If I use postman, I can get the desired results from the request. So I know that part of it is working.
What led me to using a cloud function is that making the same request using fetch was resulting in CORS issues from localhost. I figured if I can take the browser out of the equation, then the CORS issues would disappear. Which they have, but I'm not getting the desired response.
My cloud function looks like this:
const functions = require('firebase-functions');
const fetch = require('node-fetch');
const btoa = require('btoa');
const cors = require('cors')({origin:true});
const app_name = "app_name";
const app_pass = "app_password";
exports.crowdAuthentication = functions.https.onRequest((request, response)=>
{
cors(request, response, () =>{
let _uri = "https://my.server.uri/crowd/rest/usermanagement/1/session";
let _headers = {
'Content-Type':'application/json',
'Authorization':`Basic ${btoa(`${app_name}:${app_pass}`)}`
}
let _body = {
username: request.body.username,
password: request.body.password
}
const result = fetch(_uri, {
method: 'POST',
headers: _headers,
body: JSON.stringify(_body),
credentials: 'include'
})
response.send(result);
})
})
I'm then making the call in my application using fetch to the firebase endpoint and passing the username/password:
fetch('https://my.firebase.endpoint/functionName',{
method: 'POST',
body: JSON.stringify({username:"myusername",password:"mypassword"}),
headers: {
'Content-Type':'application/json'
}
})
// get the json from the readable stream
.then((res)=>{return res.json();})
// log the response - {size:0, timeout:0}
.then((res)=>
{
console.log('response: ',res)
})
.catch(err=>
{
console.log('error: ',err)
})
Thanks for looking.
Edit of May 2020
Note that request-promise is deprecated and I recommend to use axios.
Update following our discussion in the comments below
It appears that it doesn't work with the node-fetch library and that you should use another library like request-promise.
Therefore you should adapt your code as follows:
//......
var rp = require('request-promise');
exports.crowdAuthentication = functions.https.onRequest((request, response) => {
cors(request, response, () => {
let _uri = "https://my.server.uri/crowd/rest/usermanagement/1/session";
let _headers = {
'Content-Type': 'application/json',
'Authorization': `Basic ${btoa(`${app_name}:${app_pass}`)}`
}
let _body = {
username: request.body.username,
password: request.body.password
}
var options = {
method: 'POST',
uri: _uri,
body: _body,
headers: _headers,
json: true
};
rp(options)
.then(parsedBody => {
response.send(parsedBody);
})
.catch(err => {
response.status(500).send(err)
//.... Please refer to the following official video: https://www.youtube.com/watch?v=7IkUgCLr5oA&t=1s&list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM&index=3
});
});
});
Initial answer with node-fetch
The fetch() method is asynchronous and returns a Promise. You therefore need to wait this Promise resolves before sending back the response, as follows:
exports.crowdAuthentication = functions.https.onRequest((request, response)=>
{
cors(request, response, () =>{
let _uri = "https://my.server.uri/crowd/rest/usermanagement/1/session";
let _headers = {
'Content-Type':'application/json',
'Authorization':`Basic ${btoa(`${app_name}:${app_pass}`)}`
}
let _body = {
username: request.body.username,
password: request.body.password
}
fetch(_uri, {
method: 'POST',
headers: _headers,
body: JSON.stringify(_body),
credentials: 'include'
})
.then(res => {
res.json()
})
.then(json => {
response.send(json);
}
.catch(error => {
//.... Please refer to the following official video: https://www.youtube.com/watch?v=7IkUgCLr5oA&t=1s&list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM&index=3
});
})
})
In addition, note that you need to be on the "Flame" or "Blaze" pricing plan.
As a matter of fact, the free "Spark" plan "allows outbound network requests only to Google-owned services". See https://firebase.google.com/pricing/ (hover your mouse on the question mark situated after the "Cloud Functions" title)