Cannot GET api route (node.js, express) - javascript

JS noob, I'm trying to follow a course on node.js API creation. I'm doing everything by the book instruction by instruction. This is the server.js file, as specified in the course:
const http = require('http');
const app = require('./app');
const normalizePort = val => {
const port = parseInt(val, 10);
if (isNaN(port)) {
return val;
}
if (port >= 0) {
return port;
}
return false;
};
const port = normalizePort(process.env.PORT || 3000);
app.set('port', port);
const errorHandler = error => {
if (error.syscall !== 'listen') {
throw error;
}
const address = server.address();
const bind = typeof address === 'string' ? 'pipe ' + address : 'port: ' + port;
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges.');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use.');
process.exit(1);
break;
default:
throw error;
}
};
const server = http.createServer(app);
server.on('error', errorHandler);
server.on('listening', () => {
const address = server.address();
const bind = typeof address === 'string' ? 'pipe ' + address : 'port ' + port;
console.log('Listening on ' + bind);
});
server.listen(port);
I run this server from the console and cUrl and postman requests give me a 404 (Cannot GET) when I send get requests to http://localhost:3000/api/stuff, the route I specified in app.js:
const express = require('express');
const app = express();
app.use('http://localhost:3000/api/stuff', (req, res, next) => {
const stuff = [
{
message: "this is a JSON"
},
{
message: "this is also a JSON"
}
];
res.status(200).json(stuff);
});
My package.json seems alright:
{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"express": "^4.17.1",
"node": "^15.2.1"
}
}
In app.js I tried app.get instead of app.use, and generating the JSON directly into the res.status(200).json().
I really suspect the issue is in the server.js, I tried messing around with it to no avail (feeding normalizePort() a string instead of an integer, eliminating process.env.port, simplifying the switch where it checks if port 3000 is free).
I have of course checked for similar issues in SO, but nothing seemed to match my specific problem.
node --version
v13.11.0 (the course is based on an old version too)

