Giter Club home page Giter Club logo

hyper-express's People

Contributors

adonespitogo avatar armouti avatar benjaco avatar bompus avatar dadibit avatar dalisoft avatar geo25rey avatar hookyns avatar imlunahey avatar jiahonzheng avatar joacub avatar jonasfroeller avatar kartikk221 avatar kemperrr avatar michaeljcole avatar moufmouf avatar nolway avatar omgimalexis avatar piliugin-anton avatar pkaminski avatar reedham avatar snowbldr avatar snyk-bot avatar stevemcfarlin avatar supremetechnopriest avatar taratritt avatar tayler-king avatar tripodsgames avatar viper-bit avatar vpalmisano avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hyper-express's Issues

Windows 10 Git Bash

npm i hyper-express

npm ERR! code EBUSY
npm ERR! syscall rmdir
npm ERR! errno -4082
npm ERR! EBUSY: resource busy or locked, rmdir 'C:\Users\Scott\AppData\Lo
m-cache_cacache\tmp\git-clone-692bf3f6'

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\Scott\AppData\Local\npm-cache_logs\2021-10-24T21_1
60Z-debug.log

Q: How to set custom fields for request

Hey! @kartikk221 could you please suggest how to assign some field to a request object and fix types issue.

There are a lot of middleware which can extend request object for some reasons.

For example I want to set a custom field uid:

apiRouter.get('/test', (req, res) => {
  req.uid = 'test_uid'; // <- How to extend HyperExpress.Request type to support it?
});

Is it a properly way?

Can't stream a body of unknown size

In 5.1 streaming was added, but it's not usable for my use case because the body is of unknown size and too large to store in memory.

Please implement streaming in a way that can be used for a body of unknown size.

Cannot run within Docker

Describe the bug
Successfully run hyper-express in localhost, with node.js v16.0.0
Cannot run Hyper-express inside Docker, with node:16.0.0

To Reproduce

  1. Create express.js app
  2. run docker build and docker run

below is the Dockerfile

FROM node:16.0.0
WORKDIR /usr/src/app

COPY package*.json ./
COPY ./src ./src
COPY ./videos ./videos

# RUN apk add --update --no-cache git gcompat gettext
RUN npm ci --only=production


CMD npm start
EXPOSE 3000

Logs
This is output of Docker logs

> [email protected] start
> node ./src/index.js

node:internal/modules/cjs/loader:943
  throw err;
  ^

Error: Cannot find module 'hyper-express'
Require stack:
- /usr/src/app/src/index.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:940:15)
    at Function.Module._load (node:internal/modules/cjs/loader:773:27)
    at Module.require (node:internal/modules/cjs/loader:1012:19)
    at require (node:internal/modules/cjs/helpers:93:18)
    at Object.<anonymous> (/usr/src/app/src/index.js:1:22)
    at Module._compile (node:internal/modules/cjs/loader:1108:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1137:10)
    at Module.load (node:internal/modules/cjs/loader:988:32)
    at Function.Module._load (node:internal/modules/cjs/loader:828:14)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:76:12) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [ '/usr/src/app/src/index.js' ]
}

method post body

the post method has a slight error in the req.json() section,

which sometimes can read the body sometimes not

I tried host api on heroku but in local work

here's the video issue

simplescreenrecorder-2021-12-05_04.30.39.mp4

Hyper-express with deno

Deno is a modern runtime for JavaScript and TypeScript. It would be great If we can use hyper-express with deno. Please consider my feature request.

Private Messaging with Websockets

Hi, how would one go about implementing private messaging?
In socket.io you would save and retrieve the sockets in redis and then do something like io.to(receiver_of_message).emit(....)

How would you do this here?

Do you have the scalable hyper-express server and client example?

Hi Karthik,

