Can't post to firebase's database - node.js

When I try to post data with postman to firebase I get this error:
Error: Value for argument "data" is not a valid Firestore document. Cannot use "undefined" as a Firestore value (found in field body).
I checked and body and userHandle comes back as undefined but I don't know why. With postman I use POST and in the body I send a json like this:
{
"body": "scream 2",
"userHandle": "user2"
}
as raw JSON(application/json)
const functions = require('firebase-functions');
const admin = require('firebase-admin');
let firebaseConfig = {
apiKey: '*******',
authDomain: '******',
databaseURL: '*****',
projectId: '*****',
storageBucket: '****',
messagingSenderId: '*****',
appId: '*******'
};
admin.initializeApp(firebaseConfig);
exports.createScream = functions.https.onRequest((req, res) => {
if (req.method !== 'POST') {
return res.status(400).json({ error: 'Method not allowed' });
}
const newScream = {
body: req.body.body,
userHandle: req.body.userHandle,
createdAt: admin.firestore.Timestamp.fromDate(new Date())
};
admin
.firestore()
.collection('screams')
.add(newScream)
.then(doc => {
res.json({ message: `document ${doc.id} created successfully` });
})
.catch(err => {
res.status(500).json({ error: 'something went wrong' });
console.error(err);
});
});

Acording to my experience:
Lot of people while using postman forget to change the body to JSON (by Default it's text). Check the picture below:
So if you will see in the right-end you will find JSON highlighted in orange color. That must be set to JSON (If you are trying to push JSON ofcourse). By default i found that it is in text.
Rest about the code you have posted in the question is up to mark.
I really thought it might help someone facing the simliar problem therefore decided to mention this.
Happy coding.

The error message is saying that one of the fields you're adding to the Firestore document is undefined:
const newScream = {
body: req.body.body,
userHandle: req.body.userHandle,
createdAt: admin.firestore.Timestamp.fromDate(new Date())
};
Since what you're showing is all variables whose values we can't see, we can't tell which one might be undefined. You will have to debug this on your own to figure out which one is undefined, and modify your code to check that the inputs are valid.

Okay it's a little weird but in postman the body was set to raw JSON (application/json)but I set it again to JSON(application/json) and now it's working.

Related

Re-captcha token verification fails in AWS, but not in vercel

Below is my Next.js (backend API) code to verify recaptcha token (created from the client side) and send a mail.
import { NextApiRequest, NextApiResponse } from "next";
import NextCors from 'nextjs-cors';
import { recaptchaAxios } from "../../axios/axiosBackend";
import sendGridMail from '#sendgrid/mail';
sendGridMail.setApiKey(process.env.SENDGRID_API_KEY);
interface FormData {
contactName: string;
contactEmail: string;
contactPhone: string;
contactSubject: string;
contactMessage: string;
token: string;
}
export default async (req: NextApiRequest, res: NextApiResponse) => {
await NextCors(req, res, {
// Options
methods: ['GET','POST'],
origin: '*',
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
});
const formData: FormData = req.body;
console.log("form Data >>>>>>>>>>>>>>",formData)
const human = await validateHuman(formData.token);
if (!human) {
res.status(400);
return res.json({ success: false, errors: ["You are not authenticated"] });
}
const message = {
to: process.env.SENDGRID_MAIL_RECEIVER,
from: process.env.SENDGRID_MAIL_SENDER, // Change to your verified sender
subject: formData.contactSubject,
text: `Name: ${formData.contactName}\n
Contact: ${formData.contactPhone} \n
Email: ${formData.contactEmail} \n
Message: ${formData.contactMessage}`,
html: `Name: ${formData.contactName}
Contact: ${formData.contactPhone}
Email: ${formData.contactEmail}
Message: ${formData.contactMessage}`,
}
try {
await sendGridMail.send(message);
res.status(200);
return res.json({ success: true, errors: [] });
} catch (error) {
console.log(error);
res.status(500);
return res.json({ success: false, errors: ['Error occured while trying to send your details. Please contact your Administrator.']});
}
};
async function validateHuman(token: string): Promise<boolean> {
const secret = process.env.RECAPTCHA_SECRET_KEY;
const response = await recaptchaAxios.post(`/siteverify?secret=${secret}&response=${token}`,{}, {});
const success = response.data['success'];
console.log("server siteverify >>>>>>>>>>>>>",response);
return success;
}
recaptchaAxios has the baseURL as below
const recaptchaAxios = axios.create({
baseURL: `https://www.google.com/recaptcha/api`,
});
I have deployed the same code in vercel as well as using AWS Amplify.
In vercel when called to the above mail API, the Recaptcha token is verified and the mail is sent.
But unfortunately in AWS it gives the error
{ success: false, errors: ["You are not authenticated"] }
I have added all the environment variables in AWS which I have in vercel and the values are the same.
All the domains are added in reCaptch v3 console for the site.
So at this point I am stuck on why in AWS gives the error, but not vercel for the same code base
Is there anything that I am missing in AWS??
Cheers
My first pointer would be to console.log the environment variables on script load, also each time the recaptcha validation is triggered. This way you can be sure the ENV vars are all loaded correctly. You would be suprised to have a small case sensitivity typo, leave you without an important env variable.
Otherwise, I would check if I need to allow outgoing traffic (firewall rules) on AWS amplify, but this is less common, since AWS Amplify spawns a public site.
Issue was in the below code
const secret = process.env.RECAPTCHA_SECRET_KEY;
Even though the RECAPTCHA_SECRET_KEY was available in the environment variables in AWS, it was not accessible.
Fix was to introduce this key in next.config.js file
module.exports = {
images: {
domains: [],
},
env: {
RECAPTCHA_SECRET_KEY: process.env.RECAPTCHA_SECRET_KEY,
},
};
This solved the problem

Stripe "Missing required param: line_items[0][currency]." Node js

I'm creating subscription on node js backend. It had been working good but today I got this error. I didn't made any changes in code - it just starts returning this error.
backend code:
app.post('/api/subscription', async (req, res) => {
const { priceId } = req.body;
try {
const session = await stripe.checkout.sessions.create({
mode: "subscription",
payment_method_types: ["card"],
line_items: [
{
price: priceId,
// For metered billing, do not pass quantity
quantity: 1,
},
],
// {CHECKOUT_SESSION_ID} is a string literal; do not change it!
// the actual Session ID is returned in the query parameter when your customer
// is redirected to the success page.
success_url: 'https://someurl',
cancel_url: 'https://someurl',
});
res.send({
sessionId: session.id,
});
} catch (e) {
console.log(e)
res.status(400);
return res.send({
error: {
message: e.message,
}
});
}
})
from client I'm sending
fetch("http://localhost:8000/api/subscription", {
method: "POST",
body: JSON.stringify({ priceId }),
});
I've taken this code from official stripe example here https://stripe.com/docs/billing/subscriptions/checkout
And as I said it works fine, and now I've tested it on two different stripe accounts and getting the same error. It looks like something changed on stripe but not in their documentation
If priceId is undefined/null it won't be sent in the request. If the Price isn't present the API assumes you're trying to specify information about a line item without using a Price, and one of the first checks it performs is for a valid currency (which you don't have), which results in the Missing required param: line_items[0][currency]. error.
To fix the issue you'll need to figure out why priceId isn't being populated as expected, and you may also want to add a check to make sure priceId is valid before proceeding to the Checkout Session creation step.