A URL consists of multiple parts:
scheme
authority (including host and port)
path
query
fragment
Parsing http://localhost:3000/api/stuff results in:
scheme: http
authority
host: localhost
port: 3000
path: /api/stuff
app.use does not expect a complete URL. It just expects the path part: app.use('/api/stuff',
You can pass more than just a simple string. Examples can be found in the documentation.

Related

Unable to get graphql response from server that's running on local

I have a mongodb server setup which on running the below command starts on port 3000
npm run start
I also a graphql server which on running the below command starts at port 4000
npm run start-graphql
the scripts of my package.json is as below
"scripts": {
"start": "nodemon server.js",
"start-graphql": "nodemon graphqlserver.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
server.js
require('dotenv').config();
const express = require('express');
const app = express();
const mongoose = require('mongoose');
mongoose.connect(process.env.DATABASE_URL);
const db = mongoose.connection;
db.on('error', (err) => console.log(err));
db.once('open', () => {
console.log("Backend Database connected");
});
app.use(express.json({ limit: '2mb'}));
const photosRouter = require('./routes/photos');
app.use('/images', photosRouter)
app.listen(3000, () => {
console.log('Server started at port 3000');
})
graphqlserver.js
const express = require('express');
const path = require('path');
const express_graphql = require('express-graphql').graphqlHTTP;
const { loadSchemaSync } = require('#graphql-tools/load');
const { GraphQLFileLoader } = require('#graphql-tools/graphql-file-loader');
const { addResolversToSchema } = require('#graphql-tools/schema');
const getResolvers = require('./graphql/resolvers');
// GraphQL schema
const combinedSchema = loadSchemaSync(
path.join(__dirname, './graphql/schemas/*.graphql'),
{
loaders: [new GraphQLFileLoader()],
}
);
const schema = addResolversToSchema({
schema: combinedSchema,
resolvers: Object.assign({}, getResolvers())
});
// Create an express server and a GraphQL endpoint
const app = express();
app.use('/graphql', express_graphql({
schema: schema,
graphiql: true
}));
app.listen(4000, () => console.log('Express GraphQL Server Now Running On localhost:4000/graphql'));
when I call the rest api's normally either through postman or curl it returns the response as expected.
For eg: http://localhost:3000/images returns me an array of objects
But When I want to call (using axios) the same via the graphql server (which is running on port 4000 ),
I get response as null.
I have no clue why this is happening.
Please check the below screenshot for your reference
Note: For better clarity please check the codebase link
https://github.com/yaswankar/G-photos-backend
Any help would be appreciated.
Thanks in advance
Request: Please help by giving an upvote so that it could better reach to those who could help.
Edit:
New Error screenshot
I was able to resolve the main issue by adding the query block inside photos resolver
Query: {
photo: photosContext,
},
The other error was resolved by processing the response instead of sending the raw data to the hyper class
async function getActivePhotos(parent, args, req) {
try {
const activePhotos = await photoService.getActivePhotos(req).then(resp => resp.data.map(item => item)); // Process and mapping data
return activePhotos;
} catch (error) {
// logger.error(__filename + ': Failed to get response for getActivePhotos, err=' + JSON.stringify(error));
return new GraphQLError(JSON.stringify(error));
}
}

How to save data using mongodb query in middleware in nodejs

I want to save data using mongodb query using middleware in node.js. please provide some code with example?
Try this. It works both for insert and update (upsert).
// app.js
const express = require('express');
const bodyParser = require('body-parser');
const MongoClient = require('mongodb').MongoClient;
const mongodb_url = process.env.MONGO_URL || "mongodb://localhost:27017";
const mongodb_dbname = 'test_db';
const port = process.env.PORT || 3006;
const app = express();
app.use(express.json())
app.use(bodyParser.urlencoded({ extended: true}));
app.use(bodyParser.json({ extended: true}));
app.post('/api/post/:identifier', (req, res) => {
const identifier = req.params.identifier;
const content = req.body.payload;
MongoClient.connect(`${mongodb_url}`, { useNewUrlParser: true }, (err, client) => {
if (!err) {
let db = client.db(mongodb_dbname);
db.collection('posts')
.updateOne(
{ identifier: identifier },
{ $set: { content: content } },
{ upsert: true }
)
.then((output) => {
res.status(202).send({ message: "Sent"});
})
.catch((error) => {
res.status(500).send({
error_code: 500,
error_message: `Error while updating data - ${error}`
});
});
client.close();
} else {
res.status(500).send({
error_code: 500,
error_message: 'Error while connecting to database'
});
}
});
});
app.listen(port, () => {
console.log(`API bootstrapped on port ${port}...`);
});
Use the following package.json file:
{
"name": "mongo-upsert",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.17.1",
"mongodb": "^3.6.0"
}
}
When invoked as localhost:3006/api/post/my-post with a request body containing:
{
"payload": "Hello world"
}
This code is going to upsert a MongoDB document like:
{
"_id" : ObjectId("5f3d272cbd52c9c109ea9baa"),
"identifier" : "my-post",
"content" : "Hello world"
}
Prerequisites for the above code to work:
To have a working installation of mongodb
To have a database named test_db
To have a collection named posts
In this example, we are adding a post content, identified by an identifier, which for the sake of simplicity I have added as a path param in the POST definition.
Install dependencies using npm install.
Run the app using npm start.
Good luck.
Look into W3Schools NodeJS MongoDB.
I don't have enough rep to comment so here's an answer.

Why Node.js can't process the request from Vue.js?

I have strange error and don't know why Node.js don't see url address and always return me 404.
In Vue.js application I make post request with axios package when user click the button. As you can see from the code I send name of the file in the body of request and user token in the header. I check and both values are not empty.
getFile (fileName) {
axios.post('/csv', {file_name: fileName}, {headers: {'Authorization': this.token}}).then(response => {
console.log(response)
this.showAlert('File successfully downloaded.', 'is-success', 'is-top')
}).catch((error) => {
console.log(error)
this.showAlert('An error occurred while downloading the file.', 'is-danger', 'is-bottom')
})
}
ERROR:
Error: Request failed with status code 404
at FtD3.t.exports (createError.js:16)
at t.exports (settle.js:18)
at XMLHttpRequest.f.(:3010/anonymous function) (http://localhost:3010/static/js/vendor.1dc24385e2ad03071ff8.js:1312:88758)
All requests from browser goes to HTTP server in Node.js (Express.js). In my case csv.js file should process the request. I don't understand in what part of the project problem. By the way other urls works correctly.
server/bin/www.js:
/**
* Module dependencies.
*/
const app = require('../../app')
const debug = require('debug')('slot:http-server')
const http = require('http')
/**
* Get port from environment and store in Express.js.
*/
let port = normalizePort(process.env.PORT || '3010')
app.set('port', port)
/**
* Create HTTP server.
*/
const server = http.createServer(app)
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port)
server.on('error', onError)
server.on('listening', onListening)
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort (val) {
const port = parseInt(val, 10)
if (isNaN(port)) {
return val
}
if (port >= 0) {
return port
}
return false
}
/**
* Event listener for HTTP server "error" event.
*/
function onError (error) {
if (error.syscall !== 'listen') {
throw error
}
const bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges')
process.exit(1)
break
case 'EADDRINUSE':
console.error(bind + ' is already in use')
process.exit(1)
break
default:
throw error
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening () {
const address = server.address()
const bind = typeof address === 'string' ? 'pipe ' + address : 'port ' + address.port
debug('Listening on ' + bind)
}
app.js:
const express = require('express');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const cors = require('cors');
const path = require('path');
const locationsRouter = require('./server/routes/locations');
const csvRouter = require('./server/routes/csv');
const app = express();
app.use(cors());
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'dist')));
app.use('/api/locations', locationsRouter);
app.use('/csv', csvRouter);
module.exports = app;
server/routes/csv.js:
const express = require('express')
const router = express.Router()
const fs = require('fs')
const path = require('path')
let Client = require('ssh2-sftp-client')
let sftp = new Client()
const config = require('../config')
router.post('/', (req, res) => {
// Set the variable with the name of the file.
const fileName = req.body.file_name
// Path to file in remote SFTP server.
const remotePath = '/reports/' + fileName
// Local directory where the downloaded file will be placed
const localePath = path.join(process.env.HOME || process.env.USERPROFILE, 'downloads/' + fileName)
// Connect to remote SFTP server.
sftp.connect(config.sftpServer, 'on').then(() => {
// Download file from remote SFTP server to local machine of the user.
sftp.fastGet(remotePath, localePath, {}).then(() => {
res.setHeader('Content-disposition', 'attachment; filename=' + fileName)
res.sendFile(localePath)
fs.unlink(localePath)
}).catch((error) => {
console.log(error)
})
}).catch((error) => {
console.log(error)
})
})
module.exports = router
What can you guys advice?
In vue, you are doing a post request to /csv, but in your app.js you are defining the /csv route as GET, that is your problem :D
UPDATE
If you want this to work with the animation download like chrome
Take a look at this link
https://gist.github.com/javilobo8/097c30a233786be52070986d8cdb1743

