In Fastify I can specify instance options while creating it, e.g.
const fastify = require('fastify')({logger:true, disableRequestLogging: false});
Is it possible to do this in a middleware registered with the instance?
e.g. if I do something like
fastify.register(myPlugin);
and instance of fastify is passed to myPlugin - can I, for example change its disableRequestLogging value while in the middleware?
The router is the what relies on disableRequestLogging to switch on/off logging for the request and the later response.
if (disableRequestLogging === false) {
childLogger.info({ req: request }, 'incoming request')
}
The router does provide a setup function that allows disableRequestLogging to be changed. You can see fastify.js uses router.setup() late in initialisation here to apply some new values.
The problem is fastify doesn't provide access to router as part of it's public API. Only functions like fastify.get/.post/.route etc which allow access to specific components of the router.
Short of modifying the source, I can't see a way. Not even something dodgey like onkeypatching a function in due to the way fastify variables are scoped. Even if you could do that, it would be delving into undefined/untested behaviours.
Related
I have been trying to use express-openid-connect for the last few days with no success. I am able to get the flow to work when hard coding my params. However, my goal is to be able to dynamically call auth() depending on the user being logged in. My initial attempt included calling
app.use(auth(functionThatGetsParams()));
Using the approach above, express complains that secret is required. For some reason, the auth call is getting called before anything else is resolved.
I also tried doing a few different ways,
app.use((req,res, next)=> process.env.secret = 'hello');
app.use(auth({secret: process.env.secret}));
The example above also returns the secret issue. However, setting process.env.secret outside of app.use, works fine.
My issue seems to be related to the things I do in the app.use block. The approach I am looking to use is have a call that resolves who my user is and based off of that gets the right settings.
app.use(ConnectionResolver.resolve);
I use a call similar to the above which is basically a handler that does some async stuff to get the client info and right settings then ends with next().
I would expect that then calling
app.use(auth(ConnectionManager.getAuthSettings()));
Would return the auth settings I need, but when I debug, it looks like this line gets called before anything else, so then secret is missing as the error says.
One other option I believe I may have seen online is creating a list of auth calls for each client, which I can then use for authentication, but I have not seen any examples of how that works.
Does anyone have any ideas on how this might be possible? The environment I am in is multi tenant. So I need to be able to dynamically use a certain auth config depending on the user making the call.
Any help would be greatly appreciated.
You are misunderstanding the concept of middleware.
the auth function, is a middleware factory function, it gets a set of options and returns a middleware function based on those options.
The function passed to the use method of the express app, will execute only when an incoming request will arrive.
When you do app.use(auth(getParams())) what happens is that when your server is starting, it will call getParams function, pass the result to auth function which in turn will return the auth middleware function that will be passed to the app.use function.
Once a request will arrive, the auth middleware (the one returned by the auth factory function) will execute.
You don't need to use auth conditionally. You should set it up, and then you can use the requiresAuth middleware provided by express-openid-connect package to protect your paths that requires authorization/authentication.
If your secret is loading asynchronically, wrap your entire express app setup in a bootstrap function, load your secret and only then call the server bootstrap function.
async function loadSecret() {
//load secret from external source
}
function bootstrapServer(secret) {
const app = express()
app.use(auth({ ..., secert }))
app.get('protected', requiresAuth(), (req, res) => {
// your protected route, will automatically return 401 if not authenticated
})
app.get('non-protected', (req, res) => {
// This route will be open to all without authentication
})
}
I am pretty much new to Node JS. We do have a requirement to use the request header from router to model class.
Let us assume an simple router
router.ts
router.delete(
'/sample/:id',
validateRequest(),
async function (req: Request, res: Response, next: NextFunction) {
try {
const solution: string = req.header('Some Header Value') || '';
await Controller.someMethods(req.params.id, solution);
return res.json(new HttpResponse('SUCCESS', {}, {}));
} catch (err) {
return next(err);
}
},
);
This is our router, Here we should be able to read "solution" in controller, service, and model classes. Right now we have passed this as an argument to different components. Is there any better approach to read the header value which is in the current request scope?
Similarly using components in spring framework, or sesison management or any other better approach other than passing the header value as an argument at each component level.
regards
Eresh
TL; DR; There is no other way than just mapping it manually.
Express is quite minimalistic so we don't such abstractions as Spring, the truth is that Node.js is different from Java. In Java we spawn a thread per request, so every request has a single thread. Whereas Node.js is async and single-threaded, so multiple requests share the same thread so you need to pass the values down your calls because there is no out-of-the-box solution on storing global values for a request.
If you want to have an access to the headers somewhere inside an application you could build a system that does so. The first step is to add the middleware that stores the headers in service with a unique ID associated with it and somehow passes this ID down the road. Then whenever you know the ID you could call the service to get the data for you, though you still will need to pass the ID down the road. I think you should not care about that, and that is okay. I would refactor your code in a way that a Controller methods access req and res then all the logic of working with these objects will be incapsulated here, whereas the service layer will expect raw data that know nothing about the transport layer that controllers operate with. Thus you can call services from another service, because they know nothing about the request and response.
FWIW, if you need a better framework use Nest.js, it is great and advanced, also it uses decorators (in a way similar to annotations in Spring). For instance you could just inject the header value as a call argument for your method in the following way #Header("some-header") solution: string
Best regards.
I’m always coding backend api’s and I don’t really get how express does its bidding with my code. I know what the request and response objects offer, I just don’t understand how they come to be.
This simplified code for instance:
exports.getBlurts = function() {
return function(req, res) {
// build query…
qry.exec(function(err, results) {
res.json(results);
}
});
}
}
Then I’d call in one of my routes:
app.get('/getblurts/, middleware.requireUser, routes.api.blurtapi.getBlurts());
I get that the function is called upon the route request. It’s very abstract to me though and I don’t understand the when, where, or how as it pertains to the req\res params being injected.
For instance. I use a CMS that modifies the request object by adding a user property, which is then available globally on all requests made whether ajax or otherwise, making it easy at all times to determine if a user is logged in.
Are the req and res objects just pre-cooked by express but allow freedom for them to be modified to your needs? When are they actually 'built'
At its heart express is actually using node's default http-module and passing the express-application as a callback to the http.createServer-function. The request and response objects are populated at that point, i.e. from node itself for every incoming connection. See the nodeJS documentation for more details regarding node's http-module and what req/res are.
You might want to check out express' source code which shows how the express application is passed as a callback to http.createServer.
https://github.com/expressjs/express/blob/master/lib/request.js and https://github.com/expressjs/express/blob/master/lib/response.js show how node's request/response are extended by express specific functions.
I am having two controllers, SocketController and ProjectController
SocketController has method getData(data)
ProjectController has method addProject(data)
I need to call addProject() from getData() method.
I tried using sails.controllers.ProjectController.addProject(data) but I got following error:
Cannot find method addProject of undefined
I searched for alternative ways to call another controller using services in Stack Overflow but that was of no help to me. Is there any other way to get this work?
Controllers are just Node modules that export public methods. You can require them like anything else. So assuming your methods are correctly exposed with module.exports, this will work:
/* ProjectController */
module.exports = {
addProject: function(data) {
// ...
}
};
/* SocketController */
// Assuming ProjectController.js exists in the same directory (default for Sails)
var projectController = require('./ProjectController');
module.exports = {
index: function(req, res) {
// ...
projectController.addProject(...);
}
};
Edit: I will add that using services is a better place to keep common functionality like your example. Services allow complex logic to be decoupled from the controller layer and reused by other areas of the application with ease. Controllers should generally be reserved for handling HTTP requests from the client and passing the data to the service or model layers for manipulating the database. I believe Sails also makes services global by default so you don't have to worry about confusing require paths.
Controller functions are also accessible through the global sails object, without use of require, however a function from ProjectController will be found under:
sails.controllers.project.addProject
instead of
sails.controllers.ProjectController.addProject
Anyways you might want to consider having shared functionality in either services or models, as was pointed out previously.
By "setting" I mean "something that is set", similar to "setters" in Java & other OO languages, not Express's "application settings". Is there a way to access and ideally use "settings" set inside middleware use()d by the app? In particular, some middleware is a full Express app, like vhost and the new Router middleware that comes with Express 4.x. If you do most of your routing in a virtual host and want to access some route param from the main app, that could be a problem. This is especially true if you have several layers, like I'm having, and it would be inconvenient to export the setting all the way out to the main app.
So is there a way to access these settings from the main app?
In particular, some middleware is a full Express app
Express 4.x has a great new feature to get around this problem. You can now use express.Router directly. In cases where you used to use an entire routing path by using a second sub-Express object as middleware, now you can just use Router.
For anything else, I usually add properties to the request object, namespaced by the name of my app.
function (req, res, next) {
req.myApp = req.myApp || {};
req.myApp.someData='whatever';
next();
}
The next middleware in the line will have access to this variable. I use this to track unique connection IDs, assigned by the first piece of middleware and subsequently used by others.