Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(types): make request & response generic and remove express dependency #478

Closed
wants to merge 3 commits into from

Conversation

devanshj
Copy link

@devanshj devanshj commented Oct 24, 2020

So as ya'll might know, http-proxy-middleware is not coupled with express or any other third-party library. But still the types reflect that.

A few problems that pop because of that...

  1. http.createServer(createProxyMiddleware({}))

    ...won't compile when it should

  2. http.createServer(createProxyMiddleware({ onError: (_, request) => { console.log(request.originalUrl.toString()) } }))

    ...shouldn't compile when it does and would create a runtime error "Cannot read property 'toString' of undefined" because originalUrl is express-specific

  3. const myFavLibraryUse = (handler: (request: http.IncomingMessage, response: http.ServerResponse & { doMagic: () => {} }) => void) => {}
     myFavLibraryUse(createProxyMiddleware({ onError: (_, __, res) => res.doMagic() }))

    ...won't compile when it should

  4. A project using http-proxy-middleware but not having express installed won't compile unless with --skipLibChecks because types.ts imports express

The solution to all these problems in making request and response generic which consequently would remove express dependency

This will be a breaking change for the people who...

  1. have written let middleware = createProxyMiddleware({ ... }) (instead of directly passing to use so contextual inference works) AND
  2. and use request, response in any of the options AND
  3. access library exclusive properties or methods on request and response

So it'll be a breaking change only if ALL these three are fulfilled, otherwise there's no problems.
The easiest way to migrate is to directly pass to use. If for any reason the users can't do that, just annotate request and/or response whatever is being used with the library specific types.

Aside: It's my first time doing some server side work with TypeScript and I'm not using express and I see this pattern of libraries having their types depend on express, and not adhering to their source code (that doesn't require express exclusive methods & properties). Like serve-static that I recently fixed. It's probably because it's easy to use express types so it seamlessly works with express (as it's popular) and get done with it, but let's change that ;)

@ghost
Copy link

ghost commented Oct 24, 2020

DeepCode's analysis on #9b8a5a found:

  • ℹ️ 3 minor issues. 👇

Top issues

Description Example fixes
Type declaration of 'any' loses type-safety. Consider replacing it with a more precise type. Occurrences: 🔧 Example fixes
This expression has no effect. Occurrences: 🔧 Example fixes
Disable X-Powered-By header for your Express app (consider using Helmet middleware), because it exposes information about the used framework to potential attackers. Occurrences: 🔧 Example fixes

👉 View analysis in DeepCode’s Dashboard | Configure the bot

) => {
if (this.shouldProxy(this.config.context, req)) {
try {
const activeProxyOptions = await this.prepareProxyRequest(req);
this.proxy.web(req, res, activeProxyOptions);
} catch (err) {
next(err);
next && next(err);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Afaict next(err) could lead to bugs as next could be undefined


export interface RequestHandler extends express.RequestHandler {
export interface RequestHandler<
Request extends http.IncomingMessage = http.IncomingMessage,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making type parameters in all exported types optional to save some possibly unnecessary breaking errors like RequestHandler requires two parameters none passed. More here.

'/proxy',
createProxyMiddleware({
onError: (_, request, response) => {
// todo, non trivial fix @ts-expect-error
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be fixed by sending a PR to @types/connect to have the following change over here

-        use(fn: HandleFunction): Server;
+        use(fn: SimpleHandleFunction): Server;
+        use(fn: NextHandleFunction): Server;
+        use(fn: ErrorHandleFunction): Server;
-        use(route: string, fn: HandleFunction): Server;
+        use(route: string, fn: SimpleHandleFunction): Server;
+        use(route: string, fn: NextHandleFunction): Server;
+        use(route: string, fn: ErrorHandleFunction): Server;

...this would make the inference work. There's no other way to fix it on our end.

Now the question is: Are the improvements in this PR worth having http-proxy-middleware to not work with connect properly? I'm okay with all answers although I would push "Yes" because as http-proxy-middleware should not be responsible for type gotchas of connect, nor should it's users be affected.

@devanshj
Copy link
Author

devanshj commented Oct 24, 2020

Umm is the CI failing because of next && next(err) or next && next() instead of unchecked calls to next? Because that's the only change in runtime code 🤔

Ah silly me didn't realize even types.spec.ts runs, that was causing the errors. That file shouldn't run because that would spawn express, connect and browser-sync servers which is overkill for checking types. Any errors in the file would be automatically caught via tsc so I just renamed it to types-spec.ts.

@coveralls
Copy link

Coverage Status

Coverage increased (+5.7%) to 93.989% when pulling 9b8a5a2 on devanshj:fix-types-remove-express into f212a04 on chimurai:master.

@onichandame
Copy link

aside from internalizing the types, another possible approach is to add express as a peer dependency so that the express types can be reused.

@chimurai chimurai mentioned this pull request Feb 26, 2022
@cdaringe
Copy link

I like the intent of this PR, but it does a few things that aren't ideal.

  • @ts-ignores are a bit of a code smell, imho
  • next. it is a middleware library, thus next is a key param in middleware impls. i think it's fine to keep it in and require it. if this m/w is used as a final handler, folks can always drop in a noop

take a peek @ #721. i'm viewing all of the TS complaint issues, ensuring that #721 appeases all complaints/use-cases, and at this point i think it does, with this one perhaps being the exception, due to the feature request of dropping next

@devanshj
Copy link
Author

devanshj commented Feb 28, 2022

@ts-ignores are a bit of a code smell, imho

I don't know what @ts-ignores you are talking about, the @ts-expect-error are for testing types.

next [...] require it

I just kept the behavior as it is, what you're suggesting is a breaking change afaict. I don't have any opinions on that. Ughh wait I made it optional but it was required previously, I don't remember why I did that, probably because the documentation had the usage without passing next. Anyway I'm fine with keeping it required too.

#721

I haven't checked it but as long as it solves the problem this PR solves I'm good

@chimurai
Copy link
Owner

Fixed in #730

Removal of @types/express will be investigated in separate PR

@chimurai chimurai closed this Mar 20, 2022
@chimurai chimurai mentioned this pull request Feb 22, 2023
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants