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

Include an optional restRoute config #6

Closed
wants to merge 4 commits into from
Closed

Include an optional restRoute config #6

wants to merge 4 commits into from

Conversation

ChromeQ
Copy link

@ChromeQ ChromeQ commented Mar 11, 2014

So that I may override in my own configs to point to my own main route.
/public directory is often used as a grunt build directory so a possibly dev config route is useful.

So that I may override in my own configs to point to my own main route.
`/public` directory is often used as a grunt build directory so a possibly dev config route is useful.
So that I may override in my own configs to point to my own main route.
`/public` directory is often used as a grunt build directory so a possibly dev config route is useful.
@zemirco
Copy link
Owner

zemirco commented Mar 11, 2014

Where do you put your index.html if not in public/ ?

It's probably a bit more complicated than your PR because you could also use a .jade view as the starting point for your SPA.

@ChromeQ
Copy link
Author

ChromeQ commented Mar 12, 2014

I built the app using yeoman and the main front end files live under /web. The grunt build task creates the /public folder for production ready state. Sending the routes to /public/index.html isn't much good for my app or anyone using yeoman I should think. And by sending the get route of /signup/:token to index.html means it misses out getting to the getSignupToken method in lockit-signup which validates the users email in the DB.

I am trying to find a solution at the moment and trying to understand all the routes in and out of each of the modules.

The PR I sent was a quick fix to use the config path that I could override in my own config and defaulting to your /public/index.html that you already hard coded as the res.sendfile()

@zemirco
Copy link
Owner

zemirco commented Mar 12, 2014

And by sending the get route of /signup/:token to index.html means it misses out getting to the getSignupToken method in lockit-signup which validates the users email in the DB.

Here is how it works.

A user gets an email with a link pointing to /signup/:token. When visiting this route the server sends index.html and your client router takes over. Your app controller makes an AJAX request to /rest/signup/:token and gets 200 if the token is correct. Then you should show a message that the user is now authenticated and can log in with the credentials.

See the AngularJS example router examples/angular/public/js/app.js#L24 and controller examples/angular/public/js/controllers.js#L69.

@ChromeQ
Copy link
Author

ChromeQ commented Mar 12, 2014

I did think that was a way to do it but it seems silly to load the front end app to just make another http request when the original could hit the route directly via the email link. That was my thinking for the first pull request when I deleted the lines that added /rest to the routes in lockit-signup.
Now with the routes in the main lockit module catching it, I have played with doing a res.redirect to /rest/signup/:token instead and that seems a bit more direct (for this and the other routes as config.rest is a global config setting), it means it will hand off the route handling to the module concerned, although I have had to put handleResponse: false in my own config so my express routes can respond.

Perhaps that your suggestion is the slightly cleaner and more modular within the lockit ecosystem and letting the responsibility of the developer to know what I'm doing by setting rest: true in my configs.

In that case would it be a good idea to let the config dictate the location of the index.html so that in my case using yeoman that makes /web the (dev)public and not the normal /public folder, this way it offers a bit of flexibility to all users. I could edit my grunt file to update this route dependent on environment. Of course the default in the config.default.js can be /public/index.html as per my PR.

The issue and complication still remains of course if the index.html doesn't exist and should be rendered via jade or similar (handlebars in my case). But I think that is a bit more involved at the moment and requires more work than a simple config addition.

Hope this helps and thanks for the clarification.

@zemirco
Copy link
Owner

zemirco commented Mar 12, 2014

Thanks a lot for all the detailed comments!

Mixing server-side routing and client-side routing is not a good idea. It will get very confusing.

I'll implement a solution where everybody is able to set the starting point of their SPA manually without too much hassle.

@ChromeQ
Copy link
Author

ChromeQ commented Mar 12, 2014

Sorry for the long reply! But I just had another thought, the problem I have at the moment is that you use res.sendfile and if that was changed to res.render then I could point to my handlebars or jade template as express will abstract the rendering and the layout stuff.
With sendfile it gets sent as plain html markup, with render it would benefit from the express engine.

This gets the benefit of using express engine so we can point `config.restIndex` to a handlebars or jade file.
Other option could include passing a config to res.render from another config option (such as layout: false or locals: { "what": "ever" })
@zemirco
Copy link
Owner

zemirco commented Mar 12, 2014

I'll implement a solution where everybody is able to set the starting point of their SPA manually without too much hassle.

That's what I tried to answer with my comment above. Soon you'll be able to send an HTML file via res.sendfile or render any template via res.render.

@ChromeQ
Copy link
Author

ChromeQ commented Mar 12, 2014

eek, i think my patch is patching itself!
Yes, thanks, res.render would be awesome with a config option.

@ChromeQ
Copy link
Author

ChromeQ commented Mar 25, 2014

Hi Mirco, How is it going to implement a solution that allows users to render a starting page when rest=true, interested to see how you implement the res.render and if it could use the engine defined in express rather than using jade.

@zemirco
Copy link
Owner

zemirco commented Mar 26, 2014

Soon, and with your other fixes I'll release a new version. Thanks for all your help!

@zemirco zemirco closed this in 86ea864 Apr 3, 2014
@ChromeQ
Copy link
Author

ChromeQ commented Apr 3, 2014

Thanks for the update. I really think it an improvement but can I ask that
you could let me specify a file extension or just use the entire contents
of config.restIndexPage, I don't use jade and if we pass the express app to
the lock it instance it could be possible to get the render engine
property. The issue with this though is that everyone would need to specify
the app.engine before initialising lockit.
It is very close as it is but possibly checking another config option of
the restIndexExtension could be useful for the regex test or if
config.restIndexPage is undefined then default should use public/index.html
as it did.

