I am attempting to setup fee processing for my iOS app. As soon as the fee receipt is generated in iOS – we ship it to Node.JS backend buy_subscription endpoint, which verifies receipt utilizing VerifyAppleReceipt perform, generates order knowledge to be inserted into DB utilizing generateOrderData perform. Nevertheless, when I attempt to buy my auto-renewable subscription – I consistently get backend error:
PayloadTooLargeError: request entity too massive
at readStream
at getRawBody
at learn
at jsonParser
at Layer.deal with [as handle_request]
at trim_prefix
at
at Operate.process_params
at subsequent
at expressInit
In some unspecified time in the future previously I used to be in a position to course of the acquisition appropriately and write generated knowledge into DB.
I think the scale of receipt has one thing to do with it. Since I take advantage of Apple sandbox account for testing – each sandbox buy generates 6 purchases in latest_receipt_info of Apple Receipt (5 minutes * 6 renewals = 1 month of sandox). So presently my poor receipt has 254 operations in it.
const verifyAppleReceipt = async (receiptData) => {
addLog(`[verifyAppleReceipt] Beginning verification`);
addLog(`[verifyAppleReceipt] Receipt preview: ${receiptData.substring(0, 20)}...`);
const requestPayload = {
'receipt-data': receiptData,
'password': 'exampleData',
'exclude-old-transactions': true
};
addLog(`[verifyAppleReceipt] Payload keys: ${Object.keys(requestPayload).be a part of(',')}`);
strive {
addLog(`[verifyAppleReceipt] Requesting manufacturing endpoint...`);
let response = await axios.submit('https://purchase.itunes.apple.com/verifyReceipt', requestPayload);
addLog(`[verifyAppleReceipt] Manufacturing response standing: ${response.knowledge.standing}`);
if (response.knowledge.standing === 21007) {
addLog(`[verifyAppleReceipt] 21007 = Sandbox receipt, switching to sandbox endpoint...`);
response = await axios.submit('https://sandbox.itunes.apple.com/verifyReceipt', requestPayload);
addLog(`[verifyAppleReceipt] Sandbox response standing: ${response.knowledge.standing}`);
}
return response.knowledge;
} catch (error) {
addLog(`[verifyAppleReceipt] Error: ${error.message}`);
throw error;
}
};
async perform generateOrderData({ parsedReceipt, uid, receiptData, productId, quantity, isAutoRenewable }) {
strive {
const transaction = parsedReceipt.latest_receipt_info?.slice(-1)[0] || parsedReceipt.receipt?.in_app?.slice(-1)[0];
if (!transaction) throw new Error('No legitimate transaction present in receipt');
const order_id = `APPLE${transaction.transaction_id}`;
const transactionDate = new Date(parseInt(transaction.purchase_date_ms));
console.log("[GENERATE ORDER] Getting member information for:", uid);
const memResult = await executeQuery(`SELECT idx FROM MemberInfo WHERE id = N'${uid}'`);
if (!Array.isArray(memResult) || memResult.size === 0) throw new Error('Person not discovered');
const mem_idx = memResult[0].idx;
const item_settle_choice = isAutoRenewable ? 1 : (quantity === 1 ? 1 : quantity === 6 ? 2 : quantity === 12 ? 3 : 0);
console.log("[GENERATE ORDER] Getting present product information for:", mem_idx);
const existingProResult = await executeQuery(`SELECT pro_date_start FROM tv_myitem_tb WHERE mem_idx = ${mem_idx}`);
const existingProStart = existingProResult?.[0]?.pro_date_start;
const pro_date_start = existingProStart || transactionDate;
const daysToAdd = isAutoRenewable ? 3 : (typeof quantity === 'quantity' ? 30 * quantity : 0);
let pro_date_end = DateTime.fromJSDate(transactionDate).plus({ days: daysToAdd }).toJSDate();
const worth = isAutoRenewable ? 13000 : (quantity === 1 ? 13000 : quantity === 6 ? 70000 : quantity === 12 ? 120000 : 0);
return {
order_id,
regdate: transactionDate,
item_settle_choice,
mem_idx,
mem_id: uid,
pro_date_start,
pro_date_end,
receiptData,
productId,
worth
};
} catch (error) {
console.error("[GENERATE ORDER] Error:", error);
throw error;
}
}
perform toUTCFromLocal(date) {
return DateTime.fromJSDate(date).toUTC(); // Converts a JavaScript Date object to a Luxon DateTime object and returns UTC
}
router.submit("/buy_subscription", async perform (req, res) {
strive {
const { uid, receiptData, productId } = req.physique;
console.log("[BUY MEMBERSHIP] Beginning buy for:", uid);
const existingOrder = await executeQuery(`SELECT order_idxx FROM web_pay_apple_log WHERE productId = N'${productId}' AND receiptData = N'${receiptData}'`);
if (Array.isArray(existingOrder) && existingOrder.size > 0) {
return res.finish('{"rtnCd":"fail","rtnMsg":["Duplicate receipt detected"]}');
}
const appleResponse = await verifyAppleReceipt(receiptData);
if (appleResponse.standing !== 0) throw new Error("Verification failed");
const orderData = await generateOrderData({ parsedReceipt: appleResponse, uid, receiptData, productId, isAutoRenewable: true });
const checkQuery = `SELECT pro_date_count FROM tv_myitem_tb WHERE pro_code="915" AND mem_idx = ${orderData.mem_idx}`;
console.log("[BUY MEMBERSHIP] Checking present membership:", checkQuery);
const checkResult = await executeQuery(checkQuery);
const proDateCount = checkResult?.[0]?.pro_date_count || 0;
if (proDateCount === 0) {
const insertQuery = `
INSERT INTO tv_myitem_tb(mem_idx, mem_id, pro_cate, pro_code, pro_name, pro_gubun, pro_date_count, dnis, pro_date_start, pro_date_end)
SELECT idx, id, 1, '915', N'정회원 자동결제', 2, 1, '15', GETDATE(), DATEADD(dd, 3, GETDATE())
FROM MemberInfo WHERE idx = ${orderData.mem_idx}
`;
console.log("[BUY MEMBERSHIP] Inserting new membership:", insertQuery);
await executeQuery(insertQuery);
} else {
const updateQuery = `
UPDATE tv_myitem_tb
SET pro_date_end = DATEADD(dd, 3, GETDATE())
WHERE mem_idx = ${orderData.mem_idx} AND pro_code="915"
`;
console.log("[BUY MEMBERSHIP] Updating present membership:", updateQuery);
await executeQuery(updateQuery);
}
const logQuery = `
INSERT INTO web_pay_apple_log(order_idxx, id, cd_value, item_settle_choice, item_code_idx, item_name, cd_info, website, productId, receiptData, mem_idx)
VALUES (N'${orderData.order_id}', N'${orderData.mem_id}', ${orderData.worth}, ${orderData.item_settle_choice}, '915', N'정회원 자동결제', '1', 'land', N'${orderData.productId}', N'${orderData.receiptData}', ${orderData.mem_idx})
`;
console.log("[BUY MEMBERSHIP] Logging transaction:", logQuery);
await executeQuery(logQuery);
res.finish('{"rtnCd":"success","rtnMsg":[""]}');
} catch (error) {
console.error("[BUY MEMBERSHIP] Error:", error);
res.finish('{"rtnCd":"fail","rtnMsg":["Error processing payment"]}');
}
});
Since I do not see any debug logging – I think that no matter buy_membership does fails earlier than something is executed and I can not determine it out.
Any suggestions? I simply must confirm the receipt, parse it and get TransactionDate from it.