{"id":15415821,"url":"https://github.com/davidje13/websocket-express","last_synced_at":"2025-04-19T14:24:16.343Z","repository":{"id":143928553,"uuid":"177453632","full_name":"davidje13/websocket-express","owner":"davidje13","description":"express and ws combined","archived":false,"fork":false,"pushed_at":"2024-10-25T17:52:50.000Z","size":386,"stargazers_count":7,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-08T14:02:52.428Z","etag":null,"topics":["express","expressjs","websocket","ws"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/davidje13.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-03-24T18:33:58.000Z","updated_at":"2024-12-18T19:50:07.000Z","dependencies_parsed_at":null,"dependency_job_id":"5709a08b-f955-42da-8f73-77556a6628d7","html_url":"https://github.com/davidje13/websocket-express","commit_stats":{"total_commits":76,"total_committers":1,"mean_commits":76.0,"dds":0.0,"last_synced_commit":"a4539e77b19cdc2bee4e35c4977476d399c2e202"},"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidje13%2Fwebsocket-express","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidje13%2Fwebsocket-express/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidje13%2Fwebsocket-express/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidje13%2Fwebsocket-express/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/davidje13","download_url":"https://codeload.github.com/davidje13/websocket-express/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249260803,"owners_count":21239663,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["express","expressjs","websocket","ws"],"created_at":"2024-10-01T17:09:46.931Z","updated_at":"2025-04-19T14:24:16.315Z","avatar_url":"https://github.com/davidje13.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WebSocket Express\n\nExtends [express](https://expressjs.com/) with WebSocket capabilities\nfrom [ws](https://github.com/websockets/ws). This allows an easy syntax\nfor handling WebSockets as well as allowing a single server to handle\nboth HTTP and WebSocket requests.\n\nThis project is similar to (and takes some inspiration from\n[express-ws](https://github.com/HenningM/express-ws), but chooses to\nprovide a separate API rather than monkeypatching the express objects,\nand supports asynchronous operations in all locations.\n\n## Install dependency\n\n```bash\nnpm install --save websocket-express ws express @types/ws @types/express\n```\n\n(`ws` and `express` are required as peer dependencies of\n`websocket-express`. You can use `express` version 4 or 5.\n`@types/ws` and `@types/express` must be added even if you\nare not using TypeScript in your project)\n\n## Usage\n\n```javascript\nimport { WebSocketExpress, Router } from 'websocket-express';\n\nconst app = new WebSocketExpress();\nconst router = new Router();\n\n// Simple usage:\nrouter.ws('/path/foo', async (req, res) =\u003e {\n  const ws = await res.accept();\n  ws.on('message', (msg) =\u003e {\n    ws.send(`echo ${msg}`);\n  });\n  ws.send('hello');\n});\n\nrouter.ws('/path/bar', async (req, res) =\u003e {\n  const ws = await res.accept();\n\n  ws.send('who are you?');\n\n  const message = await ws.nextMessage({ timeout: 1000 });\n  ws.send(`hello, ${message.data}`);\n\n  ws.close();\n});\n\n// Asynchronous accept/reject:\nrouter.ws('/path/ws-async', async (req, res, next) =\u003e {\n  const acceptable = await myAsynchronousOperation();\n  if (acceptable) {\n    const ws = await res.accept();\n    ws.send('hello');\n  } else {\n    next();\n  }\n});\n\n// Transactions:\nrouter.ws('/path/transactional', async (req, res) =\u003e {\n  const ws = await res.accept();\n\n  try {\n    res.beginTransaction();\n    ws.send('hello');\n    ws.send('this is a long series of messages');\n    ws.send('and all messages will be sent');\n    ws.send('even if the server is asked to close()');\n    ws.send('although they may be stopped if the server crashes');\n\n    await myAsynchronousOperation();\n\n    ws.send('still included');\n  } finally {\n    res.endTransaction();\n  }\n\n  ws.send('this message might not be included');\n  ws.send('because the transaction has finished');\n});\n\n// Full Router API of express is supported too:\nrouter.get('/path/foo', (req, res) =\u003e {\n  res.end('response to a normal HTTP GET request');\n});\n\n// use sends both HTTP and WS requests to the middleware / router:\napp.use(router);\n\n// useHTTP allows attaching middleware only to HTTP requests:\napp.useHTTP(middleware);\n\n// the setting 'shutdown timeout' can be set to automatically close\n// WebSocket connections after a delay, even if they are in a\n// transaction\napp.set('shutdown timeout', 1000);\n\n// create and run a server:\nconst server = app.createServer();\nserver.listen(8080);\n\n// or attach to an existing server:\nconst server = http.createServer();\napp.attach(server);\nserver.listen(8080);\n```\n\nIf you have a vanilla express `Router` or middleware (e.g. from an\nexternal library), it is recommended to use `useHTTP` rather than `use`\nto attach it, to ensure it is not confused by WebSocket requests.\n\nThe `static`, `json` and `urlencoded` middleware is bundled by default\nand ignores WebSocket requests, so `use` is fine:\n\n```javascript\nimport { WebSocketExpress } from 'websocket-express';\n\nconst app = new WebSocketExpress();\napp.use(WebSocketExpress.static(myDirectory));\n```\n\nExample integration with an external websocket server library (socket.io):\n\n```javascript\nimport { Server } from 'socket.io';\nimport { WebSocketExpress } from 'websocket-express';\n\nconst app = new WebSocketExpress();\napp.ws('/socket.io/*', (req, res) =\u003e res.abandon()); // /socket.io requests are handled by socketioServer\n// register other websocket and non-websocket endpoints as normal\n\nconst server = app.createServer();\nconst socketioServer = new Server(server);\n// configure socketioServer as normal\n\nserver.listen(8080);\n```\n\nNote that if you `abandon` a request which is _not_ handled by another\nlibrary, the connection will hang until the client eventually times out.\nThis may be particularly problematic when shutting down the server:\n`websocket-express` will normally close all remaining websocket\nconnections automatically when `server.close` is called, but it will\nnot close abandoned connections. This may delay the process termination,\nas NodeJS will remain active as long as any connections are open.\n\n## API\n\nThe main method is `Router.ws`. This accepts a (possibly asynchronous)\nfunction with 3 parameters: the request, the response, and a `next`\ncallback to be invoked if the request is rejected for any reason.\n\nIf the request is accepted, the function should call `accept` to get a\nWebSocket, attach `message` and `close` event listeners and can\ncontinue to handle the WebSocket as normal.\n\nIf the request is rejected, `next` should be called (possibly with an\nerror description), and the next possible handler, or the error\nhandler, will be called (according to the standard express logic).\n\nIf no handlers are able to accept a WebSocket request, it will be\nclosed (with code 4404 by default). If you want another library to\nhandle the request (e.g. socket.io), you can call `abandon` to stop\nany further handling of the request.\n\nIf an exception is thrown, the socket will be closed with code 1011.\n\nAs with `get` / `post` / etc. it is possible to register a WebSocket\nhandler under the same URL as a non-websocket handler.\n\n- `Router.useHTTP` / `App.useHTTP` behaves like `Router.use` in\n  express. It will invoke the middleware or router for all\n  non-WebSocket requests.\n\n- `Router.all` is similarly updated to apply only to non-WebSocket\n  requests.\n\n- `Router.use` / `App.use` will invoke the middleware or router for\n  *all* requests.\n\n- `Router.ws` will invoke the middleware only for WebSocket requests.\n\n- `App.createServer` is a convenience method which creates a server and\n  calls `attach` (see below).\n\n- `App.attach` will attach the necessary event listeners to the given\n  server (e.g. if you want to use a https server, or a long-lived\n  server with hot reloading).\n\n- `App.detach` will remove all attached event listeners from the given\n  server.\n\n- `App.set('shutdown timeout', millis)` configures a timeout (in\n  milliseconds) used by `close()`, after which connections will be\n  forced to close even if they are in a transaction.\n\nThe `response` parameter passed to websocket handlers has additional\nmethods:\n\n- `res.accept()` accepts the protocol switch, establishing the\n  websocket connection. This returns a promise which resolves to the\n  newly established websocket.\n\n- `res.reject([httpStatus[, message]])` returns a HTTP error instead\n  of accepting the websocket connection. Defaults to HTTP 500.\n\n- `res.abandon()` stops all further processing of the connection. This\n  should be used if you want to delegate to another library which has\n  also registered an `upgrade` listener on the server. Note that this\n  is provided as an escape hatch; in general you should try to\n  `accept` the connection and pass the websocket to other libraries,\n  as this will handle lifecycle events (such as closing the server)\n  more gracefully.\n\n- `res.sendError(httpStatus[, websocketErrorCode[, message]])` sends\n  a HTTP or websocket error and closes the connection. If no explicit\n  websocket error code is provided and the websocket connection has\n  already been established, this will default to `4000 + httpStatus`\n  (e.g. HTTP 404 becomes websocket error 4404).\n\n- `res.send(message)` shorthand for accepting the connection, sending\n  a message, then closing the connection. Provided for compatibility\n  with the `express` API.\n\n- `res.beginTransaction()` / `res.endTransaction()` mark (nestable)\n  transactions on the websocket connection. While a transaction is\n  active, `websocket-express` will avoid closing the connection\n  (e.g. during server shutdown). These should be used to wrap\n  short-lived sequences of messages which need to be sent together.\n  Do not use these for long-lived operations, as it will delay\n  server shutdown. To ensure `endTransaction` is called, it is\n  recommended that you use the pattern:\n\n  ```javascript\n  try {\n    res.beginTransaction();\n    // transaction code\n  } finally {\n    res.endTransaction();\n  }\n  ```\n\nThe WebSocket returned by `accept` has some additional helper methods:\n\n- `ws.nextMessage` will return a promise which resolves with the next\n  message received by the websocket. If the socket closes before a\n  message arrives, the promise will be rejected. You can also specify\n  a timeout (with `nextMessage({ timeout: millis })`) to reject if no\n  message is received within the requested time.\n\n  The object returned by `nextMessage` has a `data` element (a\n  `String` if using `ws` 7.x and the message is text, or a `Buffer`\n  if the message is binary, or if using `ws` 8.x), and an `isBinary`\n  boolean. You can use `String(message.data)` to convert the `Buffer`\n  to a string using UTF8 encoding, matching `ws` 7.x's behaviour.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavidje13%2Fwebsocket-express","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdavidje13%2Fwebsocket-express","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavidje13%2Fwebsocket-express/lists"}