I am integrating a Twitch API for subs, and having issue with getting the webhook callback response to the middleware function that it should check the header and verify the signature.
I am receive the right response! however, it stops right there!
I check the order of the routes, and I am not sure what I am missing
I am following https://dev.twitch.tv/docs/eventsub
app.post('/createWebhook/:broadcasterId', (req, res) => {
const createWebHookParams = {
host: "api.twitch.tv",
path: "helix/eventsub/subscriptions",
method: 'POST',
headers: {
"Content-Type": "application/json",
"Client-ID": clientId,
"Authorization": "Bearer " + authToken
}
}
const createWebHookBody = {
"type": "channel.follow",
"version": "1",
"condition": {
"broadcaster_user_id": req.params.broadcasterId
},
"transport": {
"method": "webhook",
"callback": "ngrokURL/notification",
"secret": webhookSecret //
}
}
let responseData = ""
const webhookReq = https.request(createWebHookParams, (result) => {
result.setEncoding('utf8')
result.on('data', (d) => {
responseData = responseData + d
})
.on('end', (result) => {
const responseBody = JSON.parse(responseData) // json
console.log(responseBody)
res.send(responseBody)
})
})
webhookReq.on('error', (e) => {
console.log("Error")
})
webhookReq.write(JSON.stringify(createWebHookBody))
webhookReq.end()
});
// middlewsre ---> // not triggered!!!
app.use(express.json({
verify: verifyTwitchSignature
}));
// making post to receeive the notification.
app.post('/notification', (req, res) => {
console.log("incoming notificatin", req.body)
res.status(200).end();
})
// the middleware verifing the signature
const crypto = require("crypto");
const twitchSigningSecret = process.env.SECRET;
const verifyTwitchSignature = (req, res, buf, encoding)=>{
const messageId = req.header("Twitch-Eventsub-Message-Id");
const timeStamp = req.header("Twitch-Eventsub-Message-Timestamp")
const messageSignature = req.header("Twitch-Eventsub-Message-Signature")
console.log(`Message ${messageId} Signature: `,messageSignature)
if (!twitchSigningSecret){
console.log(`Twitch signing secret is empty`);
throw new Error ("Twitch signing secret is empty.");
}
const computedSignature = "sha256=" + crypto.createHmac("sha256", twitchSigningSecret).update(messageId + timeStamp + buf).digist("hex");
console.log(`Message ${messageId} Computed Signature: `, computedSignature)
if (messageSignature !== computedSignature) {
throw new Error("Invalid Signature.");
}else {
console.log("Verification Successful");
}
}
module.exports = verifyTwitchSignature
I believe in your verifyTwitchSignature function you need to pass next as one of the parameters and in the else-statement when it passes call next();.
That is my observation.
If you are working with middleware you always have to pass next together with req and res. next is what calls the next middleware or function in the queue.
Related
I have been working on a real-time tweet streamer app. Whenever the app tries to fetch new tweets, it throws up repeating errors in the console.
I looked into possible solutions and people suggested using the following code:
cors: {
origin: "*",
methods: ["GET", "POST"],
allowedHeaders: ["my-custom-header"],
credentials: true
}
But this error led to another issue and now, my bearer token is not being authenticated.
I am attaching the code of the server.js file below. Would really appreciate it if someone could help me understand the error and the solutions.
const express = require("express");
const bodyParser = require("body-parser");
const util = require("util");
const request = require("request");
const path = require("path");
const socketIo = require("socket.io");
const http = require("http");
const app = express();
let port = process.env.PORT || 3000;
const post = util.promisify(request.post);
const get = util.promisify(request.get);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
const server = http.createServer(app);
const io = socketIo(server);
const BEARER_TOKEN = process.env.TWITTER_BEARER_TOKEN;
let timeout = 0;
const streamURL = new URL(
"https://api.twitter.com/2/tweets/search/stream?tweet.fields=context_annotations&expansions=author_id"
);
const rulesURL = new URL(
"https://api.twitter.com/2/tweets/search/stream/rules"
);
const errorMessage = {
title: "Please Wait",
detail: "Waiting for new Tweets to be posted...",
};
const authMessage = {
title: "Could not authenticate",
details: [
`Please make sure your bearer token is correct.
If using Glitch, remix this app and add it to the .env file`,
],
type: "https://developer.twitter.com/en/docs/authentication",
};
const sleep = async (delay) => {
return new Promise((resolve) => setTimeout(() => resolve(true), delay));
};
app.get("/api/rules", async (req, res) => {
if (!BEARER_TOKEN) {
res.status(400).send(authMessage);
return;
}
const token = BEARER_TOKEN;
const requestConfig = {
url: rulesURL,
auth: {
bearer: token,
},
json: true,
};
try {
const response = await get(requestConfig);
if (response.statusCode !== 200) {
if (response.statusCode === 403) {
res.status(403).send(response.body);
return;
} else {
throw new Error(response.body.error.message);
}
}
res.send(response);
return;
} catch (e) {
res.send(e);
return;
}
});
app.post("/api/rules", async (req, res) => {
if (!BEARER_TOKEN) {
res.status(400).send(authMessage);
return;
}
const token = BEARER_TOKEN;
const requestConfig = {
url: rulesURL,
auth: {
bearer: token,
},
json: req.body,
};
try {
const response = await post(requestConfig);
if (response.statusCode === 200 || response.statusCode === 201) {
res.send(response);
return;
} else {
throw new Error(response);
}
} catch (e) {
res.send(e);
return;
}
});
const streamTweets = (socket, token) => {
let stream;
const config = {
url: streamURL,
auth: {
bearer: token,
},
timeout: 31000,
};
try {
const stream = request.get(config);
stream
.on("data", (data) => {
try {
const json = JSON.parse(data);
if (json.connection_issue) {
socket.emit("error", json);
reconnect(stream, socket, token);
} else {
if (json.data) {
socket.emit("tweet", json);
} else {
socket.emit("authError", json);
}
}
} catch (e) {
socket.emit("heartbeat");
}
})
.on("error", (error) => {
// Connection timed out
socket.emit("error", errorMessage);
reconnect(stream, socket, token);
});
} catch (e) {
socket.emit("authError", authMessage);
}
};
const reconnect = async (stream, socket, token) => {
timeout++;
stream.abort();
await sleep(2 ** timeout * 1000);
streamTweets(socket, token);
};
io.on("connection", async (socket) => {
try {
const token = BEARER_TOKEN;
io.emit("connect", "Client connected");
const stream = streamTweets(io, token);
} catch (e) {
io.emit("authError", authMessage);
}
});
console.log("NODE_ENV is", process.env.NODE_ENV);
if (process.env.NODE_ENV === "production") {
app.use(express.static(path.join(__dirname, "../build")));
app.get("*", (request, res) => {
res.sendFile(path.join(__dirname, "../build", "index.html"));
});
} else {
port = 3001;
}
server.listen(port, () => console.log(`Listening on port ${port}`));
You can not use wildcard origin and credentials at the same time. If you want to use credentials specify domains explicitly.
cors: {
origin: "*", // <-- set origin explicitly.
methods: ["GET", "POST"],
allowedHeaders: ["my-custom-header"],
credentials: true
}
I have the following code below for clover payment api and although the code works perfectly, I do not get a response back when I call the api from postman. I know this is because of the multiple requests in the service and I tried to find a cleaner way to do it but keep failing to get it to work. I am trying to send back the final response which is the response of the request in the postPayment() function. Any help would be appreciated.
my service code is:
const db = require('../_helpers/db');
const crypto = require('crypto');
const request = require("request-promise");
module.exports = {
getAll
};
var targetEnv = 'https://sandbox.dev.clover.com/v2/merchant/';
var cardNumber = '6011361000006668';
async function getAll(data) {
var url = targetEnv + data.merchant_id + '/pay/key';
var options = {
url: url,
method: 'GET',
headers: {
Authorization: 'Bearer ' + data.api_token
}
};
request(options, (error, response, body) => {
if (!error && response.statusCode === 200) {
console.log('getAll ' +data);
processEncryption(JSON.parse(body), JSON.stringify(data));
}
});
}
// Process the encryption information received by the pay endpoint.
function processEncryption(jsonResponse, data) {
console.log('processEncryption ' +data);
var prefix = jsonResponse['prefix'];
var pem = jsonResponse['pem'];
// create a cipher from the RSA key and use it to encrypt the card number, prepended with the prefix from GET /v2/merchant/{mId}/pay/key
var encrypted = crypto.publicEncrypt(pem, Buffer(prefix + cardNumber));
// Base64 encode the resulting encrypted data into a string to Clover as the 'cardEncrypted' property.
var cardEncrypted = new Buffer(encrypted).toString('base64');
return postPayment(cardEncrypted, data);
}
// Post the payment to the pay endpoint with the encrypted card information.
async function postPayment(cardEncrypted, body) {
// POST to /v2/merchant/{mId}/pay
console.log('mid ' +JSON.parse(body));
var posturl = targetEnv + '9ZQTAJSQKZ391/pay';
var postData = {
"orderId": "4N3RBF33EBEGT",
"currency": "usd",
"amount": 2,
"tipAmount": 0,
"taxAmount": 0,
"expMonth": 12,
"cvv": 123,
"expYear": 2018,
"cardEncrypted": cardEncrypted,
"last4": 6668,
"first6": 601136,
"streetAddress": "123 Fake street",
"zip": "94080",
"merchant_id": "9ZQTAJSQKZ391",
"order_id": "4N3RBF33EBEGT",
"api_token": "4792a281-38a9-868d-b33d-e36ecbad66f5"
}
var options = {
url: posturl,
method: 'POST',
headers: {
'Authorization': 'Bearer ' + "4792a281-38a9-868d-b33d-e36ecbad66f5",
},
json: postData
};
request(options, (error, response, body) => {
if (!error && response.statusCode === 200) {
//console.log(response);
return response; <---- this response is what i need to show in postman
}
});
console.log(response);
}
my controller is:
const express = require('express');
const router = express.Router();
const tableOrderService = require('./cloverPayment.service');
// routes
router.post('/getAll', getAll);
module.exports = router;
function getAll(req, res, next) {
tableOrderService.getAll(req.body)
.then(users => res.json(users))
.catch(err => next(err));
}
Your asynchronous functions getAll() and postPayment() are not properly returning an asynchronous value (either via callback or promise).
I'd suggest converting everything to promises and returning a promise from getAll() and from postPayment(). And, since converting to promises, I'd remove the deprecated request-promise library in favor of the got() library. Then, you can call getAll(), get a promise back and use either the resolved value or the rejection to send your response from the actual request handler:
const db = require('../_helpers/db');
const crypto = require('crypto');
const got = require('got');
module.exports = {
getAll
};
var targetEnv = 'https://sandbox.dev.clover.com/v2/merchant/';
var cardNumber = '6011361000006668';
async function getAll(data) {
console.log('getAll ', data);
const url = targetEnv + data.merchant_id + '/pay/key';
const options = {
url: url,
method: 'GET',
headers: {
Authorization: 'Bearer ' + data.api_token
}
};
const response = await got(options);
return processEncryption(response, data);
}
// Process the encryption information received by the pay endpoint.
function processEncryption(jsonResponse, data) {
console.log('processEncryption ' + data);
const prefix = jsonResponse.prefix;
const pem = jsonResponse.pem;
// create a cipher from the RSA key and use it to encrypt the card number, prepended with the prefix from GET /v2/merchant/{mId}/pay/key
const encrypted = crypto.publicEncrypt(pem, Buffer(prefix + cardNumber));
// Base64 encode the resulting encrypted data into a string to Clover as the 'cardEncrypted' property.
const cardEncrypted = Buffer.from(encrypted).toString('base64');
return postPayment(cardEncrypted, data);
}
// Post the payment to the pay endpoint with the encrypted card information.
function postPayment(cardEncrypted, body) {
// POST to /v2/merchant/{mId}/pay
console.log('mid ', body);
const posturl = targetEnv + '9ZQTAJSQKZ391/pay';
const postData = {
"orderId": "4N3RBF33EBEGT",
"currency": "usd",
"amount": 2,
"tipAmount": 0,
"taxAmount": 0,
"expMonth": 12,
"cvv": 123,
"expYear": 2018,
"cardEncrypted": cardEncrypted,
"last4": 6668,
"first6": 601136,
"streetAddress": "123 Fake street",
"zip": "94080",
"merchant_id": "9ZQTAJSQKZ391",
"order_id": "4N3RBF33EBEGT",
"api_token": "4792a281-38a9-868d-b33d-e36ecbad66f5"
}
const options = {
url: posturl,
method: 'POST',
headers: {
'Authorization': 'Bearer ' + "4792a281-38a9-868d-b33d-e36ecbad66f5",
},
json: postData
};
return got(options);
}
And, then your controller:
const express = require('express');
const router = express.Router();
const tableOrderService = require('./cloverPayment.service');
// routes
router.post('/getAll', (req, res) => {
tableOrderService.getAll(req.body)
.then(users => res.json(users))
.catch(err => next(err));
});
module.exports = router;
I'm new to NodeJs and I'm having the problem with response.on('end') I still can't find out the method to send the data I got from the response to the client side.
exports.getCheckoutSession = catchAsync(async (req, res, next) => {
const uuidv1 = require('uuid/v1');
const https = require('https');
const tour = await Tour.findById(req.params.tourId);
console.log(tour);
//parameters send to MoMo get get payUrl
var endpoint = 'https://test-payment.momo.vn/gw_payment/transactionProcessor';
var hostname = 'https://test-payment.momo.vn';
var path = '/gw_payment/transactionProcessor';
var partnerCode = 'MOMO';
var accessKey = 'accessKey';
var serectkey = 'secretKey';
var orderInfo = 'pay with MoMo';
var returnUrl = 'https://momo.vn/return';
var notifyurl = 'https://callback.url/notify';
var amount = (tour.price * 23000).toString();
console.log(amount);
var orderId = req.params.tourId;
var requestId = req.params.tourId;
var requestType = 'captureMoMoWallet';
var extraData = 'merchantName=;merchantId='; //pass empty value if your merchant does not have stores else merchantName=[storeName]; merchantId=[storeId] to identify a transaction map with a physical store
//before sign HMAC SHA256 with format
//partnerCode=$partnerCode&accessKey=$accessKey&requestId=$requestId&amount=$amount&orderId=$oderId&orderInfo=$orderInfo&returnUrl=$returnUrl¬ifyUrl=$notifyUrl&extraData=$extraData
var rawSignature =
'partnerCode=' +
partnerCode +
'&accessKey=' +
accessKey +
'&requestId=' +
requestId +
'&amount=' +
amount +
'&orderId=' +
orderId +
'&orderInfo=' +
orderInfo +
'&returnUrl=' +
returnUrl +
'¬ifyUrl=' +
notifyurl +
'&extraData=' +
extraData;
//puts raw signature
console.log('--------------------RAW SIGNATURE----------------');
console.log(rawSignature);
//signature
const crypto = require('crypto');
var signature = crypto
.createHmac('sha256', serectkey)
.update(rawSignature)
.digest('hex');
console.log('--------------------SIGNATURE----------------');
console.log(signature);
//json object send to MoMo endpoint
var body = JSON.stringify({
partnerCode: partnerCode,
accessKey: accessKey,
requestId: requestId,
amount: amount,
orderId: orderId,
orderInfo: orderInfo,
returnUrl: returnUrl,
notifyUrl: notifyurl,
extraData: extraData,
requestType: requestType,
signature: signature
});
//Create the HTTPS objects
var options = {
hostname: 'test-payment.momo.vn',
port: 443,
path: '/gw_payment/transactionProcessor',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(body)
}
};
//Send the request and get the response
console.log('Sending....');
var req = https.request(options, res => {
console.log(`Status: ${res.statusCode}`);
console.log(`Headers: ${JSON.stringify(res.headers)}`);
console.log('Type of body', JSON.stringify(res.body));
res.setEncoding('utf8');
let fullBody = '';
res.on('data', body => {
fullBody += body;
console.log(' Real Body');
console.log(fullBody);
//console.log('Type of body', body.payUrl);
// console.log(JSON.parse(body).payUrl);
// res.redirect(JSON.parse(body).payUrl);
});
res.on('end', () => {
const payURL = JSON.parse(fullBody).payUrl;
console.log('payUrl', payURL);
console.log('No more data in response.');
});
});
req.on('error', e => {
console.log(`problem with request: ${e.message}`);
});
// write data to request body
req.write(body);
req.end();
});
This is the url I got from response
payUrl https://test-payment.momo.vn/gw_payment/payment/qr?partnerCode=MOMO&accessKey=F8BBA842ECF85&requestId=5f38cc86954a6206211e2842&amount=23000&orderId=5f38cc86954a6206211e2842&signature=37ae247d56efd9ed6630b7d7d1435b88ffb8895956da5711a62ebbab8118aa7b&requestType=captureMoMoWallet
Can you please tell how could i send the data from res.on('end'), the "payURL" in the picture above, to client-side. I have tried some methods like res.writeHead, res.send, res.json( ) .... But they all returned error: res.send, res.writeHead, res.json... is not a function
This is my client-side, . If you guys don't mind , please also show me how to automatically redirect the payURL site above when the client click my button. Should I keep using window.location.replace like above ?
export const bookTour = async tourId => {
try {
const res = await fetch(
`http://localhost:3000/api/v1/bookings/checkout-session/${tourId}`,
{
method: 'POST',
body: 'a=1'
}
).then(res => window.location.replace(res.redirectURL));
console.log('The res', res);
} catch (err) {
showAlert('error', err);
}
};
This is my index.js
if (bookBtn) {
bookBtn.addEventListener('click', e => {
e.target.textContent = 'Processing...';
const tourId = e.target.dataset.tourId;
bookTour(tourId);
});
}
You're shadowing the req/res-variables from your getCheckoutSession-handler by using the same names for your http-request. If you change it to:
const request = https.request(options, response => {
// ...
let fullBody = '';
response.on('data', body => {
fullBody += body;
});
response.on('end', () => {
const payURL = JSON.parse(fullBody).payUrl;
// access the handler "res" object here
res.send(payURL);
// alternatively use res.json({payURL}) to send a json response
});
});
it should work fine.
Note: Nowadays you should definitely use const/let instead of var (see this for more information)
Simple,
res.on('end', () => {
const payURL = JSON.parse(fullBody).payUrl;
res.json({
payURL: payURL
})
});
or other way
res.on('end', () => {
const payURL = JSON.parse(fullBody).payUrl;
res.status(200).send({
payURL: payURL
});
});
I cannot able to validate the webhook response from the shopify by using the "shopify-node-api". and i am using the following code to validate the signature.
Below code is on app.js
app.use(bodyParser.json({
type:'application/json',
limit: '50mb',
verify: function(req, res, buf, encoding) {
if (req.url.startsWith('/webhook')){
req.rawbody = buf;
}
}
})
);
app.use("/webhook", webhookRouter);
Below on webhook.router.js
router.post('/orders/create', verifyWebhook, async (req, res) => {
console.log('🎉 We got an order')
res.sendStatus(200)
});
Below for the verification function
function verifyWebhook(req, res, next) {
let hmac;
let data;
try {
hmac = req.get("X-Shopify-Hmac-SHA256");
data = req.rawbody;
} catch (e) {
console.log(`Webhook request failed from: ${req.get("X-Shopify-Shop-Domain")}`);
res.sendStatus(200);
}
if (verifyHmac(JSON.stringify(data), hmac)) { // Problem Starting from Here
req.topic = req.get("X-Shopify-Topic");
req.shop = req.get("X-Shopify-Shop-Domain");
return next();
}
return res.sendStatus(200);
}
Verify signature function
function verifyHmac(data, hmac) {
if (!hmac) {
return false;
} else if (!data || typeof data.data !== "object") {
// I am Getting Error HERE
console.log('Error in data', data);
return false;
}
const sharedSecret = config.shopify_shared_secret;
const calculatedSignature = crypto
.createHmac("sha256", sharedSecret)
.update(Buffer.from(data), "utf8")
.digest("base64");
console.log('calculatedsecret', calculatedSignature);
return calculatedSignature === hmac;
};
and the body I am getting it as undefined. suggest me how to fix this problem in shopify webhook API
Instead of using the bodyparser.json() use bodyparser.raw to fetch the all the payload to process the shopify webhook verification.
router.use(bodyparser.raw({ type: "application/json" }));
// Webhooks
router.post("/", async (req, res) => {
console.log("Webhook heard!");
// Verify
const hmac = req.header("X-Shopify-Hmac-Sha256");
const topic = req.header("X-Shopify-Topic");
const shop = req.header("X-Shopify-Shop-Domain");
const verified = verifyWebhook(req.body, hmac);
if (!verified) {
console.log("Failed to verify the incoming request.");
res.status(401).send("Could not verify request.");
return;
}
const data = req.body.toString();
const payload = JSON.parse(data);
console.log(
`Verified webhook request. Shop: ${shop} Topic: ${topic} \n Payload: \n ${data}`
);
res.status(200).send("OK");
});
// Verify incoming webhook.
function verifyWebhook(payload, hmac) {
const message = payload.toString();
const genHash = crypto
.createHmac("sha256", process.env.API_SECRET)
.update(message)
.digest("base64");
console.log(genHash);
return genHash === hmac;
}
*Edited for clarity and to reflect changes:
Hello. I'm struggling to understand why my async functions are working just fine individually, and when chained together, but not when chained together and fired off in an event listener....
worth noting: when i try to run this without an even listener, data passes from my app, through my post route, and to my endpoint the way it should, it is then returned to my app through the correct route, etc. However, i do get an error in the console that says :
error SyntaxError: Unexpected token < in JSON at position 0
however, when i try to run my chain of async functions on the click of a dom element i don't get the above error, data is passed to my post route, i can log the object that is posted:
Object: null prototype] { zipcode: '97206', feel: 'confused' }
but then my server doesn't save any data, and my get route is never triggered, and nothing gets sent back to my app.......
i'm fairly lost.....
full server and app code below:
server:
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors());
app.use(express.static('public'));
//test values
let projectData = {
date: "today",
temp: "38",
feelings: "confused"
};
app.get("/", (req, res) => {
});
app.post("/postData", (req, res) => {
console.log(req.body)
projectData = {
date: req.body.date,
temp: req.body.temp,
feelings: req.body.feelings
}
console.log("post route was hit, saved:", projectData);
res.redirect("/")
});
app.get("/getData", (req, res) => {
console.log("getData route was hit, sent: ", projectData)
res.send(projectData);
})
app.listen(3000, (req, res) => {
console.log("Listening on port 3000");
});
app
let newDate = getDate();
const apiKey = "5fd7b3a253e67a551e88ff34a92b9e02";
const baseURL = "http://api.openweathermap.org/data/2.5/weather?";
// zip=${}&APPID=${}&units=metric;
const userData = {};
// returns the date //
function getDate() {
let d = new Date();
let newDate = d.getMonth() + "." + d.getDate() + "." + d.getFullYear();
return newDate;
}
//constructs string for api call, adds temp to userData object
const getData = async (apiUrl, zip, key) => {
const url = `${apiUrl}zip=${zip}&APPID=${key}&units=metric`;
const result = await fetch(url);
try {
let newData = await result.json()
// console.log(newData.main.temp)
userData.temp = newData.main.temp
}catch(error) {
console.log("error", error);
}
}
// getData(baseURL, 97206, apiKey)
// .then(result => {
// console.log(userData)
// })
//saves contents of userData Object to server
const postData = async (url, data) => {
const result = await fetch(url, {
method: "POST",
credentials: "same-origin",
headers: {
"Content-type": "application/json"
},
body: JSON.stringify(data)
});
try {
const newData = await result.json();
// console.log(newData);
return newData;
} catch (error) {
console.log("error", error);
}
};
// postData('/postData', userData);
//updates interface with projectData values from server
const updateUI = async url => {
const result = await fetch(url);
try {
const newData = await result.json();
document.getElementById("date").innerHTML = newData.date;
document.getElementById("temp").innerHTML = newData.temp;
document.getElementById("feelings").innerHTML = newData.feelings;
} catch (error) {
console.log("error", error);
}
};
// updateUI("/getData")
// THIS WORKS
userData.date = newDate;
userData.feelings = document.getElementById("feel").value;
const zipCode = document.getElementById("zipcode").value;
getData(baseURL, 97206, apiKey).then(result => {
postData("/postData", userData).then(result => {
updateUI("/getData");
});
});
// THIS DOESNT WORK
// document.getElementById("btn").addEventListener("click", e => {
// userData.date = newDate;
// userData.feelings = document.getElementById("feel").value;
// const zipCode = document.getElementById("zipcode").value;
// getData(baseURL, zipCode, apiKey).then(result => {
// postData("/postData", userData).then(result => {
// updateUI("/getData");
// });
// });
// });
EDIT:
I realized that the information that was being passed through the post route when my async functions are fired off by an event listener was actually just the form input element values, rather than the contents of the fetch/post request. after i removed the name attributes from the form inputs, i'm getting no data at all hitting my post route......yet the corosponding function works fine with not in the event listener.
I'm stumped.
well, the syntax error was solved by using .text() instead of .json() on the results of my post request.
adding e.preventDefault() as the first line of my event listener callback fixed the event listener, and now everything is working as it should.