resource-router-middleware icon indicating copy to clipboard operation
resource-router-middleware copied to clipboard

As ES6 Class?

Open samdesota opened this issue 9 years ago • 8 comments

samdesota avatar Aug 29 '15 13:08 samdesota

That seems like a nice idea. I'll try to find time today.

developit avatar Aug 29 '15 13:08 developit

Hey,

I ended up assembling something myself. I'm using experimental decorators though, so you can merge it as an optional if you want.

my fork: https://github.com/mrapogee/resource-router-middleware

To make a resource

@resource('user')
export default class UserResource {

This exports as an express router.

Also, you can use the route decorator on a class method.

// Custom route
@route.patch('/:user/:foo')
updateFoo({user, params}, res) {
  user.foo = params.foo
  res.status(204).send()
}

Full example

import {resource, route} from './src/resource-router-middleware'

const users = [{id:'foo', test: 'test'}]

@resource('user')
export default class UserResource {
  load(req, id, callback) {
    var user = users.find( user => user.id===id ),
    err = user ? null : 'Not found'
    callback(err, user)
  }

  list({ params }, res) {
    res.json(users)
  }

  create({ body }, res) {
    body.id = users.length.toString(36)
    users.push(body)
    res.json(body)
  }

  read({ user }, res) {
    res.json(user)
  }

  update({ user, body }, res) {
    for (let key in body) {
      if (key!=='id') {
        user[key] = body[key]
      }
    }
    res.status(204).send()
  }

  // Custom route
  @route.patch('/:user/:foo')
  updateFoo({user, params}, res) {
    user.foo = params.foo
    res.status(204).send()
  }

  delete({ user }, res) {
    users.splice(users.indexOf(user), 1)
    res.status(204).send()
  }
}

UserResource // Is an express router

samdesota avatar Sep 11 '15 15:09 samdesota

Interesting approach. I like the custom route decorator, but I wonder: why go with @resource('name') for decorating the class rather than just using inheritance?

import { Resource } from 'resource-router-middleware';

export default class UserResource extends Resource {
  name = 'user';
  // etc
}

This would also work nicely into the existing syntax:

import { Resource, default as resource } from 'resource-router-middleware';

export default new Resource({ name: 'user' });

// ...which would be the same as:
export default resource({ name: 'user' });

// such that:
(resource() instanceof Resource);  // true
(resource() instanceof express.Router);  // true

... just my thoughts. Perhaps it's easy to support all of the above and the @resource decorator?

developit avatar Sep 11 '15 15:09 developit

I moved away from inheritance due to needing a getMiddleware() method, but I didn't think of extending express Router. I wasn't to keen on the class UserResource then UserResource returning a completely separate Router instance, but this solves that.

We'd need to rename delete to remove though. And watch out for overrides.

samdesota avatar Sep 11 '15 16:09 samdesota

Overrides yes. What's the need to rename delete? It's a valid method name, and babel's transpiled classes add defined methods using Strings for names (versus literals, which would be reason to avoid). Since these class methods are generally only called by the module's routing logic, I think we should be good?

developit avatar Sep 11 '15 16:09 developit

Router already has the method delete defined. We could just use super.delete to fix this.

Also, just tried this. Express Router doesn't seem to be compatible with ES6 classes

If I use this for Router:

class Router {
  param () {
  }
}

Calling super.param works inside the constructor of a class extending from Router. But super.param is undefined when using the express Router.

samdesota avatar Sep 11 '15 16:09 samdesota

Ah, good catch - Router doesn't appear to be a class at all.

Score one for the decorator solution...

developit avatar Sep 11 '15 16:09 developit

The other option is having a getMiddleware() function that returns the Router.

That way instanceof Resource would work, but not instanceof Router. Also, slightly simpler inheritance as well multiple instances of the same resource without calling the decorator.

Any advantage you see here?

samdesota avatar Sep 11 '15 17:09 samdesota