Giter VIP home page Giter VIP logo

Comments (26)

jonathanong avatar jonathanong commented on May 26, 2024

right now, you can do the same, except with app.callback() with koa apps. probably won't add it to the examples until we make vhost its own repo, which we'll do in connect 3 / express 4

from examples.

rynz avatar rynz commented on May 26, 2024

@jonathanong Could you please reference an app.callback() vhost example with koa apps in this ticket in the meantime please?

from examples.

jonathanong avatar jonathanong commented on May 26, 2024

well it's the same except instead of app.use(express.vhost('example.com', main)); it'll be app.use(express.vhost('example.com', main.callback()));. this is assuming app is a connect/express app, and main is a koa app.

from examples.

rynz avatar rynz commented on May 26, 2024

I think I've misinterpreted koajs. Can I not write a web app purely in koajs without express/connect?

from examples.

jonathanong avatar jonathanong commented on May 26, 2024

yes. that's why it's not an example. vhost is a connect/express middleware, and there isn't one for koa, yet.

from examples.

rynz avatar rynz commented on May 26, 2024

Okay thanks for your help @jonathanong - Do you have a timeline for the koajs vhost middleware? It seems to be the only thing really missing currently and koajs is so awesome I can't wait to use it! Maybe I could have a crack at porting the express version to koajs to be merged with the main repo?

from examples.

jonathanong avatar jonathanong commented on May 26, 2024

well.. connect's pretty much works without connect. it's just a shame it's a part of connect, which is why we're moving it to its own repo in connect 3. we're not going to add it to koa though, it should still be its own module/middleware.

you could make your own if you want. i think it should sit between the server/apps. the api should look like this:

var vhost = require('vhost')()
var server = http.createServer(vhost)

vhost.use('*.example.com', connect())
vhost.use('example.com', koa().callback())
server.listen()

from examples.

rynz avatar rynz commented on May 26, 2024

