Show HN: Server.js – A modern Express alternative
serverjs.io
serverjs.io
I recently started learning express/node and wasted weeks googling for blog posts for each dependency to figure out how to configure them. I guess this is somewhat valuable for end-to-end understanding but not for productivity.
There are a bunch dependencies I am now kind of decided on (not for technical reasons, but because they are clear popularity contest winners) and figured out how use:
body-parser
compression
serve-favicon
express-session
csurf
helmet
cors
dotenv
moment
selfsigned
chalk
debug
But still a bunch that I haven't gotten to googling and still need to decide on what to choose: logging (morgan vs winston)
validation (express-validator, joi)
auth (passport jwt, local, social)
session storage (redis vs keeping it in database?)
database (mongo/mongoose vs pg/knex/bookshelf/sequelize, graphql)
storage (s3 vs gcs)
ajax requests (request vs axios)
mail (mailgun, sendgrid, mailchimp)
error handlers
rate limiting
geo ip
I would be so happy if someone took away my power to choose and just forced me to use something that will "just work".I highly recommend js-joda, particularly if you’ll ever be computing/showing things to your users in different time zones. It actually treats dates and times rigorously, and has an api that makes it clear what kinds of operations make sense to do on a zoned vs local datetime and makes things like converting between timezones vs transposing them explicit and simple.
In general I see the appeal of using a small shim around a standard library thing rather than re-implementing something totally new, but JS Date is bad enough that you're better off staying away altogether. It's just hard to use correctly since there's no "timezone unaware" object available and it always assumes the local timezone, so users' browsers in different timezones treat them differently. Lots of seemingly simple things (e.g. a time + timezone input picker) are easy to mess up because you end up accidentally implicitly converting things to the local time.
In short, the ES5 specs [1] say that
The implementation of ECMAScript should not try to determine whether the
exact time was subject to daylight saving time, but just whether daylight
saving time would have been in effect if the current daylight saving time
algorithm had been used at the time. This avoids complications such as
taking into account the years that the locale observed daylight saving time year round.
This means that if your country handled daylight saving differently in the past, converting the timestamp to string may give you a wrong answer (this would be the case of a number of european countries during WWII).The spec has been improved starting with ES6 [2], but to my knowledge no browser has fixed the issue:
An implementation dependent algorithm using best available information on
time zones to determine the local daylight saving time adjustment
DaylightSavingTA(t), measured in milliseconds. An implementation of
ECMAScript is expected to make its best effort to determine the local
daylight saving time adjustment.
NOTE It is recommended that implementations use the
time zone information of the IANA Time Zone Database
http://www.iana.org/time-zones/.
A solution is to use a JS library that has its own timezone database.[1] http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.8 [2] http://www.ecma-international.org/ecma-262/6.0/#sec-daylight...
Unix timestamp refers unambiguously to single point in time. Interpretation of this point in time in different timezones is complicated but it's outside of it.
My issue was with "then displayed to the proper locale by the client's device." I mean, by itself it is ok, but in the case of a web client one cannot unfortunately just use the Date object and convert the timestamp to a human readable string.
As an aside, moment-timezone it a godsend for dealing with timezone discrepancies. I would pay money for it.
Link for the lazy: https://github.com/js-joda/js-joda
Maybe you'd seen the name somewhere and your subconscious had reminded you, haha
rate-limiting -> nginx || iptables
Never ask PHP/Node/Ruby/Python to do low-level network routing. Your throwing megabytes of memory at a simple connection decision. If you need advanced logic for rate-limiting (not just access counting) then using nginx + memcached/redis as the marker. Have your app mark the ip in memcached/redis so nginx knows not to bother Node/PHP/Ruby/Python next time."Never" doesn't make sense.
On the other hand, it's not simply "a performance optimization" as there is no way for node to handle a DDoS without crazy amounts of hardware relative to what iptables|nginx can handle.
Notice how "rate-limiting" is a much more generic concept.
For example, Hacker News rate-limits the amount of posts you can make in a window of time. That's not because they think you're trying to DoS them.
You are looking for django/ruby on rails.
The diversity of the Node.js ecosystem is great because there is clear change and innovation. It's bad, however, because some of that innovation is simply taking things done by other frameworks and poorly implementing them in libraries or other frameworks. The lack of general consensus potentially hurts adoption by those of us who work with Django/Rails and perpetuates the myth of the JS world changing every hour/day/week.
More likely is that the people who want the features of Django/Rails just use Django/Rails, so there's no goldrush to recreate them in Node nor a monolithic community around the attempts so far.
The Node ecosystem is like the Clojure ecosystem: all-inclusive frameworks just aren't as popular as library composition.
Express is a nice small framework and is good for some things. Sometimes though you really want a monolith. If you are a Node developer there isn’t a clear choice for this.
I actually enjoy Sails, but I can see some decisions they’ve made that probably aren’t attractive to new developers (such as still using Grunt by default).
Waterline is nice as an ORM on the surface, but you run into walls as your queries become significantly complex.
I'm also interested in a NodeJS version of something like that even though express is very straightforward once you've worked out all the modules you need.
https://github.com/konstructorjs/konstructor It is still in it's very early stages. Thoughts welcome!
> But still a bunch that I haven't gotten to googling and still need to decide on what to choose:
logging (morgan vs winston)
validation (express-validator, joi)
auth (passport jwt, local, social)
session storage (redis vs keeping it in database?)
database (mongo/mongoose vs
pg/knex/bookshelf/sequelize, graphql) storage (s3 vs gcs)
ajax requests (request vs axios)
mail (mailgun, sendgrid, mailchimp)
error handlers
rate limiting
geo iplogging - morgan vs winston - popularities seem similar, although winston has a bit of a lead: https://npmcharts.com/compare/morgan,winston
validation - express-validator vs joi - joi no question: https://npmcharts.com/compare/express-validator,joi
SQL ORMs - sequelize and knex were neck and neck for a while, but sequelize seems to have pulled ahead in the last couple months. bookshelf is way behind. https://npmcharts.com/compare/knex,bookshelf,sequelize
For example, I left the Rails world hungering for tiny, composable solutions like Clojure's Ring and Node's Koa.
I ended up preferring to just see glue code in my git diffs. For me and the small teams I work on, there's a lot of productivity to be gained when you can just look at the code and understand what's going on.
You end up with bespoke glue code per application, but the glue is generally simple so I didn't reap much reward from using a framework that tries to hide it at all cost.
That's basically what Google did on the front end with Angular for people who had the exact same problem with React. Maybe we'll see something like this happen on Backend Javascript, I mean there is Sails, but it doesn't "just work" as well as Angular does on the frontend.
At this point I have a repo that I keep somewhat up to date and then fork the repo for any new projects.
Every time I start a new express app I feel like I'm working at the 'wrong level of abstraction' to put it in Dan Abramov's words about the React ecosystem. I end up writing the same boilerplate over and over.
The only solution I have is a bare bones repo that I keep up to date myself. Not a great solution, but it's a solution.
I am starting a new project soon and I played with Sails. I really liked it, except I struggled with the user authentication part.
Also worried that the momentum of the project seems to have slowed down a bit, Mike does a lot but seems a bit lonely... Or?
I do agree with another poster in that if you want a opinionated just works stack, use Ruby or Python.
Mega-frameworks are, in my experience, one of the biggest sources of encouraging Bad Practices just because their the favorite idiom of the developers.
Rails is infamous for this.
Node (and JavaScript) already has a big enough problem encouraging good code practices that a Rails framework would do untold damage.
The closest it has now is Express (obviously not the same) and that’s already pretty bad for doing what I mention (vastly superseded by Koa and Hapi anyhow).
These things create a very dangerously myopic gravity.
The micro module route Node, JS , and npm uses is - I feel - much much more flexible and beneficial long term.
In some ways we benefit. Sometimes its harder to replace us not just because of skill, but because of countless layers of byzantine and mundane information we’ve memorized about a system. It just not cost effective to stuff all of that crap into someone else’s brain if you don’t have to.
However whenever there is a way to reduce the cruft to productivity ratio, the power is staggering. That’s your “10x” developer right there, someone who gets to actually think a higher percentage of the time.
It is designed to work perfectly with Promises and async/await, the new ES7 features that makes asynchronous code awesome. Also, I put a lot of work into making the documentation extensive and clear and I'll keep working on that for the future while preparing for the 1.1.
Edit, release notes: https://medium.com/server-for-node-js/server-js-1-0-released...
socket.send('login', [uname, pass], (err) => ...)
And there are socket-io clients for most languages that can interop with a socket-io server, once again supporting message_id callbacks.Reconciling my own message_id + reconnect buffer system is not something I want to build on the client + server every time I build an application.
People talk shit about socket.io and then never recommend an alternative that implements this fundamental feature. Without message_ids, I get flashbacks to working with IMAP.
The real reasoning is browser support. Socket.io supports automatic fallback to AJAX long polling if the client doesn't support websockets. It also standardizes the interface across clients. It's essentially to websockets what jQuery is to the DOM.
It means that your initial setup takes a bit longer, but it forces you to understand all the moving parts.
The session in production tutorial makes no mention of secret rotation, which I'd consider an important detail for a production environment. The docs don't mention the feature either, but if you look at the underlying express-session library you see that the secret can either be a string or an array of strings.
Although redis is an amazing tool, I disagree with recommending it as the first choice for a session store. Unless you really need it or plan on using it for more stuff, you'd probably be better off keeping sessions in whatever data store you're using for the rest of the application. That lets you avoid having to setup and maintain yet another tool.
No documentation at all for how the socket.io stuff is supposed to be configured. Chat tutorial assumes a single-node environment, which I'd consider unreasonable for anything outside of a hackathon. Wouldn't you at the very least want a process per core?
About session rotation, it was my impression that it is a smaller problem compared to how it can be exploited if we're using cookies [1][2], could you share some more info about it please?
About Redis, I totally agree. You can add any store that you want with the plain `{ session: { store: ... } }` option. There is an issue though for some of them that need the original `session` passed in which I'll have to fix. So the main fix would really to improve the documentation to explain how to use the appropriate store.
Finally about socket.io, I also agree. I am not a large-scale system expert, so this is part of my limitations and that's why I recommend server.js for small-to-medium sized projects. Long-term I am working on improving on my knowledge here, but not the highest priority right now (compared to security for instance). Also, socket.io right now is not stable officially, so use with care. I'd love any help in here if you want to share some of your expertise.
[1] https://stackoverflow.com/questions/2846401/does-session-id-...
[1] : https://github.com/franciscop/server/blob/master/package.jso...
I think around express 3 the guys decided to go with a modular approach and decouple the server from any of those heavy ( render ) libraries, as well as body-parser ( once it was core module in express itself ).
My really friendly feedback is that I think express carries so much experience that it will be really hard to replace it with something so monolithic. I use express for REST APIs as well as full web app, where I need no render engine and having this installed on my server is an overkill.
Best approach I would think of is having someone rewrite express from scratch and call it express 5, while keeping the same balance of core and extra functionality, as well as new async / promise goodies.
An extra render engine does not affect on anything except on file size (and a tiny bit of install time), which is cheap nowadays. If you are making a single big project server might not be the best option, since you might want to fine-tune many things. If you are making several projects per year with Node.js then it is perfect, since you don't want to waste time doing the same thing again and again.
As others commented, express 5 with async/await = Koa.js
BTW, bodyParser was just added back into the core of express.
The initial idea is to do the next level express framework using back-then generator functions. What is missing ( for me ) is the smaller community and popularity. So it makes it tough to argue about the business impact between choosing koa over express.
Honestly, being a nodeJS freelancer for the last decade there was not a single project, where koa was in use. Mostly I've seen express or sailsjs [http://sailsjs.com] which is quite a full-blown MVC Rails style solution.
- server: return something to reply to the browser. Can use `async` for more advanced features.
- express: reply.send() is fairly straightforward. next() for middleware is a new concept but conceptually in the right place (when you are digging a bit deeper in the middleware).
- Koa: yield, function with asterisk, etc.
So I think Koa is fine for devs who have been a while in JS dev, but the learning curve is too steep to get started. Same as what happens with React and the reason create-react-app has become so popular.
And `await` is so much easier and safer than callbacks in userland code! Really excited about Node.js in 2018, now that `await` is supported in the LTS release. Callback hell is finally dead.
(Diff showing a refactor of an example app from traditional callbacks to async/await: https://github.com/mikermcneil/chatkin/pull/4/files)
https://github.com/ChALkeR/notes/blob/master/Do-not-underest...
Haven't used it in production but replaced Express with it in some side projects.
Since server.js is built on top of express it might even be possible to build a variant of it on Fastify instead and get those benefits as well.
It looks like as if Express wanted to become more like Koa (obvious from the context object). Frankly, it has missed out - koa's simplicity and elegance is unmatched. The routing and middleware syntax is particularly clunky.
Documentation seems really nice though.
But that is not why I created server. It is not about library elegance and simplicity, it's all about making it easy to use. Both of Express and Koa involve external middleware that the user has to manage manually, and there is a subset that is really common for most situations. Server.js is all about usage simplicity, including this subset by default and making things work by default.
Context was inspired initially by the way Promises work with a single return value, but then expanded further (and named after) Koa's context.
But I do try to do batteries-included, because express-like workflow involves following a bunch of steps that are basically the same for most projects.
Edit, maybe you are interested on Sails: https://sailsjs.com/
2. You could say npm is the framework.
3. You could say Adonisjs did kick off (pretty good if you wanted a laravel clone)
4. Mainstream webdev in Node is younger, so a clear rails clone is not evident but could already exist under your nose.
5. Maybe front end frameworks are the new "MVC frameworks". You can make both SPAs, MPAs, and hybrid SPA/MPAs with nuxtjs and nextjs. Do you need a full backend MVC framework to do what your frontend framework already does, but better?
> [insert the latest framework here] that just works so you can focus on your awesome project
Also, ask any Lisper about "being modern".
I can't wait till somebody rebuilds it in Typescript or at least around async
In Koa, handlers don't respond to the request. Instead, they update a representation of the response and return a promise. The response bubbles up to the top-level where the `res.send()` is done.
This way you have real middleware. You can post-process the response or do something else entirely after the downstream has run.
const middleware = async (ctx, next) => {
console.log('request going down')
await next()
console.log('request coming up')
}I'm super-interested, but I'd like to know at a deeper level what this gets us over plain Express.
Long-term I would like to reduce this and have some ideas in mind, but right now this is not an issue.
How could the package name "server" be available all these years :D?
I wrote an article called "Getting a great npm name": https://medium.com/server-for-node-js/getting-a-great-npm-na...
[1] http://blog.npmjs.org/post/141577284765/kik-left-pad-and-npm