Short answer: No - It is not possible.
Explanation:
In the context of functional programming, we have a data flow - the program takes some input data, transforms that and returns output data.
In case of a server, we have two data flows. First is when you are starting a server. In this flow, you might want to read config file or command line params from external world for stuff like port, host, database string, etc. This is a side effect and hence we would typically put it in Future. Example,
readJson(process.argv[2]) // Read configuration file
.chain(app) // Get app instance (routes, middlewares, etc.)
.chain(start) // Start server
.run().promise()
.then((server) => info(`Server running at: ${server.info.uri}`))
.catch(error);
This is typical index.js file containing all side effects (reading config). Now let us turn to second data flow.
This data flow is slightly hard to imagine. The output/side-effect of first data flow is server listening on some port for external connection. Now imagine, that every request coming to this server as one independent data-flow in itself.
Just like index.js was the file meant to handle all the side effects, your route-file or route-handler function is meant to handle the side effect i.e. result request should be replied back at this route handler. Typically, a close-to-pure functional route would look like:
function handler(request, reply) {
compose(serveFile(reply), fileToServe)(request)
.orElse((err) => err.code === 'ENOENT' ? reply404(reply) : reply500(reply))
.run(); // .run() is the side effect
}
return {
method: 'GET',
path: '/employer/{files*}',
handler
};
In above snippet, everything is pure. Only impure stuff is .run() method (I am using Hapi.js and Folktale.js Task).
Same is the idea with Front-end frameworks like Angular or React. Components in these frameworks should contain all the effects/impurity. These components just like your route handlers are end-points where side effects should happen. Your models/services should be free from impurity.
Having said this, if you still want to make your routes perfectly pure, then there is hope. What you essentially want to do is - the more higher level of abstraction:
- If Express.js is a framework, then you should build your own abstractions on top of it.
- You would typically write your own generic route handler for all your routes and you will expose your own API to register routes.
- Your route handlers will then return future/task/observable or any other monad that contains all the side effects waiting to set free.
- Your abstracted route handler will then simply call .fork() or .run().
- What it means is that when you unit-test your route handlers, no side effects are happening. They are simply wrapped in some Async Monad.
In case of front-end frameworks, as I said earlier, that your UI components will have side-effects. But there are new frameworks that are going beyond this abstraction. Cycle.js is one framework I am aware of. It applies the higher level of abstraction than Angular or React. All the side-effects are caged in observable which are then dispatched to a framework and executed making all (I literally mean 100%) your components pure.
I have attempted to create server the way you are doing using Hapi.js+Folktale.js+Ramda. My idea originally traces its roots in Cycle.js. However, I achieved mild success. Some part code was really awkward and too restrictive to write. Afterward, I gave up on having pure routes. However, rest of my code is pure and is quite readable.
On a closing note, functional programming is about coding in parts and not coding in whole. What you or me are trying to do is functional programming all the way in whole. That will feel little awkward at least in JavaScript.