Heroku - specific route works locally but not on production

I have a node project which was deployed to an Heroku app.
The deploy was successful and i can open the app , but there is one route to which i'm getting a "Cannot GET" error (404) while other routes on the same page are working as expected.
Locally everything is working as expected and when i run heroku local in cmd i can see the response coming back from that function but i can't say the same for trying it from heroku app link.
server.js
'use strict';
var http = require ('http');
var url = require('url') ;
var express= require('express');
var app= express();
var port = process.env.PORT || 3000;
var mongoose = require ('mongoose');
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
mongoose.connect (db_details);
var conn=mongoose.connection;
var trip = require ('./Schemas/trip');
var user = require ('./Schemas/user');
app.all('/*', function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type,accept,access_token,X-Requested-With');
next();
});
conn.on('error', function(err) {
console.log('connection error: ' + err);
process.exit(1);
});
conn.once('open',function() {
console.log('connected successfuly to the remote DB');
app.use(require('./Routes')); //API routings
app.listen(port);
console.log("listening on port "+port+" and waiting for WS requests");
});
Routes/api/trip.js
'use strict'
var router = require('express').Router();
var mongoose = require('mongoose');
var trip = require ('../../Schemas/trip');
var user = require ('../../Schemas/user');
var Gmap = require ('../../TripBuilder/builder');
// get all trips
router.get('/getTrips', function(req, res) {
trip.find({},'trip_id Trip_Name Country City', function(err, trips) {
res.send(trips.reduce(function(userMap, item) {
userMap[item.id] = item;
return userMap;
}, {}));
});
});
// create new trip
router.post('/addNewTrip', function(req, res,next) {
let newTrip = new trip ({"Trip_Id":req.body.Trip_id,"Trip_Name":req.body.Trip_Name,"Trip_Date":req.body.Trip_Date,
"Trip_Owner":req.body.Trip_Owner,
"Country":req.body.Country,"City":req.body.City,"status":"Pending","Days":[],"Sites":[]});
return newTrip.save().then(function(){
return res.send("A Trip was created");
}).catch(next);
});
router.post('/addUserToTrip', async function(req, res,next) {
user.find({'email':req.body.email},'first_name last_name email', function(err,obj) {console.log("print " +obj); });
let secUser = {"Trip_Id":req.body.Trip_id};
});
router.post('/createRoute', function(req, res,next) {
var map=new Gmap();
var origins = ['Big Ben, London, UK','Bridge St, Westminster, London SW1A 2JR, UK','Palace of Westminster, Westminster, London SW1A 0PW, UK','Whitehall, Westminster, London SW1A 2ET, UK'];
var destinations =['Big Ben, London, UK','Bridge St, Westminster, London SW1A 2JR, UK','Palace of Westminster, Westminster, London SW1A 0PW, UK','Whitehall, Westminster, London SW1A 2ET, UK'];
map.calcRoute(origins,destinations).then(function(result){
map.longestroute=result; //save start and end
origins.splice(origins.indexOf( map.longestroute.origin), 1);
origins.splice(origins.indexOf( map.longestroute.destination), 1);
map.waypoints=origins;
map.setRoute(map.longestroute.origin,map.longestroute.destination,map.waypoints).then(function(route){
return res.send(route);
});
}).catch(next);
});
module.exports = router;
Calling https://APP-NAME.herokuapp.com/api/trip/createRoute returns "Cannot GET /api/trip/createRoute", while calling https://APP-NAME.herokuapp.com/api/trip/getTrips returns a response.
Heroku logs seems to record the request without any special exceptions but nothing is coming back.
I added "res.send("ok");" inside "createRoute" just to see at least that will be sent back but nothing.
Package.json
"name": "tripin",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"engines": {
"node": "9.8.0"
},
"author": "",
"license": "ISC",
"dependencies": {
"#google/maps": "^0.4.6",
"body-parser": "^1.18.2",
"express": "^4.16.2",
"http": "0.0.0",
"https": "^1.0.0",
"inspect-process": "^0.5.0",
"mongoose": "^5.0.9",
"node-dev": "^3.1.3",
"package.json": "^2.0.1",
"request": "^2.85.0"
}
}
Thanks
Edit:
router.post('/createRoute) and router.get('/createRoute) were attempted.
didn't work in either case
Your error messages is complaining about the GET, so it wants to GET "createRoute".
The create route path is a POST (so your HTTP request should be a POST).
You can check this by implementing a GET, and give a response your will reconize..
router.get('/createRoute', function(req, res) {
// .. your reconizalbe response here ..
res.send("Oops I did a GET, but wanted to POST");
}
and/or test with tool which can invoke the POST, like Postman or some other tool.
Ok , so as we all know programming rules state that the smaller the issue is, the harder it is to find it.
I managed to find out the solution:
I had my project duplicated in heroku - once in the root folder and once in its folder like it should be.
That threw off any routing i tried.
cleaning up heroku and re-deploy did the trick.
Thank you all for trying to help

Extracting POST parameters from request in Nodejs

I am trying to get parameters from a POST in the variable postData by using the request by -
( i used this because it was suggested here - How do I get the post request with express js? )
and here -
How to retrieve POST query parameters?
var express = require('express');
var app = express();
var fs = require('fs');
var json = require('json');
app.use(express.json()); // to support JSON-encoded bodies
app.use(express.urlencoded()); // to support URL-encoded bodies
app.post('/shrib/:file/:data',function(req,res){
var fileName = req.params.file;
var data = req.params.data;
req.on('data',function(data){ body+=data; } );
req.on('end' ,function(){
var postData = qs.parse(body);
var writeStream = fs.createWriteStream(fileName);
var postData = req.body.text;
if(postData)
console.log(postData);
else
console.log("failed miserably");
res.write(200);
res.end();
});
});
app.get('/shrib/:file',function(req,res){
var fileName = req.params.file;
if(fileName != ''){
var readStream = fs.createReadStream(fileName);
var content;
readStream.on('data',function(chunk){
content+=chunk.toString();
console.log(content);
});
readStream.on('end',function(){
res.writeHead(200,{"Content-Type":"text/html"});
res.write("<form id=\"submitForm\" method=\"POST\">");
res.write("<textarea id=\"text\"rows=50 cols=50 >");
console.log(content);
if(content)
res.write(content.toString());
res.write("</textarea>");
res.write("<input type=\"submit\" value=\"submit\" />");
res.write("</form>");
res.write("<script>");
res.write("var windowLocation = location.href;");
res.write("document.getElementById(\"submitForm\").action=windowLocation + \'/data\';");
res.write("</script>");
res.end();
});
}else{
res.writeHead(200);
res.write("invalid/empty path name");
}
});
app.listen(8080);
and got this error -
Error: Most middleware (like json) is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.
at Function.Object.defineProperty.get (/home/unknown/public_html/node/node_modules/express/lib/express.js:89:13)
I was using body parser before which i read in some solutions here and it gave me the same error middleware missing, i installed it globally then also got the same error and after that i read about json , so i installed it globally using
npm install -g json
did not work, then too. then i tried adding the dependancies -
{
"name": "express_shrib.js",
"version": "0.0.1",
"description": "Creating Shrib Using Express",
"main": "express_shrib.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/iamdeadman/nodejs.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/iamdeadman/nodejs/issues"
},
"homepage": "https://github.com/iamdeadman/nodejs",
"dependencies": {
"express": ">= 1.2.0",
"json": ">= 9.0.0"
}
}
and ran npm install
still the same error -
Error: Most middleware (like json) is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.
at Function.Object.defineProperty.get (/home/unknown/public_html/node/node_modules/express/lib/express.js:89:13)
Edit** - Code with the new body-parser module
var express = require('express');
var app = express();
var fs = require('fs');
var bodyParser = require('body-parser');
app.use(bodyParser());
app.post('/shrib/:file/:data',function(req,res){
var fileName = req.params.file;
var data = req.params.data;
req.on('data',function(data){ body+=data; } );
req.on('end' ,function(){
var postData = req.body;
var writeStream = fs.createWriteStream(fileName);
if(postData)
console.log(postData);
else{
console.log("failed miserably");
console.log(postData);
}
res.writeHead(200);
res.end();
});
});
app.get('/shrib/:file',function(req,res){
var fileName = req.params.file;
if(fileName != ''){
var readStream = fs.createReadStream(fileName);
var content;
readStream.on('data',function(chunk){
content+=chunk.toString();
console.log(content);
});
readStream.on('end',function(){
res.writeHead(200,{"Content-Type":"text/html"});
res.write("<form id=\"submitForm\" method=\"POST\">");
res.write("<textarea id=\"text\"rows=50 cols=50 >");
console.log(content);
if(content)
res.write(content.toString());
res.write("</textarea>");
res.write("<input type=\"submit\" value=\"submit\" />");
res.write("</form>");
res.write("<script>");
res.write("var windowLocation = location.href;");
res.write("document.getElementById(\"submitForm\").action=windowLocation + \'/data\';");
res.write("</script>");
res.end();
});
}else{
res.writeHead(200);
res.write("invalid/empty path name");
}
});
app.listen(8080);
and here i get
{}
in the console which means that the body object is empty for some reason.
With Express 4, the body parsing middleware (like other previously built-in middleware) was extracted out into the 'body-parser' module. However, this new module only handles JSON and urlencoded form submissions, not multipart.
If you need multipart support, you'd need to use something like connect-busboy or multer or connect-multiparty (connect-multiparty is essentially the old Express bodyParser middleware).
EDIT: Also, the name attribute is missing for the textarea input field. This is required, otherwise the field will not be sent with the form.
When using express 4 use body-parser middleware to get parameters.
Multipart has issue that it creates loads of temp files. So its better to avoid it whenever possible and use upload services directly.
app.use(function (req, res, next) {
var urlParser = require('url');
var url = urlParser.parse(req.url, true);
if (url.pathname == "/rest/file/upload") {
next();
} else {
var contentType = req.header("content-type");
if (contentType && contentType.indexOf("application/json") != -1) {
bodyParser.json({limit: 1024 * 1024 * 10})(req, res, next);
} else {
bodyParser.urlencoded({ extended: true, limit: 1024 * 1024 * 10})(req, res, next);
}
}
});
then just get your request parameter as :
console.log(req.param("parameter-name"));

Categories