question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Start using FastifyRequest objects for the upgrade request so hooks fire and decorators can be used

See original GitHub issue

🚀 Feature Proposal

fastify-websocket currently passes the raw http.IncomingMessage into websocket route handlers, not a FastifyRequest object. I think instead passing a FastifyRequest to handlers would improve a number of things.

Motivation

First off, it is unfortunate to not have access to FastifyRequest’s basic helpers. The higher level object is more useful than the raw IncomingMessage and has some handy doodads for getting say route params or the logger to work with. Second, fastify promotes and has a really healthy ecosystem of things that decorate FastifyRequest that websocket handlers also can’t access. Things like a session from fastify-secure-session, utilities from fastify-url-data, or user-land decorators to get a database client or what have you aren’t available in route handlers.

Finally, it’s unfortunate that hooks don’t run for websocket handlers. We’d have to discuss semantically how this might work, but, if we could come up with sane semantics for this, it’d be really handy. I want to use hooks to implement authorization for example – deny requests based on the presence of a session value or whatever. This same logic needs to apply to work done over normal HTTP requests as well as work done over websocket connections, but currently I have to duplicate it in a hook and in a verifyClient option. One place (especially one place that had access to decorators) would be simpler.

I also think there’s an argument to be made that websocket handlers being different like this violates the principle of least surprise.

How

This’d definitely be a breaking change, so knowing that, we’d either introduce a new API or just do a major version bump. With that, I think it’d be possible to actually implement this by using ws ability to bind to an existing http.Server, as is detailed here: https://www.npmjs.com/package/ws#external-https-server

I think for an UPGRADE request we’d probably not want to provide a FastifyReply object, or we’d want to change the API to use FastifyReply to actually start the websocket connection. I think there’s really only one thing you want to do with an upgrade request, which is delegate it to the websocket server, so I think having to do that manually isn’t really worth it, and that it’s a special enough scenario that having a different handler signature is actually a good thing anyways. So I’d suggest having websocket handlers look pretty similar to how the do right now.

Hooks wise, the semantics that make sense to me are firing everything up until the reply is sending. So, onRequest, preParsing, preValidation, preHandler, preSerialization, and onError could all be relied on, but onSend and onResponse would never be called and would be documented as such. I am not really familiar with Fastify’s internals enough to say how hard it would be to actually do this weird half-chain of hooks, but were that easy enough, this makes sense to me.

Context

I don’t really know why fastify-websocket works the way it does right now, but if I had to guess, I’d say it’s because its really simple to implement. That’s not a bad reason. I am finding that I have to do more work in userland because of this though, and I think implementing this inside the library instead of in bespoke and crappy ways outside it each time would save devs lots of time.

Thoughts?

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:4
  • Comments:14 (9 by maintainers)

github_iconTop GitHub Comments

1reaction
airhornscommented, Dec 16, 2020

I see what you mean, it does remove some noise for creating websocket handlers, but I think the mission of this library should be to make more possible as opposed to just making the common case easier. I think some folks might want access to the connection object instead of just the socket, and I think the PRs linked above remove the need to work with the params as a separate object, and would pass in a FastifyRequest with the params already set up fine.

1reaction
airhornscommented, Dec 16, 2020

@adminy can you be more specific about what you’d like to see? I don’t really understand.

Nobody needs to know that websockets is actually a get request upgrade.

I kind of disagree. That’s how they work, there’s no other way to initiate them, you can’t around this. Let’s say you want to build authentication for websocket connections to your server. If your server already serves normal authenticated HTTP requests, you already have some way to look at an HTTP request and figure out who is making it and if you trust them, lets say through cookies and fastify-secure-session. A really easy way to authenticate websocket requests would be to use the exact same mechanism, and look at the cookies for the incoming upgrade request. You can only do that because there’s a request, and if you are given the request. Forcing users of this library to re-build authentication or any of their middleware/plugin stack in a websocket-specific way just because the transport is different seems unnecessary and wasteful.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Decorators - Fastify
The decorators API allows customization of the core Fastify objects, such as the server instance itself and any request and reply objects used...
Read more >
When Using Fastifysession And Fastifywebockets How To Get ...
When using fastifywebsocket it needs to be registered before all routes in ... objects for the upgrade request so hooks fire and decorators...
Read more >
How to use the fastify-decorators.GET function in fastify ... - Snyk
To help you get started, we've selected a few fastify-decorators.GET examples, based on popular ways it is used in public projects.
Read more >
Decorators - Fastify
Note: using an arrow function will break the binding of this to the Fastify request instance. ¶Usage Notes. decorateReply and decorateRequest are used...
Read more >
Upgrading the guest room: 5 things you need to know
Provide ample blankets and pillows so your guests can gauge their comfort levels on the bed as they please, and be sure to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found