First of all, I haven't tried hyper-express or even uWebsockets. I normally use socket.io along with PM2 and Redis if scalable architecture needed. I liked your efforts and develop a hypre-express. I appreciate this middleware application and also that its on top of uWebsockets.js, which is high performance. I would like to know if there is a scalable example of server and client, say for the clients sending many messages and file streaming say about 100Mb (take any size).

  1. It should allow the normal GET POST requests
  2. It should allow creating two sockets one for normal message and another for file sharing in same client, with login check (point 5)
  3. Ensuring that all cores are used and scalable if I install another machine, say like socket-io/pm2 and Redis adapters.
  4. CORS requests configuration
  5. session / cookie / any other way, with authentication like passport.js (standard email password use case, with email to new registration, validation of it, login and logout, along with session)
  6. data from Redis and Sqlite database (based on whether the normal DB or in-memory DB is needed
  7. the routing needed, obviously for GET POST requests

Nothing fancy needed, just

Can you help with that? I tried to check your contact details like email id but couldn't get it, so logging as an issue.

Keep up the great work! I am following you to check the updates.

You can delete this request and update your id, if you wish to connect.

A simple question...

I read at nanoexpress faq about performance issue.

Why nanoexpress slower than express on my server
First, please, make sure your server has at least 2-cores and you not using any free hosting as these may be limitation, but not limitation of nanoexpress nor uWebSockets.js itself.
If your logic is slow, try optimize them first, example, your SQL is slow and you call it 10-x in 3 request? Try cache requests as possible

What is the minimal infrastructure to use uWebSocket based solutions like hyper-express ?? A docker with 1 cpu/core could be a problem ?

Request undefined

I saw you found a tricky way to instantiate classes more performant. Also you have a typo in Response.js, line 1001, there should be Response.prototype, not Request.prototype

set_error_handler doesn't handle string rejections

Not sure if this is a bug or an expected limitation.

In express I use express-promise-router to add this. Would be nice to see this built into hyper-express.

const HyperExpress = require('hyper-express');
const webserver = new HyperExpress.Server();

// Works
webserver.get('/works', () => {
    throw new Error('Hello World');
});

// Never responds
webserver.get('/not-working', async () => {
    await new Promise((_resolve, reject) => {
        return reject('Hello World');
    });
});

// This is only called for the thrown error but not the rejection
webserver.set_error_handler((_request, _response, error) => {
    console.log('error', error);
});

webserver.listen(80)
.then(() => console.log('Webserver started on port 80'))
.catch(() => console.log('Failed to start webserver on port 80'));

CORS Preflight doesn't works

Hi,

I'm using Express's CORS module to use CORS but it doesn't seem to work the problem seems to be in the OPTIONS method of hyper-express

When using a global middleware it doesn't listen for OPTIONS method so the preflight request never makes it to the server

Catch all route doesn't work either

webserver.options('*', (req, res) => {
	console.log(req)
})

It only works when you explicitly match the path like this but this isn't maintainable you'd have to repeat it for all routes

webserver.options('/api/login, (req, res) => {
	console.log(req)
})

Router support

First off, good job, I love the idea of a uWebsockets.js library with the express api.
I would like to know if you have any plans to add support for routers, I use them a lot and I want to move my projects to hyper-express asap.

Typescript types ?

Hii @kartikk221, amazing project. Have couple of questions.

  • Do we have TS definitions for the API ?
  • Can we have discussions open for this repo, will easy for discussions on certain topics
    Thanks

JWT Middleware Types

What is the proper way to resolve type errors when using the jwt-express middleware?

For now I used an unsafe cast to make it work:

import express, { MiddlewareHandler } from 'hyper-express';
import jwt from 'express-jwt';

const server = new express.Server();
server.use(jwt() as unknown as MiddlewareHandler);

I guess this question also holds for other third party middlewares (e.g. bodyParser).

Feature request: Method to get current webserver port

I currently need to install uWebsockets myself to have access to the us_socket_local_port method.

Here's an example of this based on the Hello World example.

const HyperExpress = require('hyper-express');
const { us_socket_local_port } = require('uWebSockets.js');
const webserver = new HyperExpress.Server();

// Create GET route to serve 'Hello World'
webserver.get('/', (request, response) => {
    response.send('Hello World');
})

// Activate webserver by calling .listen(port, callback);
webserver.listen(0)
.then((socket) => console.log('Webserver started on port %s', us_socket_local_port(socket)))
.catch((error) => console.log('Failed to start webserver'));

