I was exploring developing in Node.JS and found ExpressJS and RailwayJS (based on Express) which are frameworks for Node. The templating engine used Jade/EJS appears to be more for HTML. How might I generate JSON, eg. when I develop an API
Express and Railway both extend off the HTTP module in node and both provide a "response" object as the second argument of the route/middleware handler's callback. This argument's name is usually shortened to res to save a few keystrokes.
To easily send an object as a JSON message, Express exposes the following method:
res.json({ some: "object literal" });
Examples:
app.use(function (req, res, next) {
res.json({ some: "object literal" });
});
// -- OR -- //
app.get('/', function (req, res, next) {
res.json({ some: "object literal" });
});
Check out the docs at expressjs.com and the github source is well documented as well
You just create normal JavaScript objects, for example:
var x = {
test: 1,
embedded: {
attr1: 'attr',
attr2: false
}
};
and
JSON.stringify(x);
turns it into JSON string. Note that x may contain functions which will be omitted. Also JSON.stringify returns x.toJSON() if .toJSON() is available.
Related
I'm trying to escape form input for a simple demo express app, and I'm getting a result I don't understand.
When I execute this route:
/* Update a toy */
app.post('/toys/:id', [
body().escape()
], (req, res) => {
console.log("Update: ");
console.log(req.body);
toyController.update(req, res);
});
I get this output:
Update:
[object Object]
It looks to me as if the request body is getting destroyed.
If I remove the middleware,
/* Update a toy */
app.post('/toys/:id', (req, res) => {
console.log("Update: ");
console.log(req.body);
toyController.update(req, res);
});
I get the expected result:
Update:
{
toy: {
name: 'Playstation 4',
description: 'A gaming console',
manufacturer: 'Sony',
price: '400'
},
commit: 'Update Toy'
}
Update: If I call body('toy') instead of body(), I get the following result:
{ toy: '[object Object]', commit: 'Update Toy' }
So, it appears that the problem lies in the fact that that body is a nested object.
How can I apply the validation/sanitization to body.toy instead of all of body?
Is there a way that I can directly call the escape code an apply it to a specific string, instead of using the entire middleware setup?
You need to use body().escape() in a correct way. Please refer below an example.
const express = require('express');
const { body } = require('express-
validator');
const app = express();
app.use(express.json());
app.post('/comment', [
body('email')
.isEmail()
.normalizeEmail(),
body('text')
.not().isEmpty()
.trim()
.escape(),
body('notifyOnReply').toBoolean()
], (req, res) => {
// Handle the request somehow
});
Above example contains the right way to use express validator.In the example above, we are validating email and text fields, so we may take advantage of the same chain to apply some sanitization, like e-mail normalization (normalizeEmail) and trimming (trim)/HTML escaping (escape).
The notifyOnReply field isn't validated, but it can still make use of the same check function to convert it to a JavaScript boolean.
Sorry the indentation is not good, I am posting the answer from mobile.
Since you modified the question. You can use schema validation by express- validator.
https://express-validator.github.io/docs/schema-validation.html
I'm learning express from various tutorials and have an app working locally, but I'd like to better understand what each part of the code does.
I'm a bit stumped with the example in the app.route() section here:
https://expressjs.com/en/guide/routing.html
app.route('/book')
.get(function (req, res) {
res.send('Get a random book')
})
.post(function (req, res) {
res.send('Add a book')
})
.put(function (req, res) {
res.send('Update the book')
})
I can see that app is equal to express(), which is a top level function documented here.
And I can see that the .get(), post() and put() methods are chained to the route() method, which is documented here.
Where I get confused is that the docs state that the arguments for the .get(), post() and put() methods are in this format:
app.get(path, callback [, callback ...])
app.post(path, callback [, callback ...])
app.put(path, callback [, callback ...])
Why do the chained .get(), post() and put() methods not require the path argument, and instead have a singular function as an argument that returns values from the Request (aka req) and Response (aka res) object parameters?
I'm obviously missing something simple, so pointers to documentation that could help me better understand the distinctions between these methods when called straight from app, eg app.get(), and from route(), eg app.route('/book').get() would be much appreciated.
Edit: Basically, I'd like to know if there is documentation that defines the required argument format for the .get(), post() and put() methods when called from the route object returned from calling app.route("/book"), because it does not seem to be what is documented, ie path, callback [, callback ...].
app.route()
As per the docs, the app.route method:
Returns an instance of a single route, which you can then use to handle HTTP verbs with optional middleware. Use app.route() to avoid duplicate route names (and thus typo errors).
It means, app.route() takes only the path and returns the route object. Which will have all http verb methods to handle middlewares against one path, get, post, delete, post, put, patch etc.
Why?
To simply have routes which have same path but different HTTP requests. Like:
app.route('/books')
.get() // To get the list of objects
.post() // To save a new book.
Individual HTTP methods
On the other hand, express provides individual methods on app for handling HTTP requests. Like app.get(), app.post(), app.delete().
As per docs for post route: HTTP POST requests to the specified path with the specified callback functions.
Why?
For the cases where you don't have one path for multiple HTTP requests. Let's say:
app.delete('/books/:bookId/comments/:commentId', function(){});
The above route is a kind of single route and only used for deleting a specific comment on book.
I hope I was able to clear the difference.
Reference Link for the docs: https://expressjs.com/en/4x/api.html#router.route
Edit:
As no proper Docs are available listing methods provided by route object:
For more information adding github's link to the express router.
https://github.com/expressjs/express/blob/master/lib/router/route.js
Here see the below code of express's router which adds handler on all methods.
methods.forEach(function(method){
Route.prototype[method] = function(){
var handles = flatten(slice.call(arguments));
for (var i = 0; i < handles.length; i++) {
var handle = handles[i];
if (typeof handle !== 'function') {
var type = toString.call(handle);
var msg = 'Route.' + method + '() requires a callback function but got a ' + type
throw new Error(msg);
}
debug('%s %o', method, this.path)
var layer = Layer('/', {}, handle);
layer.method = method;
this.methods[method] = true;
this.stack.push(layer);
}
return this;
};
});
In this file at top, it has:
var methods = require('methods');
methods: https://github.com/jshttp/methods
Thus, the required parameters for the chained methods is unlimited functions as request handlers/middlewares.
The point of chained method is that they have same path.
So you can write this:
app.route('/book')
.get(function (req, res) {
res.send('Get a random book')
})
.post(function (req, res) {
res.send('Add a book')
})
.put(function (req, res) {
res.send('Update the book')
})
instead of
app.get('/book', function (req, res) {
res.send('Get a random book')
});
app.post('/book', function (req, res) {
res.send('Add a book')
});
app.put('/book', function (req, res) {
res.send('Update the book')
});
Which means that if you i.e. change the endpoint it is changed for all methods, you cannot write typo in one method...
I am writing a restful api in nodejs using expressjs as a framework. I have the following code
.get(function(request,response)
{
Production.find(function(err, prods) {
if (err)
response.send(400, {success:false, error: err});
response.send(200, prods);
console.log(response._headers);
});
});
Now I want to read the headers of the response before actually sending the response. I want this so that I could read the ETag value and hence check whether I should send the data again or not.
Any ideas please?
Thanks
req.stale might be what you want to use. Here are the docs for req.stale and req.fresh.
Both methods return a Boolean true or false which you can use in your logic.
app.get('/', (req, res, next) => {
if (req.stale) return res.sendStatus(304);
res.render('your/template'); // or .send() or whatever sauce you choose
});
Most of my handlers look as follows:
function(req, res) {
var data = ...;
res.render('my_view', data);
}
I know that If I want to return JSON I need to change res.render to res.json, as follows:
function(req, res) {
var data = ...;
res.json(data);
}
when debugging I often want to see the raw data (in JSON format that was computed by the handler). To do that, I (manually) go to the handler callback and change res.render('...', to res.json(.
I am wondering whether there is a way to tell express that if the URL meets a certain condition token (say, ends with .json, or, alternatively, has a ?format=json query param) then res.view will seamlessly delegate to res.json ?
If it is just for debugging purpose then you could make a middleware that would override render method to json.
I will not recommend to use this in production.
In your app.configure add this:
app.use(function(req, res, next) {
if (req.query.json !== undefined) {
res.render = function(name, data) {
res.json(data);
}
}
return next();
});
So what it does: if request has json in query, then it will override render method and will call json instead.
So test it with: http://example.com/test?json
My application has several layers: middleware, controllers, managers. Controllers interface is identical to middlewares one: (req, res, next).
So my question is: how can I test my controllers without starting the server and sending 'real' requests to localhost. What I want to do is to create request, response instances as nodejs does and then just call controllers method.
Something like this:
var req = new Request()
var res = new Response()
var next = function(err) {console.log('lala')}
controller.get_user(req, res, next)
Any advice is highly appreciated. Thanks!
P.S. the reason why I want to do this is that at the end I would like to test whether the response object contains correct variables for the jade views.
There's a semi decent implementation at node-mocks-http
Require it:
var mocks = require('node-mocks-http');
you can then compose req and response objects:
req = mocks.createRequest();
res = mocks.createResponse();
You can then test your controller directly:
var demoController = require('demoController');
demoController.login(req, res);
assert.equal(res.json, {})
caveat
There is at time of writing an issue in this implementation to do with the event emitter not being fired.
Since JavaScript is a dynamically typed language you can create mock objects and passing them to your controllers as follow:
var req = {};
var res = {};
var next = function(err) {console.log('lala')}
controller.get_user(req, res, next)
If your controller needs a particular piece of data or functionality from your request or response object you'll need to provide such data or functionality in your mocks. For example,
var req = {};
req.url = "http://google.com"; // fake the Url
var res = {};
res.write = function(chunk, encoding) {
// fake the write method
};
var next = function(err) {console.log('lala')}
controller.get_user(req, res, next)
I would try using dupertest for this. It's a node module I created for the very purpose of easy controller testing without having to spin up a new server.
It keeps the familiar syntax of node modules like request or supertest, but again, without the need to spin up a server.
It runs a lot like Hector suggested above, but integrates with a test framework like Jasmine to feel a little more seamless.
An example relating to your question may look like:
request(controller.get_user)
.params({id: user_id})
.expect(user, done);
Or the more explicit longhand version:
request(controller.get_user)
.params({id: user_id})
.end(function(response) {
expect(response).toEqual(user);
done();
});
Note: the examples assume user_id and user are defined somewhere, and that the controller grabs and returns a user based on id.
Edit: reading your response to an answer above, I will admit the downside currently is that this module does not integrate a more robust mock request or response object by default. dupertest makes it super easy to extend and add properties to both req and res, but by default they are pretty bare.
If you want to use the real req and res objects, you have to send real requests to the server. However this is much easier than you might think. There are a lot of examples at the express github repo. The following shows the tests for req.route
var express = require('../')
, request = require('./support/http');
describe('req', function(){
describe('.route', function(){
it('should be the executed Route', function(done){
var app = express();
app.get('/user/:id/edit', function(req, res){
// test your controllers with req,res here (like below)
req.route.method.should.equal('get');
req.route.path.should.equal('/user/:id/edit');
res.end();
});
request(app)
.get('/user/12/edit')
.expect(200, done);
})
})
})
A bit old post, but I would like to give my 2 cents. The approach you want to take depends on whether you are doing unit testing or integration testing. If you are going down the route of using supertest, that means you are running the actual implementation code and that means you are doing integration testing. If that's what you want to do this approach is fine.
But if you are doing unit testing, you would mock req and res objects (and any other dependencies involved). In the below code (non-relevant code removed for brevity), I am mocking res and giving just a mock implementation of json method, as that's the only method I need for my tests.
// SUT
kids.index = function (req, res) {
if (!req.user || !req.user._id) {
res.json({
err: "Invalid request."
});
} else {
// non-relevent code
}
};
// Unit test
var req, res, err, sentData;
describe('index', function () {
beforeEach(function () {
res = {
json: function (resp) {
err = resp.err;
sentData = resp.kids;
}
};
});
it("should return error if no user passed in request", function () {
req = {};
kidsController.index(req, res);
expect(err).to.equal("Invalid request.");
});
/// More tests....
})
Take a look at node-tdd and the useNock flag. It builds on top of mocha and nock and automatically creates and uses a recording file for each test.
We love that it's so easy to use. Basically just "enable and forget" and focus on writing requests / test cases. If requests for a test change, one still needs to delete or adjust the recording file, but at least it's entirely separate from the code.