sveltejs / kit

web development, streamlined
https://kit.svelte.dev
MIT License
18.45k stars 1.89k forks source link

implement "Upgrade" as a function in a api route to support websocket #12358

Open jacobbogers opened 3 months ago

jacobbogers commented 3 months ago

Describe the problem

One can easy implement GET, PUT in an api route by a function (see below)

import { json } from '@sveltejs/kit';

export function GET() {
    const number = Math.floor(Math.random() * 6) + 1;

    return json(number);
}

Describe the proposed solution

If we implement UPGRADE Protocol_upgrade_mechanism we could implement websockets aswell

this file is in src/route/chat-app/server.js connect with new WebSocket('/chap-app')


// if this file is in src/route/chat-app/server.js

import { json } from '@sveltejs/kit';

// called when http call wants to upgrade to websocket protocol
export function UPGRADE() {

      // this function will be called after successfull upgrade
       return function connection(ws: WebSocket) {

           ws.send('hello');
               ws.onmessage = (event) => {..});
              // other handlers
      }
}

### Alternatives considered

_No response_

### Importance

would make my life easier

### Additional Information

Currently, customers expect some kind of live real time interaction,  a clean solution integrating with sveltekit would be a huge advantage
eltigerchino commented 3 months ago

Would a conditional in the fallback method handler fit your needs? https://kit.svelte.dev/docs/routing#server-fallback-method-handler . Our motivation for adding this was so that sveltekit wouldn't need to check an indefinite list of named exports in the +server file (we only focus on the most commonly used ones)

Conduitry commented 3 months ago

It wouldn't really help, no. Web Sockets are a two-way stream, and you can't make them fit into a Request/Response framework, which is what you'd still have to do with the fallback method handler.

This is basically #1491. It's a hard problem to come up with an API for, and we don't have a solution for it.

jacobbogers commented 3 months ago

Would a conditional in the fallback method handler fit your needs? https://kit.svelte.dev/docs/routing#server-fallback-method-handler . Our motivation for adding this was so that sveltekit wouldn't need to check an indefinite list of named exports in the +server file (we only focus on the most commonly used ones)

That is not how websocket works (read the link in the OP), the UPGRADE request is not a HTTP method, I suggest this handler name because to me it fits more how the kit uses api routes.

jacobbogers commented 3 months ago

It wouldn't really help, no. Web Sockets are a two-way stream, and you can't make them fit into a Request/Response framework, which is what you'd still have to do with the fallback method handler.

actually websockets are designed to piggy back on request/response framework, how we expose things to the developer is either we create a specific context per websocket connection and a singler handler function or a function factory that creates a PERMANENT lived function context for the duration of the websocket connection (the latter my proposed solution)

Fallback would not work because a websocket initial request is just a GET (with some special headers). and normal GET handlers have precedence in sveltekit. the only thing skit should not do is physically close the socket after the request.

I looked at kit code and you can add specific handler names if you want (ofc you need to change skit code for this).

jacobbogers commented 3 months ago

So basically

if kit receives GET + websocket upgrade headerss -> call Upgrade handler if kit receives GET (no specific websocket headers) -> call the usual GET handler

eltigerchino commented 3 months ago

Thanks for all the information on websockets, especially since I don't have much understanding of it yet. Reading through the main websocket issue, it seems there are a few workarounds the community has come up with, such as this one that also handles upgrading the GET requests.

Is it a good idea for the framework to handle these upgrades and for the developer to simply export a websocket function to handle these connections? But, reading the MDN docs on this it seems like more control is needed depending on the raw request or just the Upgrade header?

Might be a good idea to move this discussion to https://github.com/sveltejs/kit/issues/1491 so that we can collect these ideas and brainstorm an API for this.

jacobbogers commented 3 months ago

Last post here, moved to #1491

But, reading the MDN docs on this it seems like more control is needed depending on the raw request or just the Upgrade header?

No the upgrade header is what makes this piggy back on existing http transports (remember the billions of routers and proxies that dont need to be configured to handle websockets). other then this you enter the websocket space and ofc you have full duplex control mechancism and framing protocol you can read about full websocket here rfc6455

From Server perspective you need to:

  1. initiate sending data to client at any time
  2. close connection
  3. receive data from client

From Client perspective:

  1. create connection
  2. send data
  3. receive data from server
  4. close connection

there is no crazy magic going on.