Validation with Joi in Axios call not giving correct response

I'm trying to apply validation with Joi on a NodeJS server and my frontend is Vue.
This is my backend validation function (in the AuthenticationPolicy):
register(req, res, next) {
const schema = Joi.object({
email: Joi.string().email(),
password: Joi.string().required()
})
const result = schema.validate(req.body)
if (result.error) {
console.log(`There was an error: ${JSON.stringify(result.error.details)}`)
res.status(400).send(JSON.stringify(result.error.details))
}
else {
next()
}
}
This is the hanlder for the registration:
var authenticationPolicy = require('./policies/AuthenticationPolicy')
router.post('/register', authenticationPolicy.register, (req, res, next) => {
console.log(`Entered registration on server after validation`)
res.send(`Registered! ${req.body.email}`)
})
When I try to enter an invalid Email the server logs:
There was an error: [{"message":"\"email\" must be a valid email","path":["email"],"type":"string.email","context":{"value":"Mailmailmail","key":"email","label":"email"}}]
POST /register 400 43.382 ms - 151
This is the relevant part in the frontend:
Service:
register(credentials) {
return Api().post('/register', credentials) //Api is the axios created to my baseURL
}
Method in component:
async register() {
try {
this.error = null;
await AuthenticationService.register({
email: this.email,
password: this.password
})
}
catch (err) {
console.log(`${err.message}`)
this.error = err.message
}
}
When I run this with an invalid Email (mailmail) the browser logs Request failed with status code 400. Why doesn't the err.message That I log on the front end match the response I get from the backend? If I understand correctly, Axios rejected the promise because of the 400 status so it was thrown, but where did the body go?
Thanks,
Ben
So after many hours of debugging and playing around, I realized that the err object that I catch is an object whose structure I didn't know. Specifically, it has a response component. err.response.data got me what I want.
I would still like to know if anyone has any ideas how could I find something like this out, I didn't see anything that pointed me in this direction in the documentation and I guess the logging wasn't what I expected.

