I am trying to post data from my form to MailChimp API server with node.js and express. However, I am getting an error message that seems strange to debug. I have checked my index.html file and all is well there. Please help me figure out a solution or point me in the right direction. Kindly check out my code below:
const express = require("express");
const bodyParser = require("body-parser");
const https = require("https");
const app = express();
app.use(bodyParser.urlencoded({extended:true}));
app.use(express.static("public"));
app.listen(3000, function(){
"Server is running on Port 3000!"
});
app.get("/", function(req, res){
res.sendFile(__dirname + "/signup.html");
});
app.post("/", function(req, res){
const firstName = req.body.firstName;
const lastName = req.body.lastName;
const email = req.body.email;
console.log(firstName, lastName, email);
var data= {
members: [
{
email_address : email,
status : "subscribed",
merge_fields : {
FNAME : firstName,
LNAME : lastName
}
}
]
};
var jsonData = JSON.stringify(data);
const url ="https://us10.api.mailchimp.com/3.0/lists/{apikey}";
const options = {
method: "post",
auth: "xxxx:xxxx"
}
const request= https.get(url, options, function(response){
response.on("data", function(data){
console.log(JSON.parse(data));
})
})
request.write(jsonData);
request.end();
});
This is the error I am getting.
events.js:200
throw er; // Unhandled 'error' event
^
Error [ERR_STREAM_WRITE_AFTER_END]: write after end
at write_ (_http_outgoing.js:594:17)
at ClientRequest.write (_http_outgoing.js:586:15)
at C:\Users\Iredafe\Desktop\Web Development practice\Email-List\app.js:48:9
at Layer.handle [as handle_request] (C:\Users\Iredafe\Desktop\Web Development practice\Email-List\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\Iredafe\Desktop\Web Development practice\Email-List\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (C:\Users\Iredafe\Desktop\Web Development practice\Email-List\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\Users\Iredafe\Desktop\Web Development practice\Email-List\node_modules\express\lib\router\layer.js:95:5)
at C:\Users\Iredafe\Desktop\Web Development practice\Email-List\node_modules\express\lib\router\index.js:281:22
at Function.process_params (C:\Users\Iredafe\Desktop\Web Development practice\Email-List\node_modules\express\lib\router\index.js:335:12)
at next (C:\Users\Iredafe\Desktop\Web Development practice\Email-List\node_modules\express\lib\router\index.js:275:10)
Emitted 'error' event on ClientRequest instance at:
at writeAfterEndNT (_http_outgoing.js:649:7)
at processTicksAndRejections (internal/process/task_queues.js:82:21) {
code: 'ERR_STREAM_WRITE_AFTER_END'
}
[nodemon] app crashed - waiting for file changes before starting...
You can use axios for simplicity.
const axios = require('axios');
const headers = {
'Content-Type': 'application/json',
'Authorization': 'JWT fefege...'
}
axios.post(url,postPayload,headers)
.then(response => {
console.log(response.data);
})
.catch(error => {
console.log(error);
});
I just found the answer. It was a bug in my code. I am using the native https method in Node hence I ought not to use https.get here:
const request= https.get(url, options, function(response){
response.on("data", function(data){
console.log(JSON.parse(data));
})
})
request.write(jsonData);
request.end();
the correct code that solved the problem was using the http.request instead of http.get:
const request= https.request(url, options, function(response){
response.on("data", function(data){
console.log(JSON.parse(data));
})
})
request.write(jsonData);
request.end();
Hope it helps someone in the future!
Related
I am developing a dashboard, I need to conect to a API and catch a Auth Token and afther that send info by using a HTTPS protocol. I use a Nodejs, and when I run my code I have the next error on the pm2 monit:
Error: getaddrinfo ENOTFOUND my.url.net/path
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:67:26) {
errno: -3008,
code: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'my.url.net/path'
}
Also here is my code where I made the request (Node.js):
const path = require('path');
require('dotenv').config({path: path.join('path','.env')});
const https = require('https');
const database = require('./sql');
const fs = require ('fs');
const user = process.env.USER;
const pwd = PWD;
const host = 'https://my.url.net/extencio';
const host_1 = 'my.url.net/extention';
async function getLoginToken(pForce){
if (login_token.Health && !pForce) { return login_token }
//Creates the POST request
const options = {
protocol: 'https:',
hostname: host_1,
path: '/api/auth/token',
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
};
//Body of the POST request, contains the user and password
const post_data = JSON.stringify({username: user, password: pwd});
.
Here is the rest of the code:
return new Promise((resolve, reject) => {
const req = new https.request(options, (response) => {
response.setEncoding('utf8');
response.on('data', function(chunk){
const output = JSON.parse(chunk);
if(output.token){
login_token.Health = true;
login_token.Token = output.token;
resolve(login_token)
}
else{
login_token.Health = false;
login_token.Token = '';
resolve(login_token);
}
});
});
req.write(post_data);
req.end();
req.on('error', function(err) {
console.log(err);
login_token.Health = false;
login_token.Token = '';
resolve(login_token)
});
});
}
Remove protocol, and use domain names only for the host. For instance:
Wrong:
const host = 'https://my.url.net/extencio'
const path = '/api/auth/token'
Correct:
const host = 'my.url.net'
const path = '/extencio/api/auth/token'
See documentation for the http.request options.
It seems that is trying to getaddrinfo of the full url, instead of just the hostname. I would put hostname in option as only "my.url.net" and update path with the rest of the url.
#Eric0607 the error stackoverflow.com/questions/65810720/… you've provided is not showing anymore, I might've been too late to reply.
but in case you got "an invalid local cert SSL error", here is a fix I found that works for it.
disable SSL check in your code, not recommended but it would work temporarily, turn it on after you're done or it can be risky.
I'm a new developer learning how to work with API's and I've run into this error a few times now that keeps crashing Node:
SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
at IncomingMessage.<anonymous> (/Users/SA/Desktop/pokeApp/app.js:13:34)
at IncomingMessage.emit (events.js:314:20)
at IncomingMessage.Readable.read (_stream_readable.js:513:10)
at flow (_stream_readable.js:986:34)
at resume_ (_stream_readable.js:967:3)
at processTicksAndRejections (internal/process/task_queues.js:80:21)
I'm not really sure how to resolve it or what the problem is exactly... my JS code looks like this:
const express = require("express");
const https = require("https");
const app = express();
app.get("/", (req,res) => {
const url = "https://pokeapi.co/api/v2/pokemon/1/";
https.get(url, function(response){
console.log(response.statusCode);
response.on("data", (data) =>{
const pokemon = JSON.parse(data);
console.log(pokemon);
})
})
res.send("server running");
})
app.listen(3000, () => {
console.log("Port 3000");
})
This is basically the same setup I used for a weatherAPI and had no issues.
I also checked the JSON with JSON lint to see if there were any problems and it came back okay.
You need to wait for the full response to come in - it's a large file, so it may not come in all at once:
https.get(url, function(response){
let result = '';
response.on("data", (data) =>{
result += data;
});
response.on('end', () => {
const pokemon = JSON.parse(result);
console.log(pokemon);
});
})
This is my server.js file code . I am trying to push the JSON content in the user object , but i am getting following error. Please tell me where i am going wrong.
const express = require('express')
const app = express()
const bcrypt = require('bcrypt')
const bodyParser = require('body-parser')
app.use(express.json())
const users = []
app.get('/users', (req, res) => {
JSON.stringify(users)
res.json(users)
})
app.post('/users', (req, res) => {
const user = {
name: req.body.name,
password: req.body.password
}
users.push(user)
res.status(201).send()
})
app.listen(3000, console.log("server started"));
I used an extension in VS code called REST client.
GET http: //localhost:3000/users
#####
POST http: //localhost:3000/users
Content-Type: application/json
{
"name": "Tanay",
"password": "password"
}
When I'm firing POST request it shows the error - SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
at parse (C:\Users\TANAY RAJ\Desktop\nodePassport\Wsimplified\node_modules\body-parser\lib\types\json.js:89:19)
at C:\Users\TANAY RAJ\Desktop\nodePassport\Wsimplified\node_modules\body-parser\lib\read.js:121:18
at invokeCallback (C:\Users\TANAY RAJ\Desktop\nodePassport\Wsimplified\node_modules\raw-body\index.js:224:16)
at done (C:\Users\TANAY RAJ\Desktop\nodePassport\Wsimplified\node_modules\raw-body\index.js:213:7)
at IncomingMessage.onEnd (C:\Users\TANAY RAJ\Desktop\nodePassport\Wsimplified\node_modules\raw-body\index.js:273:7)
at IncomingMessage.emit (events.js:322:22)
at endReadableNT (_stream_readable.js:1187:12)
at processTicksAndRejections (internal/process/task_queues.js:84:21)
Can be something wrong with the user variable. Can you check this:
const user={'name':req.body.name,'password':req.body.password}
Update
I tried out:
var data = [];
const user={'name':"Deshan",'password':"password"}
data.push(user);
console.log(data);
And the result was as follow:
[ { name: 'Deshan', password: 'password' } ]
So it maybe a problem with the request data.
I'm trying to update multiple collections in my Firestore and RTDB by triggering Google cloud function through an HTTP request, and I've done some several times of testing, but the batch commit works from time to time. I've also tried running test excluding RTDB update from the code, but nothing changes much.
If something goes wrong, I get the following error message with status code 500.
Error: Cannot modify a WriteBatch that has been committed.
Here's the example code:
Server-side code
'use strict';
module.exports = ({ admin, cors, express, functions }) => {
const app = express();
const fireStore = admin.firestore();
const rtdb = admin.database();
const apps = fireStore.collection('apps');
const users = fireStore.collection('users');
const batch = admin.firestore().batch();
app.use(cors({ origin: true }));
...
app.post('/', (req, res) => {
const uid = req.user.user_id;
const data = req.body;
const appsRef = apps.doc(uid);
const usersRef = users.doc(uid);
const activityState = {
currentActiveStatus: data.activityState.currentActiveStatus,
usingApp: data.activityState.usingApp
};
const appState = {
emailVerified: data.user.emailVerified
};
const userState = {
displayName: data.user.displayName,
photoURL: data.user.photoURL,
currentActiveStatus: data.user.currentActiveStatus,
lastLoginAt: admin.firestore.FieldValue.serverTimestamp()
};
batch.update(appsRef, appState);
batch.update(usersRef, userState);
return batch.commit().then(() => {
console.log('Batch commit finished!');
return admin.database().ref(`status/${uid}`).update(activityState).then(() => {
res.status(201).send({ message: 'Successfully Initialize Default State' });
});
}).catch(err => console.log('Err:', err));
});
return functions.https.onRequest(app);
};
Client-side code
const data = {
activityState: {
currentActiveStatus: "online",
usingApp: "true"
},
user: {
displayName: this.displayName,
photoURL: this.photoURL,
currentActiveStatus: "online",
emailVerified: "true"
}
};
this.userService.updateUserProfile(this.displayName, this.photoURL).then((accessToken) => {
const url = 'https://us-central1/dbname/cloudfunctions.net/functionname';
this.http.post(url, JSON.stringify(data), {
headers: {'Authorization': accessToken, 'Content-Type': 'application/json; charset=utf-8'}
}).subscribe((res) => {
// Worked well
}, (err) => {
// Went wrong
});
});
Error message in details
Error: Cannot modify a WriteBatch that has been committed.
at WriteBatch.verifyNotCommitted (/user_code/node_modules/firebase-admin/node_modules/#google-cloud/firestore/src/write-batch.js:148:13)
at WriteBatch.update (/user_code/node_modules/firebase-admin/node_modules/#google-cloud/firestore/src/write-batch.js:333:10)
at app.post (/user_code/exports/auth/user/startapp/initDefaultState.f.js:54:11)
at Layer.handle [as handle_request] (/user_code/node_modules/express/lib/router/layer.js:95:5)
at next (/user_code/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/user_code/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/user_code/node_modules/express/lib/router/layer.js:95:5)
at /user_code/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/user_code/node_modules/express/lib/router/index.js:335:12)
at next (/user_code/node_modules/express/lib/router/index.js:275:10)
Perhaps I'm missing something out in my code?
I resolved my problem. It was a silly mistake that I've made.
I had to declare batch inside app.post().
app.post('/', (req, res) => {
const batch = admin.firestore().batch();
});
Instead
module.exports = ({ admin, cors, express, functions }) => {
const app = express();
const fireStore = admin.firestore();
const rtdb = admin.database();
const apps = fireStore.collection('apps');
const users = fireStore.collection('users');
const batch = admin.firestore().batch();
};
I'm using Express and Sequelize to make a basic user authentication based upon this tutorial
When I want to sign a token to a user I get an error telling me I'm trying to JSON.stringify() a circular reference which cannot be done. Therefor an error is thrown and I can't assign the token to the user.
OR I am doing something wrong when finding my user in the database which makes a circular reference OR I just need to find a solution to break the circular reference I suppose. Anyone who could explain me which of the two it is?
The full error is:
TypeError: Converting circular structure to JSON
at Object.stringify (native)
at toString (/Users/Desktop/express-jwt/node_modules/jws/lib/tostring.js:9:15)
at jwsSecuredInput (/Users/Desktop/express-jwt/node_modules/jws/lib/sign-stream.js:12:34)
at Object.jwsSign [as sign] (/Users/Desktop/express-jwt/node_modules/jws/lib/sign-stream.js:22:22)
at Object.module.exports [as sign] (/Users/Desktop/express-jwt/node_modules/jsonwebtoken/sign.js:144:16)
at Model.User.findOne.then.user (/Users/Desktop/express-jwt/server/index.js:69:27)
at Model.tryCatcher (/Users/Desktop/express-jwt/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/Users/Desktop/express-jwt/node_modules/bluebird/js/release/promise.js:510:31)
at Promise._settlePromise (/Users/Desktop/express-jwt/node_modules/bluebird/js/release/promise.js:567:18)
at Promise._settlePromise0 (/Users/Desktop/express-jwt/node_modules/bluebird/js/release/promise.js:612:10)
at Promise._settlePromises (/Users/Desktop/express-jwt/node_modules/bluebird/js/release/promise.js:691:18)
at Async._drainQueue (/Users/Desktop/express-jwt/node_modules/bluebird/js/release/async.js:138:16)
at Async._drainQueues (/Users/Desktop/express-jwt/node_modules/bluebird/js/release/async.js:148:10)
at Immediate.Async.drainQueues (/Users/Desktop/express-jwt/node_modules/bluebird/js/release/async.js:17:14)
at runCallback (timers.js:574:20)
at tryOnImmediate (timers.js:554:5)
My index for the server is:
const express = require(`express`);
const app = express();
const bodyParser = require(`body-parser`);
const morgan = require('morgan');
const jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
const config = require('./config'); // get our config file
const db = require(`./models`);
const User = global.db.User;
const port = process.env.PORT || 8080;
db.sequelize.sync().then(() => {
console.log(`Express server listening on port ${port}`);
});
app.set('superSecret', config.secret);
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.use(morgan('dev'));
app.get('/', (req, res) => {
res.send('Hello! The API is at http://localhost:' + port + '/api');
});
app.listen(port);
console.log('Magic happens at http://localhost:' + port);
app.get('/setup', (req, res) => {
db.sequelize.sync().then(() => {
return User.create({
username: 'Kevin frafster',
password: 'password',
admin: true
})
.then(addedUser => {
console.log(addedUser.get({
plain: true
}));
})
.catch(err => {
res.json(err);
});
});
});
// API ROUTES -------------------
// get an instance of the router for api routes
const apiRoutes = express.Router();
apiRoutes.post('/authenticate', (req,res) => {
User.findOne({
where: {username: req.body.username}
}).then(user => {
if (!user) {
res.json({ success: false, message: 'Authentication failed. User not found.'});
}else{
// console.log(user);
if (user.password != req.body.password) {
res.json({ success: false, message: 'Authentication failed. Wrong password.' })
}else{
const token = jwt.sign(user, app.get('superSecret'), {
expiresIn: 60*60*24
});
res.json({
succes: true,
message: 'Enjoy your token!',
token
});
}
}
}).catch(err => {
res.status(500).json(err);
})
});
// TODO: route to authenticate a user (POST http://localhost:8080/api/authenticate)
// TODO: route middleware to verify a token
// route to show a random message (GET http://localhost:8080/api/)
apiRoutes.get('/', (req, res) => {
res.json({ message: 'Welcome to the coolest API on earth!' });
});
// route to return all users (GET http://localhost:8080/api/users)
apiRoutes.get('/users', (req, res) => {
User.findAll({})
.then(users => {
res.json(users);
})
.catch(err => {
res.json(err);
});
});
// apply the routes to our application with the prefix /api
app.use('/api', apiRoutes);
Well, the answer was totally peanuts.
1) Make new object and assign payload to it
const payload = {username: user.username, password: user.password};
2) Use the new object to assign token to
const token = jwt.sign(payload, app.get('superSecret'), {
expiresIn: 60*60*24
});