I'm trying to test using NodeJS as a backend api for a Polymer front end. On the Polymer side, I have this iron-ajax element:
<iron-ajax
id='test-req'
url='http://localhost:9090/backend-test'
handle-as='text'
on-response='testRsp'
body='{"data":"stuff"}'>
</iron-ajax>
The testRsp handler simply logs the response text to the console. On the backend, this is my route:
app.get('/backend-test', function(req, res){
res.send(req.body)
console.log(req.body)
}
As you can see, all it does is respond with the raw request, and log the request on the backend. Both sides as expected have the same result, but unfortunately the result is just {}.
Now, I also tried sending the json in via the params attribute instead of the body attribute of the iron-ajax element, and on the backend I used the deprecated req.param() function like so: req.param('data'), and that correctly prints out stuff on both the browser and the backend. However, since it is deprecated, I'm trying to avoid that method.
Any suggestions?
Edit: I figured this extra piece of info would be helpful. When I log req.originalUrl on the backend when passing the json in 'params', I get /backend-test?data=stuff. When passing in 'body', it's just /backend-test.
I also want to note that I have tried variations of the bodyParser middleware as well:
->app.use(bodyParser.json()) (outcome as noted above)
->app.use(bodyParser.text()) (same)
->not using bodyParser at all (prints undefined as expected based on the express docs)
->app.use(bodyParser.text()); app.use(bodyParser.urlencoded({ extended: true })); (same output as json() and text(); taken from the req.body docs).
Edit2 Thanks AP. I have been putting the use statements before any route definitions, like so:
// Create Express object, enable CORS
var app = express()
app.use(bodyParser.json())
app.use(cors())
// Route definitions
app.post('/backend_test', function(req, res){
res.json(req.body)
console.log(req.body)
})
app.listen(9090, function() {
console.log('App started, listening on port 9090')
})
I also updated my iron-ajax element to explicitly make a post rather than get, and set content type as json, but no dice. I'm still getting only {} out the other side:
<iron-ajax
id='test-req'
url='http://localhost:9090/backend_test'
content-type="json"
method="post"
handle-as='json'
on-response='testRsp'
body='{"data":"stuff"}'>
</iron-ajax>
Edit3 I found the mistake with my update, content-type needed to be application/json, not just json. That got it working finally. Thanks!
Your middleware should be initialized before your routes, and should somewhat resemble this:
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
In terms of the Polymer Implementation, if you are sending JSON data, according to the docs your element should also contain:
<iron-ajax content-type='json'>
There is also a demo-repository that show's an example MEAN stack server running polymer as it's front-end. Which I believe ties into your question as well?
PS. Youtube-Black is a more comprehensive example.
Edit:
I just realized you're missing the method attribute on your Polymer element. Without that, you are sending a GET request! Make sure to use your element like so, in addition to your other props:
<iron-ajax content-type='json' method='post'>
Related
I'm trying to get data from a post request using express. But when I use Postman to create the resquest, the req.body is empty (console.log shows 'req {}')
I tried a couple of things and read similar questions in StackOverflow but I couldn't solve my issue.
Here are two screens of my Postman request using form-data and raw :
postman request
postman form
For the second, I also tried with the default content-type before adding application/json
Thanks for your help !
// File : router.js
import express from 'express'
const router = express.Router()
// I tried some router.get routes here and it works with no problem...
router.post('/myurl', (req, res) => {
console.log('req', req.body)
})
export default router
// File : app.js
import express from 'express';
import router from './router.js';
const app = express();
const port = 3000;
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use('/', router)
app.listen(port, () => {
console.log(`App listening at http://localhost:${port}`);
}
);
You need three elements of the request and server side code to match.
The Content-Type request header must specific the format you are sending the data in
The request body must be encoded to match that header (and be valid)
The server needs body parsing middleware that supports that format.
Your first screenshot shows you are POSTing raw data which is invalid JSON. It does not show what Content-Type request header you are including.
You need to make the JSON valid and ensure that you have Content-Type: application/json in the request headers.
Your second screenshot shows that you are posting multipart/form-data, but you only have middleware that parses application/json and application/x-www-form-urlencoded data.
Either change the format you are POSTing in, or add suitable middleware.
Note also that the Content-Type of the individual parts is wrong. example is not valid JSON (100 is valid JSON but you probably don't want it to be treated as such).
I'm just trying to pass the simplest data possible (at the moment, for test purposes) from client to server with a POST request, but I keep getting empty or undefined logs on req.body.
Server:
//jshint esversion:6
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const app = express();
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static("public"));
mongoose.connect("mongodb://localhost:27017/sandbox", {useNewUrlParser: true});
app.get("/", function(req, res){
res.render("home", {});
})
app.post("/filter", function(req, res){
console.log(req.body);
res.redirect("/");
})
app.listen(3000, function() {
console.log("Server started on port 3000");
});
Client (version 1):
var yourdata = { "name": "The pertinent data"};
console.log(document.body)
$.ajax({
url : "/filter",
type: "POST",
dataType:'text',
data : yourdata,
contentType: "application/json",
});
Client (version 2):
var payload = {data: "The pertinent data"};
var req = new XMLHttpRequest();
req.open('POST', '/filter' , true);
req.send(JSON.stringify(payload))
I added both attempts at a code client-side, but I'm happy with whichever method works. Ideally I'll eventually tap into the payload or data with req.body.payload or something, but at the moment that's just giving me an undefined.
I've looked into quite a few similar posts and usually they were missing the "app.use(bodyParser.urlencoded({extended: true}));" or "app.use(bodyParser.json());" I've tried adding and removing those, changing from true to false, still empty.
The console.log(document.body) on the client script does work, giving me the expected body on the browser console, and the server route is working too, eventually redirecting to home.
I can't see how the issue is something I'm doing wrong on the client side, but oddly enough, if I create a form, with an action to that route, and submit, it seems to send the req.body normally. E.g.:
<form class="form" action="/filter" method="post">
<input name="newName" placeholder="Name">
<button type="submit">Submit</button>
</form>
That does indeed log a JSON object e.g.: { newName: 'John'}
In case it might be relevant, the HTML is the simplest one possible, almost empty, only really doing the pertinent links.
Thanks all in advance!
You need three things:
A request body encoded in some data format
A content-type request header which says which data format you are using
Body parsing middleware that can process that data format
When you submit a form, with no enctype attribute, it will submit the data in URL encoded format with the right content type. This matches the body parsing middleware you have (bodyParser.urlencoded({extended: true})).
1, 2, and 3 are all good.
Note that it does not create a JSON object. The client produces URL encoded data. The server parses that into a JavaScript object. There is no JSON.
Client (version 1):
Here you are passing an object to jQuery so it will URL encode the data in it and would normally set the correct content type.
It is failing because you have contentType: "application/json",.
Since you are falsely claiming that you are sending JSON, bodyParser.urlencoded ignores it.
If you had a JSON body parser in place, it would error because the data is not JSON.
1 and 3 are good, but 2 is a lie.
Remove the contentType property.
Client (version 2):
Now you are JSON encoding the data, but you aren't setting the content type request header, and you don't have body parsing middleware that can handle JSON.
3 is bad, and either 1 or 2 is too.
For the server-side part of your application, you need something that moves the body of the request out of the request string itself to a clear, easy-to-read, and use variable. The express json() method (middleware) does that exactly.
Use the express JSON parser middleware as follows:
app.use(express.json())
Code:
const express = require("express");
// const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const app = express();
app.use(express.json()); // 👈 here
// ... the rest of your code
Just few notes about the middleware you're using
app.use(bodyParser.urlencoded({extended: true}));
We usually use this middleware to parse the HTML forms data, in other words, it's just like the express middleware express.json(), but the difference here is that it parses the requests which have the content type of HTML forms, while the express.json() converts the ones which have the content-type of application/json.
If you're using express v +4, you don't need the bodyParser package, express has the .urlencoded() and the .json() methods built into the express package itself, you can use them just as express.json() and express.urlencoded().
Tip, you can have both middlewares, the JSON parser, and the HTML form content type parser, when the server receives a content-type JSON, the express.json() middleware will parse the request body, and if the server receives an HTML form content-type the urlencoded middleware will fire:
code example:
const express = require("express");
// const bodyParser = require("body-parser"); ❌ not needed
const mongoose = require("mongoose");
const app = express();
app.use(express.json()); // 👈 here
app.use(express.urlencoded({ extended: true })) // 👈 here
// ... the rest of your code
So I am trying to retrieve images from my expressjs API and I cannot seem to actually retrieve anything, not locally or even remotely.
Here is the written code below :)
app.use(express.static(path.join(__dirname,'/public/')));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.get('/getImage/:folder/:imageName', function (req, res) {
console.log(path.join(__dirname,'/',req.params.folder,'/',req.params.imageName));
res.sendFile(path.join(__dirname,'/',req.params.folder,'/',req.params.imageName));
res.end();
});
Have I written something wrong? Is there something I am missing?
here is the request http://localhost:3000/getImage/public/da4b9237bacccdf19c0760cab7aec4a8359010b0678f63452c5c1d428cd376dd82c55aa33a34e600.jpg
UPDATE
So it works when I remove res.end(), I'm assuming this is being executed before the image has fully been received?
I am attempting to build a single page app using Express.js. On my index.html page, I have a basic form, which upon submit will make a request to an API, retrieve the data, parse it, and then I want to render the parsed data as a list of links. Right now I am able to render the index page, and I can make the submission call to the API from the form that I added to the page. What I am confused about is how to properly redirect the data I get from the API call and then render it on the same page. I've built simple apps using Express before where there were multiple views, but never a single page app. For those apps, I know that for the response you could call something like res.render('name of view to render', data), but that is not working in this case. I've tried to find some solutions through this site and via the Express docs, but I have not seen anything that didn't also include using another framework like Angular. For the purposes of this app, I need to not include any additional frameworks, and I am a bit lost.
My function for calling the API looks like this right now. When it is called, I am directed to a page that just has the json displayed
app.use(express.static(path.join(__dirname, '/public')));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use('/', express.static(path.join(__dirname, 'public')));
app.get('/search', function(req, res) {
var title = req.query.movieTitle;
var url = 'http://www.omdbapi.com/?s=' + title;
request(url, function (err, response, body) {
var results = JSON.parse(body);
var movieTitles = results.Search;
console.log(movieTitles);
res.send(movieTitles);
});
});
The basic thing you have to do is:
define routes which your back-end app has to respond with the spa
send your "skeleton" file to the response on that routes
Example code:
const handler = (req, res) => res.send(path.join(__dirname, "path/to/your/index.html"))
const routes = ["/", "/hello", "/world"]
routes.forEach( route => app.get(route, handler) )
This should get you started
I am testing the post method to create a todo item as follows. I am using postman in chrome to simulate the post method call. However, it does not work and gives me the below error. I suspect something is wrong with the way body-parser library is working. What am I doing wrong here?
1 SyntaxError: Unexpected token b
2: at parse (/Users/zack/mydrive/proj/express-demo/node_modules/body-parser/lib/types/json.js:83:15)
3: at /Users/zack/mydrive/proj/express-demo/node_modules/body-parser/lib/read.js:116:18
4: at invokeCallback (/Users/zack/mydrive/proj/express-demo/node_modules/body-parser/node_modules/raw-body/index.js:262:16)
5: at done (/Users/zack/mydrive/proj/express-demo/node_modules/body-parser/node_modules/raw-body/index.js:251:7)
6: at IncomingMessage.onEnd (/Users/zack/mydrive/proj/express-demo/node_modules/body-parser/node_modules/raw-body/index.js:308:7)
7 at IncomingMessage.emit (events.js:104:17)
8 at _stream_readable.js:908:16
Code:
var express = require('express');
var app = express();
var handlebars = require('express-handlebars');
var bodyParser = require('body-parser');
//MIDDLEWARE
app.engine('handlebars', handlebars({defaultLayout: 'main'}));
app.set('view engine', 'handlebars');
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}));
// TODOS
var todos = [
{ body: "take out the trash",completed: false},
{ body: "Do the laundry",completed:true},
{ body: "Make a screencast",completed:false}
]
app.post('/todos', function (req, res){
console.log("todo:", req.body);
var todo = req.body;
console.log("todo:"+todo);
todos.push(todo);
res.status(200).json(todo);
res.send('OK')
})
Further I observe that the problem is because of this line.
app.use(bodyParser.json());
Are you sure you are sending the request as JSON? Make sure you've selected it in Postman - https://imgur.com/j0M7TEX.
If that didn't work, you can try the following -
...
app.post('/todos', function (req, res){
console.log("todo:", req.body);
var todo = req.body;
console.log("todo:"+todo);
todos.push(todo);
// Only try to send a single response.
res.json(todo);
});
It looks like you were trying to send two responses, one containing JSON, and another with text/plain ('Ok').
http://expressjs.com/fr/api.html#res.json
It seems like your program is trying to interpret the post data as json data - and generating an error when it trys to parse the request data which is probably url-encoded.
Perhaps consider sending your data in json format. You will have to set the request headers to indicate the datatype is json. See this answer for an example:
Angular JS POST request not sending JSON data
I just created a new session in postman and it started working. I am not sure if there is a caching effect but it works now. I did not make any code change at all. Posting this as the solution now.
Just don't put quotes on your JSON value.
Not "okay2" but just okay2.
I think that postman adds the quotes himself if needed and in this case creates ""okay2"" which isn't valid JSON.
By the way you can test by clicking on the "row" radio button and write your own JSON.