Fastify middleware - access to query and params? - javascript

trying to get middleware working in Fastify - I don't seem to have access to the query or params. The docs say:
Fastify supports out of the box Express/Restify/Connect middlewares, this means that you can just drop-in your old code and it will work! (faster, by the way)
But with a simple example:
fastify.use(function(req, res, next) {
console.log('req.query', req.query); // undefined
console.log('req.params', req.params); // undefined
next();
});
Same if I add/restrict the url:
fastify.use('/foo', function(req, res, next) {
I'm sure I am missing something, but the docs do claim it 'just works' - which I can't see how if you don't get access to the qs?
[I think I can re-write to use hooks, but I'm really interested in how I am meant to be doing this with middleware]
Thanks

This was answered when Fastify 2 was the main version. This answer may not be correct for Fastify 3
While Fastify is compatible with Express/Restify method signature, it isn't exactly the same values being passed in. The method signature is:
/**
* Generic middleware method
* #param {http.IncomingMessage} req
* #param {http.ServerResponse} res
*/
const middleware = (req, res) => {
}
fastify.use(middleware)
When using .use, Fastify only deals with the Node.js HTTP classes
which do not provide the .params or .query fields.
Express adds these fields as a nicety to developers. If the middleware you use
relies on those features, unfortunately, it will not be a direct drop in.
All is not lost
If you choose to migrate your middleware to Fastify, the .params and .query
fields are available on the Request
object.
Using the middleware in your question, this is what the Fastify version would
look like.
fastify.addHook('onRequest', function(request, reply, done) {
console.log('query', request.query);
console.log('params', request.params);
done();
})
Fastify is asking developers to think more in terms of Hooks and less in terms of Middleware. This provides more flexibility and greater speed but can be a little more complicated to write at times.
Additional reading
The Lifecycle and
Hooks documentation on the Fastify
site give more detail on how these pieces work together.
The Middleware documentation
provides more detail on what features are supported.
Somewhat related, using Plugins
you are able to scope to a particular path.
References
Express middleware support
From the Middleware documentation:
Furthermore, methods added by Express and Restify to the enhanced versions of
req and res are not supported in Fastify middlewares.
and
Express modifies the prototype of the node core Request and Response objects
heavily so Fastify cannot guarantee full middleware compatibility.
Express adding .params and .query
Express adding .query to request
and where Express runs the query middleware
Express adding parameters to route.

The .use() function is only a utility to help users to migrate from Express to Fastify.
The input function interface is (req, res, next) but the req and res object are
the standard Node.js objects http.ClientRequest
and http.ServerResponse (that is the same
interface of Express middleware).
So the assumption is that the users have implemented middleware for Express using the standard Node.js's objects.
To archive your needs you should parse the req.url as described here.
The .use API will be deprecated in Fastify v3.
Instead, if you want to start developing with Fastify you should migrate to .register.
The register is the great feature of Fastify that offer encapsulation

I Fastify use method is used for registering middlewares. The middleware is a function with the following signature middleware(err, req, res, next)
Try:
fastify.use(function(err, req, res, next) {
console.log('req.query', req.query); // undefined
console.log('req.params', req.params);
next();
});

You can use fastify without .use method , just use fastify.route.
fastify.route({
method: 'GET',
url: '/',
schema: {
// request needs to have a querystring with a `name` parameter
querystring: {
name: { type: 'string' }
}
},
handler: async (request, reply) => {
// here you will get request.query if your schema validate
}
})

Related

expressJS - path values in App.use to mount a Middleware [duplicate]

I'm kind of new to express and node.js, and I can't figure out the difference between app.use and app.get. It seems like you can use both of them to send information. For example:
app.use('/',function(req, res,next) {
res.send('Hello');
next();
});
seems to be the same as this:
app.get('/', function (req,res) {
res.send('Hello');
});
app.use() is intended for binding middleware to your application. The path is a "mount" or "prefix" path and limits the middleware to only apply to any paths requested that begin with it. It can even be used to embed another application:
// subapp.js
var express = require('express');
var app = modules.exports = express();
// ...
// server.js
var express = require('express');
var app = express();
app.use('/subapp', require('./subapp'));
// ...
By specifying / as a "mount" path, app.use() will respond to any path that starts with /, which are all of them and regardless of HTTP verb used:
GET /
PUT /foo
POST /foo/bar
etc.
app.get(), on the other hand, is part of Express' application routing and is intended for matching and handling a specific route when requested with the GET HTTP verb:
GET /
And, the equivalent routing for your example of app.use() would actually be:
app.all(/^\/.*/, function (req, res) {
res.send('Hello');
});
(Update: Attempting to better demonstrate the differences.)
The routing methods, including app.get(), are convenience methods that help you align responses to requests more precisely. They also add in support for features like parameters and next('route').
Within each app.get() is a call to app.use(), so you can certainly do all of this with app.use() directly. But, doing so will often require (probably unnecessarily) reimplementing various amounts of boilerplate code.
Examples:
For simple, static routes:
app.get('/', function (req, res) {
// ...
});
vs.
app.use('/', function (req, res, next) {
if (req.method !== 'GET' || req.url !== '/')
return next();
// ...
});
With multiple handlers for the same route:
app.get('/', authorize('ADMIN'), function (req, res) {
// ...
});
vs.
const authorizeAdmin = authorize('ADMIN');
app.use('/', function (req, res, next) {
if (req.method !== 'GET' || req.url !== '/')
return next();
authorizeAdmin(req, res, function (err) {
if (err) return next(err);
// ...
});
});
With parameters:
app.get('/item/:id', function (req, res) {
let id = req.params.id;
// ...
});
vs.
const pathToRegExp = require('path-to-regexp');
function prepareParams(matches, pathKeys, previousParams) {
var params = previousParams || {};
// TODO: support repeating keys...
matches.slice(1).forEach(function (segment, index) {
let { name } = pathKeys[index];
params[name] = segment;
});
return params;
}
const itemIdKeys = [];
const itemIdPattern = pathToRegExp('/item/:id', itemIdKeys);
app.use('/', function (req, res, next) {
if (req.method !== 'GET') return next();
var urlMatch = itemIdPattern.exec(req.url);
if (!urlMatch) return next();
if (itemIdKeys && itemIdKeys.length)
req.params = prepareParams(urlMatch, itemIdKeys, req.params);
let id = req.params.id;
// ...
});
Note: Express' implementation of these features are contained in its Router, Layer, and Route.
Simply
app.use means “Run this on ALL requests”
app.get means “Run this on a GET request, for the given URL”
app.use is the "lower level" method from Connect, the middleware framework that Express depends on.
Here's my guideline:
Use app.get if you want to expose a GET method.
Use app.use if you want to add some middleware (a handler for the HTTP request before it arrives to the routes you've set up in Express), or if you'd like to make your routes modular (for example, expose a set of routes from an npm module that other web applications could use).
app.get is called when the HTTP method is set to GET, whereas app.use is called regardless of the HTTP method, and therefore defines a layer which is on top of all the other RESTful types which the express packages gives you access to.
Difference between app.use & app.get:
app.use → It is generally used for introducing middlewares in your application and can handle all type of HTTP requests.
app.get → It is only for handling GET HTTP requests.
Now, there is a confusion between app.use & app.all. No doubt, there is one thing common in them, that both can handle all kind of HTTP requests.
But there are some differences which recommend us to use app.use for middlewares and app.all for route handling.
app.use() → It takes only one callback.
app.all() → It can take multiple callbacks.
app.use() will only see whether url starts with specified path.
But, app.all() will match the complete path.
For example,
app.use( "/book" , middleware);
// will match /book
// will match /book/author
// will match /book/subject
app.all( "/book" , handler);
// will match /book
// won't match /book/author
// won't match /book/subject
app.all( "/book/*" , handler);
// won't match /book
// will match /book/author
// will match /book/subject
next() call inside the app.use() will call either the next middleware or any route handler, but next() call inside app.all() will invoke the next route handler (app.all(), app.get/post/put... etc.) only. If there is any middleware after, it will be skipped. So, it is advisable to put all the middlewares always above the route handlers.
In addition to the above explanations, what I experience:
app.use('/book', handler);
will match all requests beginning with '/book' as URL. so it also matches '/book/1' or '/book/2'
app.get('/book')
matches only GET request with exact match. It will not handle URLs like '/book/1' or '/book/2'
So, if you want a global handler that handles all of your routes, then app.use('/') is the option. app.get('/') will handle only the root URL.
There are 3 main differences I have found till now. The 3rd one is not so obvious and you may find it interesting. The differences are the same for the express router. That means router.use() and router.get() or other post, put, all, etc methods has also same difference.
1
app.use(path, callback) will respond to any HTTP request.
app.get(path, callback) will only respond to GET HTTP request. In the same way, post, put, etc will respond to their corresponding request. app.all() responds to any HTTP request so app.use() and app.all() are the same in this part.
2
app.use(path, callback) will match the prefix of the request path and responds if any prefix of the request path matches the path parameter. Such as if the path parameter is "/", then it will match "/", "/about", "/users/123" etc.
app.get(path, callback) Here get will match the whole path. Same for other HTTP requests and app.all(). Such as, if the path parameter is "/", then it will only match "/".
3
next('route') doesn't work on the middleware/callback functions of app.use(). It works only on app.get(), app.all() and other similar function of other HTTP requests.
According to express documentation:
next('route') will work only in middleware functions that were loaded by using the app.METHOD() or router.METHOD() functions.
METHOD is the HTTP method of the request that the middleware function
handles (such as GET, PUT, or POST) in lowercase.
From here we will use the keyword METHOD instead of get, post, all, etc.
But what is next('route')?!
Let's see.
next('route')
we see, app.use() or app.METHOD() can take several callback/middleware functions.
From the express documentation:
Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.
If the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will be left hanging.
So we see each middleware functions have to either call the next middleware function or end the response.
And this is same for app.use() and app.METHOD().
But sometimes in some conditions, you may want to skip all the next callback functions for the current route but also don't want to end the response right now. Because maybe there are other routes which should be matched. So to skip all the callback functions of the current route without ending the response, you can run next('route'). It will skip all the callback functions of the current route and search to match the next routes.
For Example (From express documentation):
app.get('/user/:id', function (req, res, next) {
// if the user ID is 0, skip to the next route
if (req.params.id === '0') next('route')
// otherwise pass the control to the next middleware function in this stack
else next()
}, function (req, res, next) {
// send a regular response
res.send('regular')
})
// handler for the /user/:id path, which sends a special response
app.get('/user/:id', function (req, res, next) {
res.send('special')
})
See, here in a certain condition(req.params.id === '0') we want to skip the next callback function but also don't want to end the response because there is another route of the same path parameter which will be matched and that route will send a special response. (Yeah, it is valid to use the same path parameter for the same METHOD several times. In such cases, all the routes will be matched until the response ends). So in such cases, we run the next('route') and all the callback function of the current route is skipped. Here if the condition is not met then we call the next callback function.
This next('route') behavior is only possible in the app.METHOD() functions.
Recalling from express documentation:
next('route') will work only in middleware functions that were loaded by using the app.METHOD() or router.METHOD() functions.
Since skipping all callback functions of the current route is not possible in app.use(), we should be careful here. We should only use the middleware functions in app.use() which need not be skipped in any condition. Because we either have to end the response or traverse all the callback functions from beginning to end, we can not skip them at all.
You may visit here for more information
app.use gets called every time a request is sent to the server.
Only thing is we should call it before handling get, put, post etc. requests
app.use(middleware);
function middleware(req, res, next)
{
console.log("Came in middleware function without arrow");
next();
}
app.get gets called only for get requests for given path.
app.get('/myget', myget_function);
function myget_function(req, res)
{
console.log("Came in function myget");
res.send('Hello World! from myget');
}
app.post gets called only for post requests for given path.
app.post('/mypost', mypost_function);
function mypost_function(req, res)
{
console.log("Came in function mypost");
res.send('Hello World! from mypost');
}

fastify.js equivalent of express next() for Node server

In express, we have routes like so :-
app.get("/route1", function(req, res, next){
...
}
What would be the equivalent statement in Fastify Framework (next part is important)?
The equivalent would be:
app.get('/route1', function(request, reply) {
...
}
Where request and reply are the Fastify custom object.
There is NOT next since there is no a chain of middleware in Fastify, but there is the concept of Lifecycle of a request that you can customize with hooks

Using Express.JS middleware on only some routes

As an exercise in learning NodeJS, I am building a sort of API with ExpressJS that responds to web requests. As of right now, there are three routes in the program, '/login', '/register', and '/changePassword'. All of these methods do not need any sort of token to be processed.
However, every other route I plan to add to the program, (for example, a '/post' route) would require that the user authenticate themselves with a token obtained from a POST request to '/login' with the correct credentials.
TO verify the Token, I have written a middleware function:
module.exports.validateToken = function (req,res,next) {
const token = req.headers['x-access-token']
console.log(`validateToken() - TOKEN: ${token}`)
if (token) {
//Make sure the token is valid[...]
next()
}else {
return res.status(401).send({
message: 'Missing token',
success: false
})
}
}
My question is, how do I apply this middleware to only the routes that would require authentication?
I've thought of just creating another Router object, and calling it like this:
const tokenValidator = require('./util').validate.validateToken
// Router used for any actions that require user-authentication
const authRouter = new app.Router()
authRouter.use(tokenValidator)
But would this interfere at all with my original, authentication free routes?
// Initiate the routes that don't need auth
const routes = require('./routes')(app)
Thanks in advance, I am more of a Java developer, so a lot of the Javascript quirks have left me stumped.
Let's say your middleware is in "./middleware/auth"
I would create a base route for which the middleware should be applied, e.g.
app.use("/private", require("./middleware/auth"));
This will invoke your auth middleware, on any route which starts with '/private'
Thus, any API controller which requires auth should then be defined as:
app.use("/private/foo", require("./controllers/foo"));
Your middlware function will be invoked for any route within /private, before it hits your controller.
And any that do not require your middleware, should simply stay outside of the 'private' api context, e.g.
app.use("/", require("./controllers/somecontroller"));
In Expressjs, every middleware you add, gets added to the middleware stack, i.e. FIFO.
Thus, if you have certain routes, which you'd like to have no authentication, you can simply keep their middlewares above others.
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use(<<pattern>>, authenticate)
Additionally, you can try using nodejs basic-auth module for authentication
Hope this helps!

Modify Request body and then proxying in Node.js

I am a relative newbie of Node.js. It been two days that I am trying to modify the body of a Request in Node.js and then forwarding it. For proxying I am using http-proxy module.
What I have to do is to intercept the password of a user inside a JSON object, encrypting it and set the new encrypted password inside the request body.
The problem is that every time I try to collect the request body I consume it (i.e. using body-parser). How can I accomplish this task? I know that the Request in node is seen has a stream.
For sake o completeness, I am using express to chain multiple operation before proxying.
EDIT
The fact that I have to proxy the request is not useless. It follows the code that I am trying to use.
function encipher(req, res, next){
var password = req.body.password;
var encryptionData = Crypto().saltHashPassword(password);
req.body.password = encryptionData.passwordHash;
req.body['salt'] = encryptionData.salt;
next();
}
server.post("/users", bodyParser.json(), encipher, function(req, res) {
apiProxy.web(req, res, {target: apiUserForwardingUrl});
});
The server (REST made by Spring MVC) give me the exception Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: null
The real problem is that there is an integration problem between modules body-parser and http-proxy, as stated in this thread.
One solution is to configure body-parser after http-proxy. If you can't change the order of the middleware (as in my case), you can restream the parsed body before proxying the request.
// restream parsed body before proxying
proxy.on('proxyReq', function(proxyReq, req, res, options) {
if (req.body) {
let bodyData = JSON.stringify(req.body);
// if content-type is application/x-www-form-urlencoded -> we need to change to application/json
proxyReq.setHeader('Content-Type','application/json');
proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
// stream the content
proxyReq.write(bodyData);
}
}
Why don't use express chaining for this ?
In your first function just do something like this :
req.body.password = encrypt(req.body.password); next();
You just have to use a middleware.
body-parser is also just a middleware that parses the request bodies and puts it under req.body
You can do something like this:
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
function encryptPassword(req, res, next) {
req.body.password = encrypt(req.body.password);
// You can do anything really here and modify the req
//call next after you are done to pass on to next function
next();
}
app.use(encryptPassword);
Generally people use middlewares for authentication, role-based access control etc.....
You can use middlewares in particular routes also:
app.post('/password', encryptPassword, function(req, res) {
// Here the req.body.password is the encrypted password....
// You can do other operations related to this endpoint, like store password in database
return res.status(201).send("Password updated!!");
});

Testing for next(err) with supertest and Express JS

In a route or middleware in Express, you can skip the remaining call chain by invoking next(err) where err is any object. This is pretty straightforward from the docs.
When testing with SuperTest, this workflow does not seem to be supported. The only error result from the middleware to supertest, is that the text on the response is set to [object Object].
For example:
const request = require('supertest');
const app = express();
app.use( (req, res, next) => next({ error: "ErrorCode" }) );
request(app).get('/')
.expect(500)
.end(function(err, res) {
// err == undefined
// res.text === '[object Object]'
});
Is there a way with supertest to validate the object passed to the next() callback?
I obviously could use sinon+chai or jasmine to straight unit test the code, but I'm curious if this is possible with just supertest, and maybe even a supporting bespoke middleware after the testable unit.
Supertest works at the HTTP response level, so it can only check the status, headers, body of the response itself based on the HTTP message. It cannot check javascript-level details about the code inside the express app (supertest can actually check arbitrary HTTP servers written in any language, it just has some convenience code for express).
Thus first I'd write an error handler middleware that translates your error objects (which really should be Error instances instead of plain objects), sets the proper status code, content type, body, etc. Then make your supertest associations for those attributes.

Categories

Resources