Something like webserver.getPort() would be nice.

Middleware for "/"

There is a bug (or feature?) when I try to add a middleware for route "/" it will be called for any route because it's matched in ...startsWith() call

Issues about CORS

Hi Karthik,

the scenary:

  • implementing CORS using Express CORS v2.8.5 middleware
  • Hyper-Express v5.9.1

the details: package CORS index.js line 178: res.statusCode = options.optionsSuccessStatus;

I faced some little issues:

  1. CORS middleware tries to set a value to property statusCode which doesn't have setter on Response class (only getter).
(node:44869) UnhandledPromiseRejectionWarning: TypeError: Cannot set property statusCode of #<Response> which has only a getter
    at cors (/Users/henrique/node/poc-uWebSocket/hyper/node_modules/cors/lib/index.js:178:24)
    at /Users/henrique/node/poc-uWebSocket/hyper/node_modules/cors/lib/index.js:224:17
    at originCallback (/Users/henrique/node/poc-uWebSocket/hyper/node_modules/cors/lib/index.js:214:15)
    at /Users/henrique/node/poc-uWebSocket/hyper/node_modules/cors/lib/index.js:219:13
    at optionsCallback (/Users/henrique/node/poc-uWebSocket/hyper/node_modules/cors/lib/index.js:199:9)
    at Object.corsMiddleware [as middleware] (/Users/henrique/node/poc-uWebSocket/hyper/node_modules/cors/lib/index.js:204:7)
  1. even though exists a setter (I try one), I take an exception if I passed a number value. There is a trick to solve this: optionsSuccessStatus can be configured through options as string even though can be a number too.
(node:44934) UnhandledPromiseRejectionWarning: Error: Text and data can only be passed by String, ArrayBuffer or TypedArray.
    at Response._initiate_response (/Users/henrique/node/poc-uWebSocket/hyper/node_modules/hyper-express/src/components/http/Response.js:321:51)
    at Response.send (/Users/henrique/node/poc-uWebSocket/hyper/node_modules/hyper-express/src/components/http/Response.js:409:18)

I will suggested add a setter to statusCode with string type check in Response class. So, CORS plugin would work 100%.

This is more a doubt...