Sorry to be a pain, its because I really like the whole idea of lockit and
flexibility is often a good thing to developers so I hope this isn't too
annoying to hear my opinions all the time!
Thanks again,
Dav
On 3 Apr 2014 19:02, "Mirco Zeiss" notifications@github.com wrote:

Closed #6 #6 via
86ea86486ea864
.

Reply to this email directly or view it on
GitHubhttps://github.com//pull/6
.

@zemirco
Copy link
Owner

zemirco commented Apr 3, 2014

hah I'm so used to Jade that I forgot about other template engines. Thanks for the hint!

How about this?

// anything that doesn't end with .html should be render()ed
if (!/.+\.html$/.test(config.restIndexPage)) return res.render(config.restIndexPage);

// for .html files use sendfile()
res.sendfile(path.join(__parentDir, config.restIndexPage));

@ChromeQ
Copy link
Author

ChromeQ commented Apr 3, 2014

I like it!

Thanks so much.
On 3 Apr 2014 21:17, "Mirco Zeiss" notifications@github.com wrote:

hah I'm so used to Jade that I forgot about other template engines. Thanks
for the hint!

How about this?

// anything that doesn't end with .html should be render()edif (!/.+.html$/.test(config.restIndexPage)) return res.render(config.restIndexPage);
// for .html files use sendfile()res.sendfile(path.join(__parentDir, config.restIndexPage));

Reply to this email directly or view it on GitHubhttps://github.com//pull/6#issuecomment-39499420
.

@zemirco
Copy link
Owner

zemirco commented Apr 4, 2014

Thought about the issue a bit more.

The problem is that a user could actually have .html files (with ejs template engine for example) that should be rendered. So I cannot assume that every .html is used with sendfile().

Getting all the required info just from config.restIndexPage is impossible. I'll have to add another key to the config. Maybe wrap all rest related stuff into one object, like so

exports.rest = {

  // render views or send JSON for single page apps
  enabled: false,

  // set starting page for single page app
  index: 'public/index.html',

  // use view engine (render()) or send static file (sendfile())
  useViewEngine: false

}

That's probably the most flexible solution.

@ChromeQ
Copy link
Author

ChromeQ commented Apr 4, 2014

That's a good point that I also didn't think about. I use handlebars
usually. But that solution does seem to be the best fit with the extra
config key.

Talking of separating some options into another object, I had to make some
amends to the couchdb adaptor as I needed to pass some request_defaults
such as http proxy, it mostly meant taking the dB name out of the URL and
using nano.use(dbname) but I will try to simplify my changes.

Thanks.
On 4 Apr 2014 08:11, "Mirco Zeiss" notifications@github.com wrote:

Thought about the issue a bit more.

The problem is that a user could actually have .html files (with ejs
template engine for example) that should be rendered. So I cannot assume
that every .html is used with sendfile().

Getting all the required info just from config.restIndexPage is
impossible. I'll have to add another key to the config. Maybe wrap all
rest related stuff into one object, like so

exports.rest = {

// render views or send JSON for single page apps
enabled: false,

// set starting page for single page app
index: 'public/index.html',

// use view engine (render()) or send static file (sendfile())
useViewEngine: false
}

That's probably the most flexible solution.

Reply to this email directly or view it on GitHubhttps://github.com//pull/6#issuecomment-39537482
.

@zemirco
Copy link
Owner

zemirco commented Apr 11, 2014

Check out the just released version 0.8.0. It should solve both problems. Here is the changelog.

@Micha4711
Copy link

I'd like to reopen this issue and make a proposal.

I'm using lockit in a SPA using Ember.js. Routing in Ember is done in the hash part of the URL. So, I want to forward "/signup/a-token" to my frontend with an URL like "index.html#/signup/a-token". Forwarding via sendfile() does not feel suitable for my use case. For the SPA case, I'd like to have a custom hook, where I can forward to client routes in a non restricted, flexible way.

I would prefer something like this for the registered routes:

      router.get(route, function(req, res) {
        // check if user would like to render a file or use static html
        if (config.rest.useViewEngine) {
          res.render(config.rest.index, {
            basedir: req.app.get('views')
          });
        }
// PROPOSAL START
        else if (config.rest.customRouter)
        {
          config.rest.customRouter({
            "req": req,
            "res": res,
            "route": route
          });
        }
// PROPOSAL END
        else {
          res.sendfile(path.join(__parentDir, config.rest.index));
        }
      });

Then I would have full control over all routing to the client by catching this hook:

exports.rest = {
   customRouter: function(p)
   {
      if (p.route.match(/^\/signup/))
      {
         p.res.redirect('/index.html#/signup/' + p.req.params.token);
      }
   },
   useViewEngine: false
};

I think this would be more flexible and suitable for different use cases in different client frameworks.

What do you think? Or am I misunderstanding the way of forwarding requests to the client?

@zemirco
Copy link
Owner

zemirco commented Jun 1, 2014

Hash based routing was hack to make SPAs work in the past. Nowadays modern browsers support the history api. Edit your Ember app and set location to 'history'.

App.Router.reopen({
  location: 'history'
});

This removes the hash from the URL and everything should work as expected.

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

Successfully merging this pull request may close these issues.

None yet

3 participants