Skip to content

Commit af9a1e7

Browse files
authored
feat: typescript-express server template (#324)
introduces a second server template, `typescript-express` **Tasks** - [x] Template - [x] Runtime - [x] Integration tests - [x] Existing E2E tests - [x] Additional E2E tests - [x] Documentation - [x] Review **Why Express** `express` is one of the most popular server frameworks for NodeJS, getting approximately 10x as many weekly downloads as `koa` Its also quite similar to `koa` making it a good candidate for the second server template. This makes it somewhat less interesting to implement, compared to other options like `nextjs` (#152) but also means that its a good way to prompt refactors like #316 without requiring a bunch of new functionality. **Runtime** It's clear at this point that there is a lot of duplicated code between all the runtimes. I like keeping the separate runtime packages for several reasons: - Dependency declaration / management is cleaner - NPM download trends can function as a rough proxy for adoption / usage _(although private caching registries cause this to under-report significantly)_ It probably makes sense to introduce a `typescript-runtime-common` package soon. **Approach** The approach ends up looking near identical to the `typescript-koa` template, in terms of the end developer experience. This is particularly reinforced by the E2E tests and how little difference exists between the two implementations.
1 parent f529387 commit af9a1e7

File tree

63 files changed

+301503
-48
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+301503
-48
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ and API server scaffolding (routing, validation, serialization) from api specifi
99
Currently, [OpenAPI 3.0](https://swagger.io/specification/v3), [OpenAPI 3.1](https://swagger.io/specification/),
1010
and [TypeSpec](https://typespec.io/) are supported as input specifications.
1111

12-
With typescript templates for [koa](https://openapi-code-generator.nahkies.co.nz/guides/server-templates/typescript-koa), [fetch](https://openapi-code-generator.nahkies.co.nz/guides/client-templates/typescript-fetch), [axios](https://openapi-code-generator.nahkies.co.nz/guides/client-templates/typescript-axios), and [angular](https://openapi-code-generator.nahkies.co.nz/guides/client-templates/typescript-angular) currently available.
12+
With typescript templates for [koa](https://openapi-code-generator.nahkies.co.nz/guides/server-templates/typescript-koa), [express](https://openapi-code-generator.nahkies.co.nz/guides/server-templates/typescript-express), [fetch](https://openapi-code-generator.nahkies.co.nz/guides/client-templates/typescript-fetch), [axios](https://openapi-code-generator.nahkies.co.nz/guides/client-templates/typescript-axios), and [angular](https://openapi-code-generator.nahkies.co.nz/guides/client-templates/typescript-angular) currently available.
1313

1414
The [fetch](https://openapi-code-generator.nahkies.co.nz/guides/client-templates/typescript-fetch) and [axios](https://openapi-code-generator.nahkies.co.nz/guides/client-templates/typescript-axios) templates work great in conjunction with [react-query](https://tanstack.com/query/latest)
1515

@@ -39,6 +39,7 @@ The repository is structured as a mono repo of several npm packages that work to
3939

4040
- [openapi-code-generator](./packages/openapi-code-generator)
4141
- [typescript-axios-runtime](./packages/typescript-axios-runtime)
42+
- [typescript-express-runtime](./packages/typescript-express-runtime)
4243
- [typescript-fetch-runtime](./packages/typescript-fetch-runtime)
4344
- [typescript-koa-runtime](./packages/typescript-koa-runtime)
4445

e2e/scripts/generate.sh

+8
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ yarn openapi-code-generator \
1212
--extract-inline-schemas \
1313
--grouping-strategy first-tag
1414

15+
yarn openapi-code-generator \
16+
--input ./openapi.yaml \
17+
--output ./src/generated/server/express \
18+
--template typescript-express \
19+
--schema-builder "$SCHEMA_BUILDER" \
20+
--extract-inline-schemas \
21+
--grouping-strategy first-tag
22+
1523
yarn openapi-code-generator \
1624
--input ./openapi.yaml \
1725
--output ./src/generated/client/fetch \

e2e/src/express.entrypoint.ts

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import {type NextFunction, type Request, type Response, Router} from "express"
2+
import {bootstrap} from "./generated/server/express"
3+
import {createEscapeHatchesRouter} from "./routes/express/escape-hatches"
4+
import {createRequestHeadersRouter} from "./routes/express/request-headers"
5+
import {createValidationRouter} from "./routes/express/validation"
6+
import {createErrorResponse} from "./shared"
7+
8+
function createRouter() {
9+
const router = Router()
10+
11+
const requestHeadersRouter = createRequestHeadersRouter()
12+
const validationRouter = createValidationRouter()
13+
const escapeHatchesRouter = createEscapeHatchesRouter()
14+
15+
router.use(requestHeadersRouter)
16+
router.use(validationRouter)
17+
router.use(escapeHatchesRouter)
18+
19+
return router
20+
}
21+
22+
export async function startExpressServer() {
23+
const {app, server, address} = await bootstrap({
24+
cors: {
25+
credentials: true,
26+
allowedHeaders: ["Authorization", "Content-Type"],
27+
methods: ["GET", "OPTIONS"],
28+
origin: "http://example.com",
29+
},
30+
router: createRouter(),
31+
notFoundHandler: (req: Request, res: Response, next: NextFunction) => {
32+
res.status(404).json({code: 404, message: "route not found"})
33+
},
34+
errorHandler: (
35+
err: Error,
36+
req: Request,
37+
res: Response,
38+
next: NextFunction,
39+
) => {
40+
if (res.headersSent) {
41+
return next(err)
42+
}
43+
44+
const {status, body} = createErrorResponse(err)
45+
res.status(status).json(body)
46+
},
47+
})
48+
49+
return {app, server, address}
50+
}
51+
52+
if (require.main === module) {
53+
startExpressServer().catch((err) => {
54+
console.error("fatal error", err)
55+
process.exit(1)
56+
})
57+
}

e2e/src/generated/server/express/index.ts

+13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

e2e/src/generated/server/express/models.ts

+46
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

e2e/src/generated/server/express/routes/escape-hatches.ts

+95
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)