When hyper-express is installed, it automatically brings the uWebSockets.js package into the project.
Installing only hyper-express left the project with around 60Mb. 57Mb is just uWebSockets.js (Express 4 doesn't come close to 2Mb)
So I went to the uWebSockets.js folder and realized that binaries had been downloaded for many platforms: linux x64 / arm64, darwin x64 / arm64 and windows, for a total of 20 binaries.
If I'm running on macOS, I don't need the binaries from other platforms. I can delete these other binaries.
But... the question: for macOS Intel there are 4 files: uws_darwin_x64_83.node, uws_darwin_x64_88.node, uws_darwin_x64_93.node and uws_darwin_x64_102.node. Even if I delete some, one of them will suit me and hyper-express will still work fine.

What are these files exactly?

Static files serving (Nginx/Apache style)

Thanks for your work, I'm trying to use your code (trying to create a separate HTTP(S) only library) to serve static files (like Nginx or Apache), just want to measure the performance.

For single requests in browser it works as expected, but under high load (autocannon -c 2500 -d 30 -p 4 http://HOST:PORT) I got tons of errors:

Error: Invalid access of discarded (invalid, deleted) uWS.HttpResponse/SSLHttpResponse. at Response._initiate_response (/something/Response.js:261:26) at Response.stream (/something/Response.js:469:10) at Object.middleware (/something/middleware/StaticFiles.js:101:20)

.options conflicts with .options()

I'm trying to set the preflight CORS headers prior to a POST call to the same endpoint, and having trouble establishing the .options(path, func) method - node complains that webserver.options is not a function.

It would appear the method to establish a router for the OPTIONS method conflicts with the Server/Router options object?

Other calls such as webserver.get(), webserver.post() etc all work fine, but webserver.options() does not work. Docs suggest it should?

const webserver = new HyperExpress.Server({})

webserver.post('/hello', (request, response) => {
    return response.send('hi there')
})

webserver.options('/hello', (request, response) => {
    return response.header('Access-Control-Allow-Origin', '*').header('Access-Control-Allow-Headers', 'Content-Type, X-My-Header-Here')
})

Global middleware fails to call next() on a route with route-specific middleware(s) if 2nd param is a variable to an options object

HyperExpress v6.4.4 on Node 16.15.1

TypeError: middleware.middleware is not a function
    at Route.handle (/home/bobby/src/safe.fiery.me/node_modules/hyper-express/src/components/router/Route.js:89:37)
    at iterator (/home/bobby/src/safe.fiery.me/node_modules/hyper-express/src/components/router/Route.js:79:22)
    at /home/bobby/src/safe.fiery.me/controllers/middlewares/RateLimiter.js:47:16

That error will throw on every requests, assuming the following scenario:

RateLimiter.js is a synchronous global middleware that will call next() if it passes,
and the route is specified like so:

const routes = new Router()
const options = { max_body_length: 100 * 1e6 }
routes.post('/upload', options, auth.optionalUser, upload.upload)
routes.post('/upload/:albumid', options, auth.optionalUser, upload.upload)

which, according to https://github.com/kartikk221/hyper-express/blob/6.4.4/docs/Router.md#router-instance-methods, should conform to the following overload type:

any(String: pattern, Object: options, Function | Function[]: ...middleware, Function: handler)

and auth.optionalUser is a generic middleware (sync or async does not appear to matter)

I notice that it does not throw if the object is specified directly into the 2nd param, instead of a variable pointing to it

routes.post('/upload', { max_body_length: 100 * 1e6 }, auth.optionalUser, upload.upload)
routes.post('/upload/:albumid', { max_body_length: 100 * 1e6 }, auth.optionalUser, upload.upload)

The same error would be thrown if route-specific middleware is specified in the object var

const options = {
  max_body_length: 100 * 1e6,
  middlewares: [auth.optionalUser]
}
routes.post('/upload', options, upload.upload)
routes.post('/upload/:albumid', options, upload.upload)

I legitimately don't understand why


EDIT: It appears that the fact that there is another route referencing to the options variable is relevant
If I don't have the 2nd route /upload/:albumid, it just works

I'm guessing the provided object gets tampered with when used on a route, and it ends up in a way that is then no good for use by other routes
Doing the following makes it behave

routes.post('/upload', Object.assign({}, options), upload.upload)
routes.post('/upload/:albumid', Object.assign({}, options), upload.upload)

If it's for performance reason (?), I think it's sufficient to just note the behavior in the docs

Typescript Types

Hello!

Im currently evaluating hyper-express vs nanoexpress. Nanoexpress has some typescript type issues (its written in javascript and provides a d.ts with a bunch of errors). With HyperExpress I cant seem to import any types. For example, trying to write a middleware:

const middleware = (req: ?, res: ?, next: ?) => {
   return next()
}

Are these types exported anywhere?

Thank you

Add 'send' hook to Response

Currently, I see that Response has hooks for abort and complete.

I'd like to request a 'send' hook that gets fired at the top of the Response.send function, after the check to see if the response hasn't already been completed.

This would allow users to add things near the end of every request such as response time headers, set cookies for custom session handlers (similar to fastify-secure-session) , etc.

The current session logic could probably then use a global request start/response send hook, although it would take the performance hit of two hook loops.

Route middleware not working with next() callback

Hi, I made a PoC using express-jwt just calling the route with a missing bearer token.
This lib returns next( new Error(...) ) but its callback is not issued at hyper-express and the response at route sends the json with no error.

const jwt = require('express-jwt');
const HyperExpress = require('hyper-express');
const webserver = new HyperExpress.Server();

webserver.set_error_handler((request, response, error) => {
   return response.status(error.status || 500).send(error.message /* 'Uncaught Error Occured' */);
});

const secret = 'xyz123'; // or any string just to test missing auth header                                          

webserver.listen(5000, '::')
   .then((socket) => console.log('Webserver started on port 5000'))
   .catch((error) => console.log('Failed to start webserver on port 5000'));

webserver.get('/api/v1/get/:id',
   {
      middlewares: [jwt({ secret, algorithms: ['HS256'] })]
   },
   async (request, response) => {
      let headers = request.headers;
      let id = request.path_parameters.id;
      // console.log(id);
      // let body = await request.json(); // we must await as .json() returns a Promise
      // body will contain the parsed JSON object or an empty {} object on invalid JSON

      response
         .status(200).json({ result: 999 });
   });

[Enhancement] HyperExpress.Response should extend http.ServerResponse

Hello, first thanks for your awesome work,

Describe the problem

HyperExpress.Response currently extends Stream.Writable which is fine but not express compatible.
Many famous express libraries use properties/methods of Express.Requests's underlying http.ServerResponse and therefore don't work with a Stream.Writable instance like HyperExpress.Response.

Describe the proposed solution

HyperExpress.Response should extend the http.ServerResponse to make it compatible with famous express libraries that use native properties/methods of Express.Requests's underlying http.ServerResponse.

Alternatives considered

Maybe provide own implementations for such famous express libraries but that could be hard/impossible to manage as there are hundreds of them..

Importance

Would be nice to have - not insane important as it's workaround-able by hijacking the HyperExpress.Response to extend http.ServerResponse.

Additional Information

not provided.

Best regards
UnlimitedBytes

Publish Sub

I have subscribed a ws to a topic but the publish method doesn't exist on the server object.
The publish method exists within the websocket.js object.

method patern isue

I have an issue with Pat Patern

if on regular express

app.get("/api", () => som);

if i open the url

like https://url/api
or https://url/api/

it can but on hyper-express it can't

please make it similar for a pattern like express js

and for url parameters

in express like this can

app.get("/token:id::token/:method", (req, res) => somefunc);

please add this feature

btw sorry my english is bad

Hyper-Express sometimes leaves request connections hanging

Hi, I thought this was a LiveDirectory bug, but it happens even if I comment out the LiveDirectory code.

I am working on integrating passportjs with hyper-express based on the passportjs example I forked here:

https://github.com/MichaelJCole/hyper-express-sessions-passport-local

When I start the server and reload in chrome, almost always the server connections hangs on the '/' doc or some of the static assets. If I reload 20ish times, the assets serve just fine.

To reproduce, try the master branch. I'm using node 14.18.1. Firefox 95.0.2.

image

Am I using this wrong? Thank you!

Topic Publish Example with Hyper-Express

Hi, glad to get this working, but ran into an issue with the ws.publish, do you have an example to show a publish working as expected for this:
publish(String: topic, String|Buffer|ArrayBuffer: message, Boolean: is_binary, Boolean: compress): Publishes the specified message to the specified topic in MQTT syntax.
This is the gist of what I tried using below:

import { createRequire } from "module";
const require = createRequire(import.meta.url);
const HyperExpress = require('hyper-express');
const Server = new HyperExpress.Server();
const Router = new HyperExpress.Router();
Server.listen(8082)
Server.ws('/', (ws) => {

    ws.id = randomUUID()
    ws.subscribe = uTopic
    connections[ws.id] = ws
    connections[ws.id].publish('locationHb', 'you are now subscribed to locationHb') // not sent to client
    ws.publish('locationHb', 'you are now subscribed to LocationHb') // not sent to client
    connections[ws.id].send('Client ID is' + ws.id) //sent to client
    console.log('Number of clients Object.keys(connections).length;', Object.keys(connections).length)
    clientCount = Object.keys(connections).length

    console.log('Client ID is:' + ws.id)
        ws.on('close', () => {
        console.log('Client ID disconnected:' + ws.id)
        delete connections[ws.id];
        })
}

This page discusses using MQTT which is good, but not seeing a clear example https://github.com/kartikk221/hyper-express/blob/master/docs/Websocket.md

I see they are subscribed, but still not receiving messages
image

Thanks

Discussed in #30

Originally posted by debshaw13 December 13, 2021
Does hyper-express have an equivalent function to broadcast (that is available in ws)? For example, using ws, the following code broadcasts data without any connections:

const wss = new WebSocket.Server({ port: 8082 });

wss.broadcast = (data) => {
  wss.clients.forEach((client) => {
    client.send(data);
  });
};

If I replace 'WebSocket' above with 'HyperExpress' (after importing 'hyper-express' of course), I see the following error:

TypeError: Cannot read property 'forEach' of undefined

Would appreciate any advice as to what I am doing wrong. Thank you for the great package, and apologies if this is a newbie question.

Route handler bug

Hi,

The route handler has a bug where it is executed twice when the request body has JSON and the route has a middleware

I have also attached a reproducible demo

With body

curl -X POST localhost:4000/api/profile -d '{ "test": "test" }'

Output:

1659969926326
1659969926326

Without body

curl -X POST localhost:4000/api/profile

Output:

1659969971285

Reproducible Demo

const HyperExpress = require('hyper-express')

const router = new HyperExpress.Router()
const webserver = new HyperExpress.Server()

const useAuthentication = async (request, response, next) => {
    return next()
}

const updateprofile = async (request, response) => {
    console.log(Date.now())
    response.send('ok')
}

router.post('/profile', {
    middlewares: [useAuthentication]
}, updateprofile)

webserver.use('/api/', router)

webserver.listen(4000)

Response event 'close' not emitted when request canceled on client-side

First of all, thanks for HE, it's a pretty neat package!!!

I've been playing around with hyper-express lately and created a middleware to log slow requests. While working on that, I noticed that canceling requests on the client-side doesn't trigger the close event.

This test project was set up with:

  • Node (v17.6.0)
  • hyper-express (v5.9.2)
  • Express (v4.17.3)

Express.js example
https://gist.github.com/bulletinmybeard/02f5be3e2a9e8e92bbed6b8976ec42bb

// Not canceled
GET /slow [STARTED]
timeout cleared
GET /slow [FINISHED] 5,010.347 ms
GET /slow [CLOSED] 5,038.359 ms

-

// Canceled
GET /slow [STARTED]
GET /slow [CLOSED] 1,979.817 ms
timeout cleared

Hyper-Express example
https://gist.github.com/bulletinmybeard/f5620ba22a32d4e2bc020f72cb0f2d1e

// Not canceled
GET /slow [STARTED]
timeout cleared
GET /slow [FINISHED] 5,003.439 ms
GET /slow [CLOSED] 5,033.814 ms

-
// Canceled
GET /slow [STARTED]
timeout cleared

Cheers \w

writeHead implementation differs, causing an error

The implementation of the undocumented expressJS compatibility method Response.writeHead is different than what the express implementation was. The express writeHead takes a status code, an optional reasonPhrase, and an object with all of the headers.

If an existing express application is using this method the way it was implemented in express, it causes the following exception when the end point gets hit:

 Error: Text and data can only be passed by String, ArrayBuffer or TypedArray.
        at /project/node_modules/hyper-express/src/components/http/Response.js:299:75
        at Array.forEach (<anonymous>)
        at /project/node_modules/hyper-express/src/components/http/Response.js:299:37
        at Array.forEach (<anonymous>)
        at Response._initiate_response (/project/node_modules/hyper-express/src/components/http/Response.js:298:40)
        at Response.write (/project/node_modules/hyper-express/src/components/http/Response.js:346:18)

This is because the status code gets used as the header name, and the object containing the headers gets used as the header value.

The writeHead method appears to have been removed from express in 2014 expressjs/express@74f55a8

Given that it's been removed from express, this method should be removed from hyper-express. I think having a missing method is a better user experience, because the fix is to obviously use a different method. The current state is very confusing.

cannot reproduce benchmarks

hey @kartikk221

i cannot quite confirm your benchmarks on Node v16.13.1 / Arch Linux / 44GB RAM / Ryzen 7 Pro (16 core):

image

also tried with Node 17 and got similar results, except NanoExpress failed to start likely due to using an old uWS.js version:

image

Multiple Middleware on Route Hangs

Hey @kartikk221!

I rolled out my new micro services backed by hyper-express and our recent changes and I noticed a bug. I'm trying to track it down, but I might need to tag you in as you are more familiar with this change.

When you define middleware on a specific route, it seems like every other request hangs and eventually fails. Here is a quick and easy reproduction. We should add this to the tests.

import { 
  Server,
  type Request,
  type Response,
  type MiddlewareNext
} from 'hyper-express'

const app = new Server()

app.post(
  '/echo',
  async (req: Request, res: Response, next: MiddlewareNext) => {
    req.body = await req.json()
    next()
  },
 (req: Request, res: Response, next: MiddlewareNext) => {
    res.locals.data = req.body
    next()
  },
 (req: Request, res: Response) => {
    res.status(200).json(res.locals.data)
  }
)

app.listen(3000)

Then if you use Postman to POST to localhost:3000/echo with a request body:

{ "foo": "bar" }

Every other request hangs. Oddly this doesn't happen when you curl which leads me to believe that the socket isn't being closed on the server side.

Any insight?

Request hangs indefinitely if response.send throws an error

I encountered an issue where the request will hang indefinitely (likely causing a memory/connection leak).

This happens when send is called with an invalid body. Normally, the error handler would pick up the failure and send a failure response. However, since the request is marked completed, send returns immediately and doesn't call the end method in the error handler.

Here's an example to reproduce this issue:

const server = new (require('hyper-express')).Server()

server.get('/', (req, res)=>{
    console.log("end point hit")
    res.send({foo:'bar'})
})

server.set_error_handler((req, res, err) => {
    console.log("Error handler hit")
    res.send("this will never send")
})

server.listen(8080)

I think, it might be fixed by not setting completed to true until after raw_response.end is called.

Websocket client crashes server

Hi, I'm getting an error when I

  1. Start a hyper-express server (repro below)
  2. Connect with WebSocket King Client
  3. WAIT 15 seconds or so

The error looks like this, and I think it has something to do with pong.

$ ts-node --transpile-only src/index.ts
Webserver started on port 3002
upgrading connection
user some_user_id connected.
TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received undefined
    at new NodeError (internal/errors.js:322:7)
    at Function.from (buffer.js:334:9)
    at array_buffer_to_string (/home/michael/casefile-studio/node_modules/hyper-express/src/shared/operators.js:51:19)
    at WebsocketRoute.<anonymous> (/home/michael/casefile-studio/node_modules/hyper-express/src/components/ws/WebsocketRoute.js:42:42)
    at WebsocketRoute._on_pong (/home/michael/casefile-studio/node_modules/hyper-express/src/components/ws/WebsocketRoute.js:157:50)
    at uws_options.pong (/home/michael/casefile-studio/node_modules/hyper-express/src/components/ws/WebsocketRoute.js:116:50)
error Command failed with exit code 1.

A minimalish server is this:

import HyperExpress from 'hyper-express'

const PORT = 3002
const webserver = new HyperExpress.Server()

async function runServer() {
  // Upgrade HTTP connection to websocket (not always called, can authenticate)
  webserver.upgrade('/ws/connect', async (request, response) => {
    console.log('upgrading connection')
    response.upgrade({
      user_id: 'some_user_id',
    })
  })

  webserver.ws('/ws/connect', async (ws) => {
    console.log('user ' + ws.context.user_id + ' connected.')
  })

  webserver
    .listen(PORT)
    .then((socket) => console.log(`Webserver started on port ${PORT}`))
    .catch((error) => {
      console.error(`Failed to start webserver on port ${PORT}`)
    })
}

I'm using node 14.18.1 and these packages:

 "dependencies": {
    "hyper-express": "^5.4.0",
    "ts-node": "^9.1.1",
    "typescript": "4"
  },

About benchmarks and lists

First of all, I want to show my humility and respect for the beautiful work you have done.
but i need to ask.

why the absence of hyper-express or even WebSockets in the techempower benchmarks list link

after all, 8.5x more than fastify would guarantee us an excellent position on this list.

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.