Skip to content
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

Use ES6 classes - v2.x #605

Closed
wants to merge 11 commits into from

Conversation

macalinao
Copy link

This converts Context, Request, and Response to ES6 classes to make things more semantic.

See #597 for the old PR.

@macalinao macalinao mentioned this pull request Nov 24, 2015
*
* @api private
*/

createContext(req, res) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of keeping createContext around you could replace where it's used in the http callback with the call to the constructor.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true. again, did it for reverse compatibility, but it doesn't make sense to keep it, you're right

@jonathanong
Copy link
Member

@simplyianm the code as-is won't be merge. do you want to update it based on our comments?

  • Ditch all the prototypes
  • Make extending the context/request/response objects use class inheritance (which is mostly removing features and adding docs):
app.Context = class Context extends app.Context {
  whatever(){}
}

Anyone have opinions on this signature before @simplyianm or anyone else updates this PR?

@jonathanong
Copy link
Member

FWIW i'm -1/2 on this PR because I don't really see any benefits and making it classes just makes it more confusing to me

@macalinao
Copy link
Author

I'll update it
On Sun, Jan 17, 2016 at 15:56 jongleberry [email protected] wrote:

FWIW i'm -1/2 on this PR because I don't really see any benefits and
making it classes just makes it more confusing to me


Reply to this email directly or view it on GitHub
#605 (comment).

@popomore
Copy link
Member

+1

it's easy to extend Application/Context/Request/Response rather than override

@tejasmanohar
Copy link
Member

ping @simplyianm

@macalinao
Copy link
Author

Fixed @tejasmanohar @jonathanong

@tejasmanohar
Copy link
Member

nice! probably best to squash so commit history isn't polluted :P

@tejasmanohar
Copy link
Member

ping @jonathanong

@tejasmanohar tejasmanohar mentioned this pull request Feb 25, 2016
@@ -17,7 +17,7 @@ const only = require('only');
* Prototype.
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment Prototype should go since this is not a prototype object anymore, but a class (function) that has a prototype.

@felixfbecker
Copy link
Contributor

This is great imo. It is in line with the new new Koa() syntax, it is easier to understand (especially the getter/setter syntax) and it may make it easier to test koa apps without using supertest by simply creating new contexts / requests / responses.

@jonathanong
Copy link
Member

  • can we add docs? specifically, how would someone extend the context/request/response with their own methods?
  • why are the tests removed? can we rework the tests?

other than that, I'm +0

@macalinao
Copy link
Author

I actually disagree with extending the base class -- things like that
should go in the middlewares to make execution more predictable. What are
the benefits to allowing it?
On Fri, Feb 26, 2016 at 11:01 jongleberry [email protected] wrote:

  • can we add docs? specifically, how would someone extend the
    context/request/response with their own methods?
  • why are the tests removed? can we rework the tests?

other than that, I'm +0


Reply to this email directly or view it on GitHub
#605 (comment).

@jonathanong
Copy link
Member

well for one, people are using it: #652

middleware is actually an anti-pattern in koa unless it's something you really want to be executed on every request (like checking etags and setting the status as 304 if the body is fresh). everything should be a function that you can just await ex. const body = await parse.json(ctx).

middleware:

  • frequently injects globals into your context
  • is order dependent, meaning switching middleware order might cause undesirable behaviors or bugs
  • usually executes logic on every request, which may be inefficient, or executes logic based on some "filter", which makes it harder to debug

for example, instead of having a body parsing middleware that always sets this.request.body, just const body = await parse.json(ctx). the benefit of this is that sometimes you can do it before authentication and sometimes after, depending on the requirements of the route. changing order like this is difficult with middleware. if done properly, you should be able to see "all" the logic of a route in a single function instead of going through each middleware in different files. ex. you might not want to download a file a user uploaded until they've 1) been authenticated 2) been authorized.

now, back to extending the context. the two reasons for extending context is:

  1. allow users to build frameworks on top of koa
  2. allow adding functions like parse.json() to context so you don't have to require() a billion things in every file, as well as defining all the globals in one place (vs. multiple middleware).

of course, this is prone to user error, so we never really recommended it strongly, but it's a feature that shouldn't be removed.

@jonathanong
Copy link
Member

similar philosophy: vercel/micro#8

koa is the same except we abstract req and res because working with them directly is a pain

@jonathanong jonathanong added this to the v2.0.0 milestone Mar 4, 2016
@jonathanong jonathanong mentioned this pull request Mar 15, 2016
16 tasks
@jonathanong jonathanong self-assigned this Mar 17, 2016
@PlasmaPower
Copy link
Contributor

I don't like this PR because it won't fix much given that delegate is still used (multiple inheritance isn't supported in ES6).

@felixfbecker
Copy link
Contributor

@PlasmaPower that is true, but I don't think it has something to do with multiple inheritance. delegate only defines getters that delegate to another object. It could be replaced by writing the getters into the class manually, which would be much better for static analysis and IDEs to understand.

@PlasmaPower
Copy link
Contributor

@felixfbecker could you explain what you mean by "writing the getters into the class manually"?

@felixfbecker
Copy link
Contributor

@PlasmaPower Well instead of doing this

delegate(Context.prototype, 'response')
  .method('attachment')
  .method('redirect')
  .method('remove')
  .method('vary')
  .method('set')
  .method('append')
  .access('status')
  .access('message')
  .access('body')
  .access('length')
  .access('type')
  .access('lastModified')
  .access('etag')
  .getter('headerSent')
  .getter('writable');

you simply write the getters and methods into the class manually:

class Context {

  attachment(filename) {
    this.response.attachment(filename);
  }

  get status() {
    return this.response.status;
  }

  set status(status) {
    this.response.status = status;
  }
}

This is what delegate does. It is a lot more verbose to write it manually. I personally have never been a fan of this delegation because it is not clear for someone who reads the code wehter body delegates to request or response for example, so I always use response / request explicitly anyway. But using delegate here is not a sin, the class is still much cleaner (I think you confused delegate with a mixing function).

@PlasmaPower
Copy link
Contributor

@felixfbecker yeah but that's a pain compared to simply extending Response and Request.

@felixfbecker
Copy link
Contributor

@PlasmaPower Always favor composition over inheritance 😉

@jonathanong jonathanong modified the milestones: v3.0.0, v2.0.0 Mar 23, 2016
@fundon
Copy link
Contributor

fundon commented Sep 5, 2016

Drops delegates module will get better performances.

@jonathanong
Copy link
Member

hi, I'm going to close this for now. I don't think we need to move every single thing to ES6 — there's not much benefit in switching to ES6 classes.

thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants