Skip to content

Commit

Permalink
Epic: Supporting Express 5 (#1530)
Browse files Browse the repository at this point in the history
Instead of #374 but non-breaking

The express 5 beta 3 is fully operational and tested by community, but
its release is delayed.
The current issue is that it's also outdated comparing to v4.18.2,
having nested dependencies of older versions.

latest tracking issue:
```
expressjs/discussions#233
```

previous one:
```
expressjs/express#5205
```

Latest proposal:
```
expressjs/discussions#160
```

Probably it will be ready in march 🤞🏽  (no, it's not)
```
expressjs/express#5111 (comment)
```
  • Loading branch information
RobinTail authored Sep 10, 2024
1 parent b459c50 commit c5a45b1
Show file tree
Hide file tree
Showing 9 changed files with 252 additions and 137 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

## Version 20

### v20.10.0

- Feat: Supporting Express 5
- Epic news: after 10 years of struggles and anticipations
[Express 5.0.0 is finally released](https:/expressjs/express/releases/tag/v5.0.0);
- The primary a mostly awaited feature is the proper support of asynchronous handlers;
- This version introduces the initial support of Express 5 without breaking changes;
- Notice: the corresponding `@types/express` for the version 5 is not yet released;
- [Instructions on migrating to Express 5](https://expressjs.com/en/guide/migrating-5.html).

### v20.9.2

- Minor syntax adjustments and cleanup;
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ Therefore, many basic tasks can be accomplished faster and easier, in particular
## Technologies

- [Typescript](https://www.typescriptlang.org/) first.
- Web server — [Express.js](https://expressjs.com/).
- Web server — [Express.js](https://expressjs.com/) v4 or v5.
- Schema validation — [Zod 3.x](https:/colinhacks/zod) including [Zod Plugin](#zod-plugin).
- Supports any logger having `info()`, `debug()`, `error()` and `warn()` methods;
- Built-in console logger with colorful and pretty inspections by default.
Expand Down
2 changes: 1 addition & 1 deletion example/example.documentation.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
openapi: 3.1.0
info:
title: Example API
version: 20.9.2
version: 20.10.0-beta.1
paths:
/v1/user/retrieve:
get:
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "express-zod-api",
"version": "20.9.2",
"version": "20.10.0-beta.1",
"description": "A Typescript library to help you get an API server up and running with I/O schema validation and custom middlewares in minutes.",
"license": "MIT",
"repository": {
Expand All @@ -17,6 +17,7 @@
"url": "https:/RobinTail/express-zod-api/issues"
},
"scripts": {
"postinstall": "npx patch-package",
"start": "tsx example/index.ts",
"build": "yarn build:compile && yarn build:tests && yarn build:assets",
"build:compile": "tsup && attw --pack",
Expand Down Expand Up @@ -88,7 +89,7 @@
"@types/express-fileupload": "^1.5.0",
"@types/http-errors": "^2.0.2",
"compression": "^1.7.4",
"express": "^4.19.2",
"express": "^4.18.2 || ^5.0.0",
"express-fileupload": "^1.5.0",
"http-errors": "^2.0.0",
"typescript": "^5.1.3",
Expand Down Expand Up @@ -139,7 +140,7 @@
"eslint-plugin-allowed-dependencies": "^1.0.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^55.0.0",
"express": "^4.19.2",
"express": "^5.0.0",
"express-fileupload": "^1.5.0",
"globals": "^15.3.0",
"http-errors": "^2.0.0",
Expand Down
22 changes: 22 additions & 0 deletions patches/@types+express-serve-static-core+4.19.5.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
diff --git a/node_modules/@types/express-serve-static-core/index.d.ts b/node_modules/@types/express-serve-static-core/index.d.ts
index aee3041..69755e5 100644
--- a/node_modules/@types/express-serve-static-core/index.d.ts
+++ b/node_modules/@types/express-serve-static-core/index.d.ts
@@ -61,7 +61,7 @@ export interface RequestHandler<
req: Request<P, ResBody, ReqBody, ReqQuery, LocalsObj>,
res: Response<ResBody, LocalsObj>,
next: NextFunction,
- ): void;
+ ): void | Promise<void>;
}

export type ErrorRequestHandler<
@@ -75,7 +75,7 @@ export type ErrorRequestHandler<
req: Request<P, ResBody, ReqBody, ReqQuery, LocalsObj>,
res: Response<ResBody, LocalsObj>,
next: NextFunction,
-) => void;
+) => void | Promise<void>;

export type PathParams = string | RegExp | Array<string | RegExp>;

2 changes: 1 addition & 1 deletion src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export class ExpressMiddleware<
}
resolve(provider(request as R, response as S));
};
nativeMw(request as R, response as S, next);
nativeMw(request as R, response as S, next)?.catch(next);
}),
});
}
Expand Down
4 changes: 2 additions & 2 deletions src/server-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const createParserFailureHandler =
if (!error) {
return next();
}
errorHandler.execute({
return errorHandler.execute({
error: isHttpError(error)
? error
: createHttpError(400, makeErrorFromAnything(error).message),
Expand Down Expand Up @@ -111,7 +111,7 @@ export const createUploadParsers = async ({
} catch (error) {
return next(error);
}
uploader({
return uploader({
debug: true,
...options,
abortOnLimit: false,
Expand Down
14 changes: 14 additions & 0 deletions tests/unit/endpoints-factory.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,20 @@ describe("EndpointsFactory", () => {
expect(options).toEqual({ result: "Here is the test" });
});

test("Should handle rejects from async middlewares", async () => {
const factory = new EndpointsFactory(resultHandlerMock);
const middleware: RequestHandler = vi.fn(async () =>
assert.fail("Rejected"),
);
const newFactory = factory[method](middleware);
await expect(() =>
testMiddleware({
middleware: newFactory["middlewares"][0],
}),
).rejects.toThrow(new Error("Rejected"));
expect(middleware).toHaveBeenCalledTimes(1);
});

test("Should operate without options provider", async () => {
const factory = new EndpointsFactory(resultHandlerMock);
const middleware: RequestHandler = vi.fn((req, {}, next) => {
Expand Down
Loading

0 comments on commit c5a45b1

Please sign in to comment.