Skip to content

Commit b075b59

Browse files
committed
fix: smarter params, nextjs 15 support
1 parent b843249 commit b075b59

File tree

10 files changed

+100
-68
lines changed

10 files changed

+100
-68
lines changed
Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
import {
2-
_GET,
3-
_POST,
4-
} from "../../../generated/todo-lists.yaml/attachments/route"
1+
import {_GET, _POST} from "../../../generated/todo-lists.yaml/attachments/route"
52

6-
export const GET = _GET(async ({}, respond, context) => {
3+
export const GET = _GET(async (respond, context) => {
74
// TODO: implementation
8-
return respond.withStatus(501).body({ message: "not implemented" } as any)
5+
return respond.withStatus(501).body({message: "not implemented"} as any)
96
})
10-
export const POST = _POST(async ({ body }, respond, context) => {
7+
export const POST = _POST(async ({body}, respond, context) => {
118
// TODO: implementation
12-
return respond.withStatus(501).body({ message: "not implemented" } as any)
9+
return respond.withStatus(501).body({message: "not implemented"} as any)
1310
})

integration-tests/typescript-nextjs/src/app/todo-lists.yaml/list/[listId]/items/route.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import {
33
_POST,
44
} from "../../../../../generated/todo-lists.yaml/list/[listId]/items/route"
55

6-
export const GET = _GET(async ({ params }, respond, context) => {
6+
export const GET = _GET(async ({params}, respond, context) => {
77
// TODO: implementation
8-
return respond.withStatus(501).body({ message: "not implemented" } as any)
8+
return respond.withStatus(501).body({message: "not implemented"} as any)
99
})
10-
export const POST = _POST(async ({ params, body }, respond, context) => {
10+
export const POST = _POST(async ({params, body}, respond, context) => {
1111
// TODO: implementation
12-
return respond.withStatus(501).body({ message: "not implemented" } as any)
12+
return respond.withStatus(501).body({message: "not implemented"} as any)
1313
})
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import {
2+
_DELETE,
23
_GET,
34
_PUT,
4-
_DELETE,
55
} from "../../../../generated/todo-lists.yaml/list/[listId]/route"
66

7-
export const GET = _GET(async ({ params }, respond, context) => {
7+
export const GET = _GET(async ({params}, respond, context) => {
88
// TODO: implementation
9-
return respond.withStatus(501).body({ message: "not implemented" } as any)
9+
return respond.withStatus(501).body({message: "not implemented"} as any)
1010
})
11-
export const PUT = _PUT(async ({ params, body }, respond, context) => {
11+
export const PUT = _PUT(async ({params, body}, respond, context) => {
1212
// TODO: implementation
13-
return respond.withStatus(501).body({ message: "not implemented" } as any)
13+
return respond.withStatus(501).body({message: "not implemented"} as any)
1414
})
15-
export const DELETE = _DELETE(async ({ params }, respond, context) => {
15+
export const DELETE = _DELETE(async ({params}, respond, context) => {
1616
// TODO: implementation
17-
return respond.withStatus(501).body({ message: "not implemented" } as any)
17+
return respond.withStatus(501).body({message: "not implemented"} as any)
1818
})
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { _GET } from "../../../generated/todo-lists.yaml/list/route"
1+
import {_GET} from "../../../generated/todo-lists.yaml/list/route"
22

3-
export const GET = _GET(async ({ query }, respond, context) => {
3+
export const GET = _GET(async ({query}, respond, context) => {
44
// TODO: implementation
5-
return respond.withStatus(501).body({ message: "not implemented" } as any)
5+
return respond.withStatus(501).body({message: "not implemented"} as any)
66
})

integration-tests/typescript-nextjs/src/generated/todo-lists.yaml/attachments/route.ts

Lines changed: 3 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

integration-tests/typescript-nextjs/src/generated/todo-lists.yaml/list/route.ts

Lines changed: 1 addition & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/openapi-code-generator/src/typescript/server/server-operation-builder.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export type ServerOperationResponseSchemas = {
5858
}
5959

6060
export type Parameters = {
61+
hasParams: boolean
6162
type: string
6263
path: {
6364
schema: string | undefined
@@ -111,7 +112,16 @@ export class ServerOperationBuilder {
111112
${header.type}
112113
>`
113114

114-
return {type, path, query, header, body}
115+
return {
116+
hasParams: Boolean(
117+
path.schema || query.schema || header.schema || body.schema,
118+
),
119+
type,
120+
path,
121+
query,
122+
header,
123+
body,
124+
}
115125
}
116126

117127
responseValidator(): string {

packages/openapi-code-generator/src/typescript/server/typescript-nextjs/typescript-nextjs-app-router-builder.ts

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,48 @@ import {
44
SyntaxKind,
55
VariableDeclarationKind,
66
} from "ts-morph"
7+
import type {Input} from "../../../core/input"
78
import type {IROperation} from "../../../core/openapi-types-normalized"
8-
import {type HttpMethod, isDefined, isHttpMethod} from "../../../core/utils"
9+
import {
10+
type HttpMethod,
11+
isDefined,
12+
isHttpMethod,
13+
titleCase,
14+
} from "../../../core/utils"
915
import {CompilationUnit, type ICompilable} from "../../common/compilation-units"
1016
import type {ImportBuilder} from "../../common/import-builder"
11-
import {requestBodyAsParameter} from "../../common/typescript-common"
17+
import type {SchemaBuilder} from "../../common/schema-builders/schema-builder"
18+
import type {TypeBuilder} from "../../common/type-builder"
19+
import type {ServerSymbols} from "../abstract-router-builder"
20+
import {ServerOperationBuilder} from "../server-operation-builder"
1221

1322
export class TypescriptNextjsAppRouterBuilder implements ICompilable {
1423
constructor(
15-
public readonly filename: string,
24+
private readonly filename: string,
25+
private readonly name: string,
26+
private readonly input: Input,
1627
private readonly imports: ImportBuilder,
28+
private readonly types: TypeBuilder,
29+
private readonly schemaBuilder: SchemaBuilder,
1730
private readonly companionFilename: string,
1831
private readonly sourceFile: SourceFile,
1932
) {}
2033

2134
private readonly httpMethodsUsed = new Set<HttpMethod>()
2235

2336
add(operation: IROperation): void {
24-
const sourceFile = this.sourceFile
25-
26-
const hasPathParam =
27-
operation.parameters.filter((it) => it.in === "path").length > 0
28-
const hasQueryParam =
29-
operation.parameters.filter((it) => it.in === "query").length > 0
30-
const hasBodyParam = Boolean(
31-
requestBodyAsParameter(operation).requestBodyParameter,
37+
const builder = new ServerOperationBuilder(
38+
operation,
39+
this.input,
40+
this.types,
41+
this.schemaBuilder,
3242
)
3343

44+
const symbols = this.operationSymbols(builder.operationId)
45+
const params = builder.parameters(symbols)
46+
47+
const sourceFile = this.sourceFile
48+
3449
const wrappingMethod = `_${operation.method.toUpperCase()}`
3550

3651
this.httpMethodsUsed.add(operation.method)
@@ -69,20 +84,37 @@ export class TypescriptNextjsAppRouterBuilder implements ICompilable {
6984
parameter.remove()
7085
})
7186

72-
innerFunction?.addParameter({
73-
name: `{${[
74-
hasPathParam ? "params" : undefined,
75-
hasQueryParam ? "query" : undefined,
76-
hasBodyParam ? "body" : undefined,
77-
]
78-
.filter(isDefined)
79-
.join(",")}}`,
80-
})
87+
if (params.hasParams) {
88+
innerFunction?.addParameter({
89+
name: `{${[
90+
params.path.schema ? "params" : undefined,
91+
params.query.schema ? "query" : undefined,
92+
params.body.schema ? "body" : undefined,
93+
params.header.schema ? "headers" : undefined,
94+
]
95+
.filter(isDefined)
96+
.join(",")}}`,
97+
})
98+
}
8199

82100
innerFunction?.addParameter({name: "respond"})
83101
innerFunction?.addParameter({name: "context"})
84102
}
85103

104+
// TODO: duplication - should be shared with router builder
105+
protected operationSymbols(operationId: string): ServerSymbols {
106+
return {
107+
implPropName: operationId,
108+
implTypeName: titleCase(operationId),
109+
responderName: `${titleCase(operationId)}Responder`,
110+
paramSchema: `${operationId}ParamSchema`,
111+
querySchema: `${operationId}QuerySchema`,
112+
requestBodySchema: `${operationId}BodySchema`,
113+
requestHeaderSchema: `${operationId}HeaderSchema`,
114+
responseBodyValidator: `${operationId}ResponseValidator`,
115+
}
116+
}
117+
86118
toString(): string {
87119
return this.sourceFile.getFullText()
88120
}

packages/openapi-code-generator/src/typescript/server/typescript-nextjs/typescript-nextjs-router-builder.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type {Input} from "../../../core/input"
2-
import {titleCase} from "../../../core/utils"
2+
import {isDefined, titleCase} from "../../../core/utils"
33
import type {ImportBuilder} from "../../common/import-builder"
44
import {JoiBuilder} from "../../common/schema-builders/joi-schema-builder"
55
import type {SchemaBuilder} from "../../common/schema-builders/schema-builder"
@@ -67,9 +67,6 @@ export class TypescriptNextjsRouterBuilder extends AbstractRouterBuilder {
6767
protected buildOperation(builder: ServerOperationBuilder): string {
6868
const statements: string[] = []
6969

70-
const types = this.types
71-
const schemaBuilder = this.schemaBuilder
72-
7370
const symbols = this.operationSymbols(builder.operationId)
7471
const params = builder.parameters(symbols)
7572

@@ -107,11 +104,13 @@ export class TypescriptNextjsRouterBuilder extends AbstractRouterBuilder {
107104
}),
108105
buildExport({
109106
name: symbols.implTypeName,
110-
value: `(
111-
params: ${params.type},
112-
respond: ${symbols.responderName},
113-
request: NextRequest,
114-
) => Promise<KoaRuntimeResponse<unknown>>`,
107+
value: `(${[
108+
params.hasParams ? `params: ${params.type}` : undefined,
109+
`respond: ${symbols.responderName}`,
110+
"request: NextRequest",
111+
]
112+
.filter(isDefined)
113+
.join(",")}) => Promise<KoaRuntimeResponse<unknown>>`,
115114
kind: "type",
116115
}),
117116
],
@@ -121,7 +120,7 @@ export class TypescriptNextjsRouterBuilder extends AbstractRouterBuilder {
121120
buildExport({
122121
name: `_${builder.method.toUpperCase()}`,
123122
kind: "const",
124-
value: `(implementation: ${symbols.implTypeName}) => async (request: NextRequest, {params}: {params: Promise<unknown>}): Promise<Response> => {
123+
value: `(implementation: ${symbols.implTypeName}) => async (${["request: NextRequest", params.path.schema ? "{params}: {params: Promise<unknown>}" : undefined].filter(isDefined).join(",")}): Promise<Response> => {
125124
const input = {
126125
params: ${
127126
params.path.schema
@@ -151,7 +150,7 @@ export class TypescriptNextjsRouterBuilder extends AbstractRouterBuilder {
151150
const {
152151
status,
153152
body,
154-
} = await implementation(input, responder, request)
153+
} = await implementation(${[params.hasParams ? "input" : undefined, "responder", "request"].filter(isDefined).join(",")})
155154
.then(it => it.unpack())
156155
.catch(err => { throw KoaRuntimeError.HandlerError(err) })
157156

packages/openapi-code-generator/src/typescript/server/typescript-nextjs/typescript-nextjs.generator.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,11 @@ export async function generateTypescriptNextJS(
105105

106106
const nextJSAppRouterBuilder = new TypescriptNextjsAppRouterBuilder(
107107
nextJsAppRouterPath,
108+
group.name,
109+
input,
108110
imports,
111+
rootTypeBuilder.withImports(imports),
112+
rootSchemaBuilder.withImports(imports),
109113
filename,
110114
sourceFile,
111115
)

0 commit comments

Comments
 (0)