iron-meteor / iron-router

A client and server side router designed specifically for Meteor.
MIT License
1.98k stars 413 forks source link

setting http status #1479

Closed tcurdt closed 8 years ago

tcurdt commented 8 years ago

Instead of just changing the rendering in a onBeforeAction I would like to send a http status code and message instead. I tried this - but that did not work:

Router.onBeforeAction(function(){
  if(Meteor.userId()){
    this.next();
  } else {
    this.response.status = 401;
    this.response.end('not authorized');
  }
}
tcurdt commented 8 years ago

This also does not return hello\n as expected either:

this.route('some/:id', function() {
  var request = this.request;
  var response = this.response;
  this.response.end('hello\n');
}, { name: 'some' });
tcurdt commented 8 years ago

Neither does this:

SomeController = RouteController.extend({
  action: function() {
    var request = this.request;
    var response = this.response;
    this.response.end('hello\n');
  }
});

Not even sure how to tell the controller not to load a template.

chrisbutler commented 8 years ago

it seems like you're trying to implement server-side routing on the client, no?

tcurdt commented 8 years ago

@chrisbutler There are two different aspects to this. I have these two hooks

var BeforeHooks = {
  isLoggedIn: function() {
    if(Meteor.userId()){
      this.next();
    } else {
      this.render('login');
    }
  },
  isAdmin: function() {
    if(Roles.userIsInRole(Meteor.userId(), [ 'admin' ])){
      this.next();
    } else {
      this.render('unauthorized');
    }
  },
}

that work OK on the client. But now I have one route that generates a feed.

If the data of the feed is on the client it could in theory even be generated on the client as well. But given that it is a feed and it should be reachable directly from the server (e.g. with curl) I tried the following:

this.route('feed', {
  name: 'feed',
}, { where: 'server' });

and then

FeedController = RouteController.extend({
  waitOn: function(){
    return Meteor.subscribe('Posts'),
  },
  action: function() {
    // how to create the response here?
  }
});

and that's where I started to experiment with setting responses and status codes. Now if that route is a server side route the before hook should (in theory) even be able set a status code, no?

chrisbutler commented 8 years ago

does this help? http://iron-meteor.github.io/iron-router/#server-hooks-and-connect

tcurdt commented 8 years ago

@chrisbutler That I did miss!

Indeed that does help - at least in terms of the access to the response from the hooks. That said - I don't want to generate the feed in a before hook but in the controller. I am still not sure how to do that.

chrisbutler commented 8 years ago

@tcurdt i think you're on the right track, but you probably need something like response.writeHead(401) to send the status code, for example

more info here: https://nodejs.org/api/http.html#http_class_http_serverresponse

tcurdt commented 8 years ago

@chrisbutler thanks for the patience. I finally worked it out.

This was working

this.route('feed', function() {
  this.response.end('hello\n');
}, {
  name: 'feed',
  where: 'server'
});

and let me to realize that

this.route('feed', {
  name: 'feed',
}, { where: 'server' });

should be

this.route('feed', {
  name: 'feed',
  where: 'server'
});

instead (doh!) ....and that the controller needs to be on the server side of course

tcurdt commented 8 years ago

Last piece of the puzzle is to send a proper 404 on non-existing server routes. Right now it just sends the page instead. Which does not seem in line with the docs http://iron-meteor.github.io/iron-router/#404s-and-client-vs-server-routes

...but I guess that's a different issue and discussed here https://github.com/iron-meteor/iron-router/issues/1055

dr-dimitru commented 8 years ago

Hi @tcurdt this spiderable fork can easily return 404 page with real proper response code.