-
Notifications
You must be signed in to change notification settings - Fork 459
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Explicit. No middleware ? #8
Comments
Middleware accomplish two things:
Both are problematic. To elaborate on the first, consider a typical express application: app.use(logger());
app.use(needsAuth());
app.get('/my-route', require('./my-route')); Then, imagine you want to add a route app.use(function(req, res, next){
if ('/log' === req.url) return next();
logger(req, res, next);
}); Assuming that through experience and discipline you avoid this pitfall, you probably then rely on defining middleware for each route through "sub-apps". // boot.js
app.use(require('./my-route');
// my-route.js
const bodyParser = require('body-parser');
module.exports = express().get('/', bodyParser, function(req, res, next){
// req.body
}); This pattern, however, still has significant problems:
First, the assignment operator brings clarity: async function (req, res) {
const body = await json(req); // explicit
}
function (req, res, next) {
req.body // where did this come from? (╯°□°)╯︵ ┻━┻
} Second, errors are handled like everywhere else: async function (req, res) {
try {
await json(req);
} catch (e) {
// buffering failed
// size limit exceeded
// parsing failed
}
} If you don't specify This flexibility in error handling is very difficult to achieve with middleware. In general, middleware skip over subsequent routes and go to the error handler (also not very obvious). Third, the presence of the async function (req, res) {
await rateLimit(req); // this holds up the request
log(body); // this doesn't hold up the request
send(res, 200, 'woot!'); // no `res` monkey-patching
} Finally, you might still favor global middleware to avoid incessant repetition. You could successfully argue that if every route in your app requires logging, this pattern falls into "pre-mature optimization". Fortunately for us, simple functions solve this without sacrificing explicitness: import decorate from './my-middleware';
export default decorate(async (req, res) => {
// the introduction of re-usable logic is explicit and
// the programmer knows to look at `my-middleware.js`
}); As you can see, |
FWIW decorators are middleware. I totally agree though, excited to see that node core is maybe going with promises finally! Hopefully then npm modules can finally converge on the same goal, async/await should have been added 4 year ago haha – we could all be using vanilla Node with promises, no frameworks, no koa, no micro, no express, no babel, utopia <3. I'd also argue though that HTTP is a bad abstraction to begin with, I kind of like Lambda's approach there, it makes more sense for the general case, but there's always going to be weird points where you have to integrate with HTTP. You're not finding the granularity annoying? I like Lambda for data processing but for HTTP I find so many distinct functions is kind of just a pain in the ass haha Another approach that I think would be interesting, potentially even nicer is a more functional approach like Ruby's Rack and the now super popular Redux. The "middleware" just become opaque objects all the way down with promises wrapped at will for whatever behaviour, but that wouldn't have the normalizing effect that promises does/will. |
+1 to being lean/explicit and just using decorators for middleware
Couldn't agree more with this 👍, HTTP always tends towards lots of adhoc plumbing. I think what makes things like Lambda, Kafka et al conceptually nicer is that a microservice is something that simply consumes one log and produces another (as opposed to just "small service"). Then you have a fundamental way to stack component parts together. If you consider decoupling the request-response (i.e. that you could receive a response without a request, or make a request with multiple responses, or make a request that does not have a response, etc) then HTTP (responding directly to a request) just becomes one specific instance of the stream processing model. Would love to see a version of micro based on this, or otherwise, for more realtime communication (push by default rather than pull).. |
For those new to higher order functions, the const decorate = fn => (req, res) => {
// do some stuff here
fn(req, res)
} |
what about having |
yes, algebraic effects ftw |
Please provide an example where React Hooks are better than async-await |
Explicit. No middleware. Modules declare all dependencies
What does it mean by no middleware? why you design it like this.
The text was updated successfully, but these errors were encountered: