Koa: Returning new context rather than modifying

Created on 9 Feb 2018  路  3Comments  路  Source: koajs/koa

I'm still fairly new to Koa, and I want to better understand some of its design decisions. In particular, when first learning about Koa, it seemed to me that it could have easily taken a more functional approach. For instance, consider the following example from the README:

app.use(ctx => {
  ctx.body = 'Hello Koa';
});

Instead, the Koa API could have been designed so that this was written to return a new context rather than making modifications:

app.use(ctx => {
  return {...ctx, {body: 'Hello Koa'}};
});

From my perspective, this could add benefits such as making it easier to test middleware (no need to mock functions on the context) as well as playing better with composition chains and functional styles in general. I have a lot to learn about Koa, and I'm curious to know if this has ever been considered. If so, why wasn't it pursued? If not, what are people's opinion of an approach like this?

question

Most helpful comment

@edahlseng I'm going to close this issue for now. Feel free to continue discussion or reopen the issue. Good luck with your experiment :)

All 3 comments

I was never involved in the design process of Koa but here's my two cents, for what it's worth. Also, I'm no purist nor expert.

Idealistically, following a pure functional pattern would be nice, though I'm concerned about yet another signature change. From Koa v1 to v2, the middleware signature changed from ([next]) to (ctx, [next]), context was moved from being bound to first argument. I personally with think that to change to the signature again, the benefit seriously needs to outweigh the cost. As for testability, as long as mutation is expected it shouldn't be "harder" compared to a pure functional approach, just different. A thing or two might be said about tooling and/or debugging but I haven't found this to be an issue myself nor do I see issues to support that case.

Koa v1 relied on a ... not a hack maybe, but an elegant abuse of generators which pretty much did then what V8 breaks async-await down to today under the hood. The original goal was to move past the express signature (req, res, next) and bind a combined object as context to each generator middleware. As promises became "all the shiny" the current mutating approach was probably kept to not completely ostracise community middleware. Koa v2 still supports most deprecated Koa v1 middleware through koa-compose koa-convert because of this.

I'm doing allot of guesswork here but hopefully this gives you some insight.

Edit The intention was to reference convert, not compose.

@fl0w Thanks for the response! This historical lens provides a lot of valuable insight.

I might try playing around in a fork of koa to see what benefits a more functional approach would provide (won't know until I try!). If there's anything worthwhile that I learn from that, I'll post back here!

@edahlseng I'm going to close this issue for now. Feel free to continue discussion or reopen the issue. Good luck with your experiment :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ke1Del picture ke1Del  路  3Comments

imkimchi picture imkimchi  路  4Comments

tracker1 picture tracker1  路  3Comments

usernameisalreadytaken2014 picture usernameisalreadytaken2014  路  4Comments

rainesinternationaldev picture rainesinternationaldev  路  5Comments