Ah so no koa-vhost (https://github.com/koajs/vhost) in the future? That's a shame. Okay I'll roll my own for now and replace it with connect's when it is separated out. Thanks for your support.

from examples.

jonathanong avatar jonathanong commented on May 26, 2024

there's no need. there's no need for koa- this and express- that when they work just fine on their own.

from examples.

rynz avatar rynz commented on May 26, 2024

Yeah I agree but I kind of like the idea of koa- for "officially supported" generator based middleware I guess. If you could please update this ticket / documentation in koajs somewhere when vhost is it's own module/middleware that would be greatly appreciated.

from examples.

jonathanong avatar jonathanong commented on May 26, 2024

here you go! https://github.com/expressjs/vhostess if you want an example up quickly, open a PR :)

from examples.

jonathanong avatar jonathanong commented on May 26, 2024

unless you want to do mounting... which I'm -1 (for the most part).

from examples.

rynz avatar rynz commented on May 26, 2024

@jonathanong Fantastic thank you. I guess this is where a koa-vhost relevance / question might come in. I'm curious if generators could be used with vhostess for more elegant global middleware?

Eg: Express you can do the following:

var app = express();
var expressApp = express();
var secondExpressApp = express();

// Log ALL requests.
app.use(function(req, res, next) {
  req.startTime = new Date;

  function logRequest() {
    res.removeListener('finish', logRequest);
    res.removeListener('close', logRequest);
    var ms = new Date - req.startTime;
    console.log('%s %s - %s', req.method, req.originalUrl || req.url, ms);
  };

  res.on('finish', logRequest);
  res.on('close', logRequest);

  next();
});

app.use(express.vhost('express.app.com', expressApp));
app.use(express.vhost('secondexpress.app.com', secondExpressApp));

Which would provide a global middleware for logging all vhost application requests. If vhostess or an alternative koa-vhost implementation were supported, we could write elegant generator based global middleware rather than implementing the same middleware in each koa app separately.

Eg: Koa example derived from above express example

var hostess = require('vhostess')();
var koaApp = koa();
var secondKoaApp = koa();

// Log ALL requests.
hostess.use(function *(next) {
  var start = new Date();
  yield next;
  var ms = new Date() - start;
  console.log('%s %s - %s', this.method, this.url, ms);
});

hostess.use('express.app.com', koaApp.callback());
hostess.use('secondexpress.app.com', secondKoaApp.callback());

Which achieves the same global middleware with generators. The global middleware isn't only specific to logging and has many use cases, eg: Global Cross Origin Request middleware for APIs etc.

from examples.

jonathanong avatar jonathanong commented on May 26, 2024

not sure why you need to do that. just app.use(logger) in each app. you can also bundle a bunch of middleware together using koa-compose to make your life easier.

koa also has this.subdomains, so i'm not sure how useful a vhost middleware would be. connect on the other hand does not have req.subdomains.

maybe i just need an example where vhost as a middleware is required.

from examples.

rynz avatar rynz commented on May 26, 2024

I guess koa-compose is a good solution too in certain situations. I was just thinking that for example a single node instance may run multiple APIs for unique products that all depend on some common code / authentication session etc. Eg: Logging, CORS, Authentication, Validation, Error Handling etc.

Being able to mix in global middleware at the vhost level means we can yield at different points of the request/response lifecycle.

Eg:

// koa-logger
app.use(logger());
// koa-cors
app.use(cors());
// koa-etag
app.use(etag());
// koa-session
app.use(session());
// koa-compress
app.use(compress());
// generator version of express-validator
app.use(validator());

// Authentication Api.
app.use(koa.vhost('auth.mycompany.com', authApp));

// Generator for authentication testing shared across all App Apis.
// Eg: Session, token, facebook, twitter etc, one authorisation test for all Apps
// when successfully achieved at `auth.mycompany.com`.
// Responds with generic 401 if the user is not authenticated.
app.use(authentication());

// Other middleware which records metrics of logged in users etc..

// App Apis.
app.use(koa.vhost('awesomeapp.mycompany.com', awesomeApp));
app.use(koa.vhost('fantasticapp.mycompany.com', fantasticApp));
app.use(koa.vhost('realtimeapp.mycompany.com', realtimeApp));

// Common JSON Response errors from Apis.
app.use(function *(next) {
  yield next;
  // 404
  if (null == body && 200 == this.status) {
    this.status = 404;
    this.body = {code: 404, message: 'Ah, where am I?'};
  }
  // 500
  if (500 == this.status) {
    this.body = {code: 500, message: 'Kaboom!'};
  }
});

// Error logging.
app.on('error', function(err) {
  log.error('server error', err);
});

app.on('error', function(err, ctx) {
  log.error('server error', err, ctx);
});

app.listen(3000);

Which is where I think it would be beneficial for a koa-vhost specific module that behaves like a koa application to achieve this similar to express does.

If I was to use koa-compose it would work for the initial generators, however being able to use a generator mid way through and at the end would not be possible. We would have to be very careful to have the same dependencies at the same points in each app and if they were to be defined globally this way, you can clearly understand common functionality between each.

Thoughts?

from examples.

jonathanong avatar jonathanong commented on May 26, 2024

in that case, i would just do:

app.use(function*(next){
  if (this.host === 'api.awesomeapp.com') yield awesomeApp.call(this, next);
  else yield next;
})

since you're doing multiple subdomains, i would do one large switch statement.

although this could be its own repo, i'd personally rather teach people how to do this instead.

of course you'll run into different issues. you'll have to use compose(awesomeApp.middleware) and use that generator instead. in fact, i wouldn't even bother creating separate apps - just create different bundles of middleware.

note that subapps in koa are not encapsulated or inherited like in express. all the subapps will use the main app's context and keys, and there's no way it can't. to solve this, you'll have to use vhostess and do separate .callback()s

If I was to use koa-compose it would work for the initial generators, however being able to use a generator mid way through and at the end would not be possible. We would have to be very careful to have the same dependencies at the same points in each app and if they were to be defined globally this way, you can clearly understand common functionality between each.

i'm not sure what this means

from examples.

rynz avatar rynz commented on May 26, 2024

By Generators / Dependencies in that last phrase I meant "koa based" middleware sorry.

Sorry I'm a little confused, could you please show me an example with "global" middleware at the start, between two hosts and at the end?

from examples.

jonathanong avatar jonathanong commented on May 26, 2024

I'm not sure what you mean by "global" or "at the end". For each vhost in your example, I would use a conditional middleware as in my comment above.

Can you give a different example?

from examples.

rynz avatar rynz commented on May 26, 2024

Sure, how would you re-write this using your proposed solution taking into account compose() issue and not creating separate apps with an example of the same GET /test request outputting different JSON body for each host.

Eg:

// koa-logger
app.use(logger());
// koa-cors
app.use(cors());

// Authentication Api, with with GET /test Route {from: 'auth'}
app.use(koa.vhost('auth.mycompany.com', authApp));

// Placeholder for Authentication Middleware.
// Will only be used if `auth.mycompany.com` was not processed.
app.use(function *(next) {
  console.log('Test App Authenticated');
  yield next;
});

// App Apis.
// with GET /test Route {from: 'awesomeapp'}
app.use(koa.vhost('awesomeapp.mycompany.com', awesomeApp));
// with GET /test Route {from: 'fantasticapp'}
app.use(koa.vhost('fantasticapp.mycompany.com', fantasticApp));

// Common JSON Response errors from Apps.
app.use(function *(next) {
  yield next;
  // 404
  if (null == body && 200 == this.status) {
    this.status = 404;
    this.body = {code: 404, message: 'Ah, where am I?'};
  }
  // 500
  if (500 == this.status) {
    this.body = {code: 500, message: 'Kaboom!'};
  }
});

// Error logging.
app.on('error', function(err) {
  log.error('server error', err);
});

app.on('error', function(err, ctx) {
  log.error('server error', err, ctx);
});

app.listen(3000);

from examples.

jonathanong avatar jonathanong commented on May 26, 2024
// assuming all apps are koa apps, "compose" them first.
var compose = require('koa-compose')
authApp = compose(authApp.middleware)
awesomeApp = compose(awesomeApp.middleware)
fantasticApp = compose(fantasticApp.middleware)

// koa-logger
app.use(logger());
// koa-cors
app.use(cors());

app.use(function* (next) {
  // Authentication Api, with with GET /test Route {from: 'auth'}
  if (this.host === 'auth.mycompany.com') yield authApp.call(this, next);
  // Placeholder for Authentication Middleware.
  else yield otherAuthentication.call(this, next);
})

// App Apis.
app.use(function* (next) {
  switch (this.host) {
    // with GET /test Route {from: 'awesomeapp'}
    case 'awesomeapp.mycompany.com': return yield awesomeApp.call(this, next);
    // with GET /test Route {from: 'fantasticapp'}
    case 'fantasticapp.mycompany.com': return yield fantasticApp.call(this, next);
  }
  // everything else
  yield next;
})

// Common JSON Response errors from Apps.
app.use(function *(next) {
  yield next;
  // 404
  if (null == body && 200 == this.status) {
    this.status = 404;
    this.body = {code: 404, message: 'Ah, where am I?'};
  }
  // 500
  if (500 == this.status) {
    this.body = {code: 500, message: 'Kaboom!'};
  }
});

// Error logging.
app.on('error', function(err) {
  log.error('server error', err);
});

app.on('error', function(err, ctx) {
  log.error('server error', err, ctx);
});

app.listen(3000);

your error handler is actually incorrect, but that's an entirely different issue. don't think we have good error handling docs or examples yet

from examples.

rynz avatar rynz commented on May 26, 2024

Great thank you, yes I fixed the error handling with try yield / catch error to catch upstream errors correctly. You mentioned using different bundles of middleware rather than separate koa apps. How would you go about achieving this?

from examples.

jonathanong avatar jonathanong commented on May 26, 2024

it's fine like this as long as you compose them. probably would be better to keep them like this (using apps) if you ever plan to use them separately. also, doing only app.use() makes life simpler vs. mixing apps and arrays.

otherwise, i would just do var stack = [], stack.push(function*(){}) your middleware, then app.use(compose(stack)).

from examples.

rynz avatar rynz commented on May 26, 2024

Okay fantastic thank you for all your help. Would you like me to PR an example for others to learn from?

from examples.

jonathanong avatar jonathanong commented on May 26, 2024

sure. i was going to do it eventually, but i think your case is a good test case.

from examples.

jonathanong avatar jonathanong commented on May 26, 2024

it's basically a special type of conditional middleware. the only thing that isn't supported is something like *.example.com, but in that case, doing this.subdomains.length === 1 is probably better.

from examples.

rynz avatar rynz commented on May 26, 2024

PR #18

from examples.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.