I have a webhook I'm using to write data to firebase when a stripe purchase happens, and I cant get it to work.
I've tried adding try/catch statements around everything, i cant seem to catch the error regardless.
Im using the nextJS backed debugging as found here:
https://nextjs.org/docs/advanced-features/debugging
My question is why? all my api keys are correct.
the error :
[ERROR] Failed to POST: Post "http://localhost:3000/api/webhook": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
The Webhook:
import { buffer } from "micro";
import * as admin from "firebase-admin";
//secure a connection to firebase
const serviceAccount = require("../../../permissions.json");
const app = !admin.apps.length
? admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
})
: admin.app();
//connect to stripe
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);
const endpointSecret = process.env.STRIPE_SIGNING_SECRET;
const fullfillOrder = async (session) => {
try {
return app
.firestore()
.collection("users")
.doc(session.metadata.email)
.collection("orders")
.doc(session.id)
.set({
amount: session.amount_total / 100,
amount_shipping: session.total_details.amount_shipping / 100,
images: JSON.parse(session.metadata.images),
timestamp: admin.firestore.FieldValue.serverTimestamp(),
})
.then(() => {
console.log(`SUCCESS : Order ${session.id} has been added to DB.`);
});
} catch (error) {
console.error(error);
}
};
export default async (req, res) => {
try {
} catch (error) {
console.error(error);
}
if (req.method === "POST") {
const requestBuffer = await buffer(req);
const payload = requestBuffer.toString();
const sig = req.headers["stripe-signature"];
let event;
//verify that event posted from stripe
try {
event = stripe.webhooks.constructEvent(payload, sig, endpointSecret);
} catch (err) {
return res.status(400).send(`Webhook error : ${err.message}`);
}
//Handle checkout session completed event
try {
if (event.type === "checkout.session.completed") {
const session = event.data.object;
return fullfillOrder(session)
.then(() => res.status(200))
.catch((err) =>
res.status(400).send(`Webhook Error :${err.message}`)
);
}
} catch (error) {
console.log("🚀 ~ file: webhook.js ~ line 56 ~ error", error);
}
}
};
export const config = {
api: {
bodyParser: false,
externalResolver: true,
},
};
Related
This is the front-end code which is used for sending access token to server site.
useEffect(() => {
const getProducts = async () => {
try {
const url = `http://localhost:5000/product?email=${user.email}`
const { data } = await axios.get(url, {
headers: {
authorization: localStorage.getItem('accessToken')
}
});
setProducts(data);
} catch (err) {
const status = err.response.status;
if (status === 401 || status === 403) {
signOut(auth);
navigate('/login');
localStorage.removeItem('accessToken')
toast.error(err.response?.data?.message);
}
}
}
getProducts();
}, [user.email]);
This is server site express code for response. Why every time it is receiving two request and sending two response?
app.get('/product', verifyToken, async (req, res) => {
const decoded = req.decoded?.email;
const queryEmail = req.query?.email;
if (decoded === queryEmail) {
const query = { email: queryEmail };
const cursor = medicineCollection.find(query);
const products = await cursor.toArray();
res.send(products);
} else {
res.status(403).send({ message: "Forbidden Access" })
}
})
Maybe you take user.email in a state which is updating somehow so that's why useEffect is calling again and giving you twice response.
I want to make 100% coverage on this function with node-tap but I can't mock the error part, it always throw
Cannot find module 'create' Require stack: - /home/mptr8/Code/Projects/me/fastify-example/fastify-postgres/test/integration.js
But I have create function on my query.js file, what do I do wrong here? Why it doesn't invoke the method?
t.mock("../query.js", {
create: () => {
throw new Error();
},
});
I also try this combination, because query.js are dependent on db.js. Now the mock error gone but still I'm not getting the error throw from my fastify.inject.
t.mock("../db.js", {
"../query.js": {
create: () => { throw new Error() },
},
});
app.post("/", async (request, reply) => {
try {
const { body } = request;
const book = create(body.title);
reply.send(book);
} catch (error) {
// this part are not covered
reply.code(500).send({ message: "internal server error" });
}
});
here are my complete code. You can see the full code on this github repository.
// server.js
const fastify = require("fastify");
const {
migration,
create,
} = require("./query");
const db = require("./db");
function build(opts = {}) {
const app = fastify(opts);
migration();
app.post("/", async (request, reply) => {
try {
const { body } = request;
const book = create(body.title);
reply.send(book);
} catch (error) {
reply.code(500).send({ message: "internal server error" });
}
});
app.addHook("onClose", (_instance, done) => {
db.close();
done();
});
}
module.exports = build;
// db.js
const { Pool } = require("pg");
const pool = new Pool({
connectionString:
"postgresql://postgres:postgres#localhost:5432/fastify_postgres?schema=public",
});
module.exports = {
query: (text, params) => pool.query(text, params),
close: () => pool.end(),
};
// query.js
const db = require("./db");
async function migration() {
await db.query(`
CREATE TABLE IF NOT EXISTS books (
id serial PRIMARY KEY,
title varchar (255) NOT NULL
)
`);
}
async function create(title) {
return await db.query("INSERT INTO books (title) VALUES ($1)", [title]);
}
module.exports = { migration, create };
// test.js
const tap = require("tap");
const fastify = require("../server");
tap.test("coba", async (t) => {
const app = await fastify();
t.test("should success create books", async (t) => {
const response = await app.inject({
method: "POST",
url: "/",
payload: {
title: "Hello,World!",
},
});
t.equal(response.statusCode, 200);
});
t.test("should throw error", async (t) => {
const app = await fastify();
// it doesn't throw the error :((
t.mock("../query.js", {
create: () => {
throw new Error();
},
});
const response = await app.inject({
method: "POST",
url: "/",
payload: {
title: "Hello,World!",
},
});
t.equal(response.statusCode, 500);
// call app close on last test child to close app and db properly
app.close();
});
});
You should use the returned value by the t.mock function:
const build = t.mock({
"../server": {
"./query.js": {
create: () => { throw new Error() },
}
}
})
const app = await build({})
I have simple route:
fastify.post('/subscribe', {
schema: subscribeSchema,
handler: async (req, reply) => {
try {
const events = req.body.events;
const allEventsProcessingData = await Promise.all(events.map(async (ev) => {
return {
event: ev,
feedEventsData: await getFeedEventData(ev),
feedMainMarketsData: await getFeedEventMainMarketsData(ev),
}
}));
// process HTML by events data
// allEventsProcessingData
const compiledHTML = '';
return reply.send(compiledHTML);
} catch (e) {
console.log('e', e);
return reply.send(HTTP_RESPONSES.FAIL);
}
}
});
When error happens, the response does not send, why is it? And how to send it? Tried this https://github.com/fastify/fastify/issues/1864#issuecomment-534233381, but it did not work.
As I am new to botkit, I have created the bot locally as per the docs. But when it is trying to call an external API using axios, below error shows -
UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'get' of undefined
Here is the code -
const { BotkitConversation } = require("botkit");
const { axios } = require("axios");
module.exports = function(controller) {
const convo = new BotkitConversation('convo', controller);
convo.before('default', async(convo, bot) => {
axios.get(...https url...) //error line
.then(function (response) {
convo.setVar('api-response', response);
})
.catch(function (error) {
console.log(error);
})
});
convo.ask('What is your name?', async(response, convo, bot) => {
console.log(`user name is ${ response }`);
}, 'name');
convo.addAction('msg');
convo.addMessage('Hi {{vars.name}}! Welcome to my Botkit', 'msg');
}
Can someone point out what is wrong on this code?
Trying to test failure scenario for the middleware , v1TransformResponse will throw error on some validation now in unit testing i am not able to get expected result , any idea what is implemented wrong in below test ? i have added the error i am getting.
server.js
app.post('/cvs/v1/drugprice/:membershipId', orchestrateDrugPrice, v1TransformResponse);
v1TransformResponse.js
module.exports = async (req, res) => {
try {
const validateResponse = responseHandler(req.drugPriceResponse);
const transformedResponse = transformResponse(validateResponse);
const filterDrug = filteredResponse(transformedResponse);
logDrugPriceResponse('TRANSFORMED_RESPONSE V1', filterDrug);
res.status(200).send({ drugPrice: filterDrug });
} catch (error) {
if (error instanceof AppError) {
res.status(error.response.status).send(error.response.payload);
} else {
res.status(500).send(defaultErrorResponse);
}
}
};
main.test.js
const { expect } = require('chai');
const sinon = require('sinon');
const { spy, stub } = require('sinon');
const request = require('supertest');
const app = require('./../../../server/server');
const v1TransformResponse = require('./../../../server/middleware/v1TransformResponse');
const orchestrateDrugPrice = require('./../../../server/middleware/orchestrateDrugPrice');
describe('v1Transform()', () => {
let status,
send,
res;
beforeEach(() => {
status = stub();
send = spy();
res = { send, status };
status.returns(res);
});
describe('if called with a request that doesn\'t have an example query', () => {
const req = {
drugPriceResponse: [{
'brand': false,
'drugName': 'Acitretin',
'drugStrength': '10mg',
'drugForm': 'Capsule',
'retailPrice': {
'copayEmployer': '0',
'costAnnual': '3',
'costEmployer': '733.84',
'costToday': 'N/A',
'daysSupply': '30',
'deductible': 'n/a',
'memberCopayAmount': '30',
'NDC11': '378702093',
'penalties': 'N/A',
'totalDrugCost': '763.84'
}
}]
};
beforeEach(() => (req, res));
it('should return error if prices are ommitted', async () => {
try {
await v1TransformResponse(req, res);
} catch (error) {
expect(error.response).to.deep.equal({
httpStatus: 500,
payload: {
status: 500,
title: 'Internal Server Error',
detail: 'Drug prices are not valid'
}
});
}
});
});
});
ERROR:
if called with a request that doesn't have an example query
should return error if prices are ommitted:
AssertionError: expected undefined to deeply equal { Object (httpStatus, payload) }
The middleware v1TransformResponse doesn't throw errors in failure case. It calls res.status method. You need to check the parameter passed to it.
it('should return error if prices are ommitted', async () => {
await v1TransformResponse(req, res);
expect(res.status.getCall[0].args[0]).to.equal(500);
});