axios is not implementing post request

i am trying to post data with axios (NodeJS, ReactJS) but i ended up getting this errors
and here is my posting code
axios({
method: 'post',
url: '/api/signup',
data:
{
username: this.state.username,
name: this.state.name,
surname: this.state.surname,
email: this.state.email,
password: this.state.password,
confirm_password: this.state.confirm_password,
}
})
.then(res => res.data)
.then(url => window.location.href = url.location)
.catch(error => this.setState({errorBol: true, errorMessage: error}))
and my nodeJS code
router.post('/', async (req,res)=>{
const username = req.body.username;
const name = req.body.name;
const surname = req.body.surname;
const email = req.body.email;
const password = req.body.password;
const confirm_password = req.body.confirm_password;
console.log(username)
console.log(name)
console.log(surname)
console.log(email)
console.log(password)
console.log(confirm_password)
res.status(200).send({location: '/'})
})
i have config for /api/signup like this
router.use('/api/main', require('./sinupfilename'))
so problem is not in router.post('/')
about problem:
i am implementing post request form submission and have a validation for form and it works perfectly but it gives me an errors above when i click submit button so if anyone know clue, i will be glad to hear it
Looks like the issue is not with axios but with your render function. The above issue comes when you are trying to render any object instead of a valid react element.
The issue might be at setState for errorMessage variable. Try printing the errorMessage or typeof errorMessage for further info. It should not be an object.
The error is an javascript object if you read the official documentation for axios.
You need to extract the error message and set it in your errorMessage variable. It should work fine. As per the docs, the same can be done is this similar manner:
const err = ""
if (error.response) {
err = error.response.data
} else if (error.request) {
err = error.request.response
} else {
err = error.message
}
this.setState({errorBol: true, errorMessage: err})
Basically, any thing which needs to be rendered has to be valid react element like string, html tags, numbers but not object. So, you need to make sure that whatever is rendered, it needs to be a valid react element. You can read more about it here
Hope it helps, revert for any doubts.

Setting a test header in GraphQL Playground that I want to use causes "Server cannot be reached"

So I've created a bunch of mutations and queries and stitched them together that works and wanted to introduce authentication into the mix. I added an HTTP Header "x-token" to hold my sign-in token to be able to delete things like their job or the user itself.
const getMe = async req => {
const token = req.headers['x-token'];
if (token) {
try {
return await jwt.verify(token, "notSoSecret");
} catch (e) {
throw new AuthenticationError(
'Your session expired. Sign in again.',
);
}
}
};
const server = new ApolloServer({
typeDefs: schema,
resolvers,
formatError: error => {
// remove the internal sequelize error message
// leave only the important validation error
const message = error.message
.replace('SequelizeValidationError: ', '')
.replace('Validation error: ', '');
return {
...error,
message,
};
},
context: async ({ req }) => {
const me = await getMe(req);
return {
models,
me,
secret: "notSoSecret",
}
},
path: "/graphql"
});
server.applyMiddleware({ app });
sequelize.sync().then(async () => {
createUsersWithJob();
});
app.get("/playground", graphiql({ endpoint: "/graphql" }));
const handler = serverless(app);
export { handler };
const createUsersWithJob = ... //creates seed data
So when I add the token and I look into my command line console, I actually see that I'm setting the header that I want, but it loops over and over again and doesn't stop. Also playground gets an error "Server cannot be reached"
{
"error": "Response not successful: Received status code 400"
}
and running a deleteUser mutation does not work, or any other mutation and query for that matter until I remove the HTTP Header that I set on playground.
There is a secondary issue where everything in this root file runs twice, but that's not as big for me at the moment as the header issue outlined.
If anyone has any insight into this, I'd love to know more. Thanks in advance.
edit: just a quick edit to say that it works fine when I hardcode a pre-existing user.
I had quite a struggle to get the React version of GraphQL Playground working within a very simple html setup, but I figured something out that might help you as well (fingers crossed).
I added a headers section to the config in the GraphQLPlayground.init call, like so:
const root = document.getElementById('root');
GraphQLPlayground.init(root, {
endpoint: "/graphql",
headers: {
"Authorization": "Bearer " + token
}
})
I have an element with an id root since this is embedded in HTML.
Not sure this will help you though, as I just noticed from your code sample you're calling graphiql which is a different GraphQL client than GraphQL Playground..
GraphIQL: https://github.com/skevy/graphiql-app
GraphQL Playground: https://github.com/prisma/graphql-playground

Resources