Skip to content

Commit

Permalink
feat(type-safe-api): faster code generation for typescript websocket …
Browse files Browse the repository at this point in the history
…projects (#846)

* feat(type-safe-api): faster codegen for typescript async infra

Move typescript async infrastructure to the new codegen

* feat(type-safe-api): faster codegen for typescript async handlers

Move typescript async handlers to the new codegen

* feat(type-safe-api): faster codegen for typescript async runtime

Move typescript async runtime to the new codegen

* feat(type-safe-api): faster codegen for typescript websocket client library

Move typescript websocket client library to new codegen

* feat(type-safe-api): faster codegen for typescript async websocket hooks

Move typescript async websocket hooks to the new codegen
  • Loading branch information
cogwirrel authored Oct 8, 2024
1 parent 240aa4a commit e098d97
Show file tree
Hide file tree
Showing 56 changed files with 902 additions and 4,556 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -616,10 +616,19 @@ const buildData = (inSpec: OpenAPIV3.Document, metadata: any) => {
// All operations across all services
const allOperations = _uniqBy(data.services.flatMap(s => s.operations), o => o.name);

// Add top level vendor extensions
const vendorExtensions: { [key: string]: any } = {};
Object.entries(spec ?? {}).forEach(([key, value]) => {
if (key.startsWith('x-')) {
vendorExtensions[key] = value;
}
});

return {
...data,
allOperations,
info: spec.info,
vendorExtensions,
};
};

Expand Down Expand Up @@ -649,19 +658,6 @@ export default async (argv: string[], rootScriptDir: string) => {

const spec = (await SwaggerParser.bundle(args.specPath)) as any;

// TODO: consider ripping out??
Object.entries(spec?.paths ?? {}).forEach(([_path, methods]) => Object.entries(methods ?? {}).forEach(([_method, operation]) => {
// Add helper vendor extensions to make code generation easier for async operations
if (operation?.["x-async"]) {
if (["client_to_server", "bidirectional"].includes(operation?.['x-async']?.direction)) {
operation["x-async-to-server"] = true;
}
if (["server_to_client", "bidirectional"].includes(operation?.['x-async']?.direction)) {
operation["x-async-to-client"] = true;
}
}
}));

// Build data
const data = buildData(spec, JSON.parse(args.metadata ?? '{}'));

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { TypeSafeWebsocketApi, TypeSafeWebsocketApiProps, TypeSafeWebsocketApiIntegration } from "@aws/pdk/type-safe-api";
###TSAPI_WRITE_FILE###
{
"id": "api",
"dir": "<%= metadata.srcDir || 'src' %>",
"name": "api",
"ext": ".ts",
"overwrite": true
}
###/TSAPI_WRITE_FILE###import { TypeSafeWebsocketApi, TypeSafeWebsocketApiProps, TypeSafeWebsocketApiIntegration } from "@aws/pdk/type-safe-api";
import { Construct } from "constructs";
import { OperationConfig, OperationLookup } from "{{#apiInfo}}{{#apis.0}}{{vendorExtensions.x-runtime-package-name}}{{/apis.0}}{{/apiInfo}}";
import { OperationConfig, OperationLookup } from "<%- metadata.runtimePackageName %>";
import * as path from "path";

export type WebSocketApiIntegrations = OperationConfig<TypeSafeWebsocketApiIntegration>;
Expand All @@ -19,7 +27,7 @@ export class WebSocketApi extends TypeSafeWebsocketApi {
...props,
integrations: props.integrations as any,
operationLookup: OperationLookup,
specPath: path.resolve(__dirname, "{{#apiInfo}}{{#apis.0}}{{vendorExtensions.x-relative-spec-path}}{{/apis.0}}{{/apiInfo}}"),
specPath: path.resolve(__dirname, "<%- metadata.relativeSpecPath %>"),
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
###TSAPI_WRITE_FILE###
{
"dir": "<%- metadata.srcDir || 'src' %>",
"name": "functions",
"ext": ".ts",
"overwrite": true
}
###/TSAPI_WRITE_FILE###import { Construct } from "constructs";
import { Duration } from "aws-cdk-lib";
import { SnapStartFunction, SnapStartFunctionProps } from "@aws/pdk/type-safe-api";
import { Code, Function, Runtime, Tracing, FunctionProps } from "aws-cdk-lib/aws-lambda";
import * as path from "path";

<%_ if (vendorExtensions['x-connect-handler']) { _%>
<%_ const language = vendorExtensions['x-connect-handler'].language; _%>
<%_ const isTypeScript = language === 'typescript'; _%>
<%_ const isJava = language === 'java'; _%>
<%_ const isPython = language === 'python'; _%>
/**
* Options for the $ConnectFunction construct
*/
export interface $ConnectFunctionProps extends Omit<<% if (isJava) { %>SnapStart<% } %>FunctionProps, 'code' | 'handler' | 'runtime'> {}
/**
* Lambda function construct which points to the <%- language %> implementation for the websocket connect event
*/
export class $ConnectFunction extends <% if (isJava) { %>SnapStart<% } %>Function {
constructor(scope: Construct, id: string, props?: $ConnectFunctionProps) {
super(scope, id, {
<%_ if (isTypeScript) { _%>
runtime: Runtime.<%- metadata['x-handlers-node-lambda-runtime-version'] %>,
<%_ } else if (isPython) { _%>
runtime: Runtime.<%- metadata['x-handlers-python-lambda-runtime-version'] %>,
<%_ } else if (isJava) { _%>
runtime: Runtime.<%- metadata['x-handlers-java-lambda-runtime-version'] %>,
<%_ } _%>
<%_ if (isTypeScript) { _%>
handler: "index.handler",
<%_ } else if (isPython) { _%>
handler: "<%- metadata['x-handlers-python-module'] %>.__connect.handler",
<%_ } else if (isJava) { _%>
handler: "<%- metadata['x-handlers-java-package'] %>.$ConnectHandler",
<%_ } _%>
code: Code.fromAsset(path.resolve(__dirname, "..",
<%_ if (isTypeScript) { _%>
"<%- metadata['x-handlers-typescript-asset-path'] %>",
"$connect",
<%_ } else if (isPython) { _%>
"<%- metadata['x-handlers-python-asset-path'] %>",
<%_ } else if (isJava) { _%>
"<%- metadata['x-handlers-java-asset-path'] %>",
<%_ } _%>
)),
tracing: Tracing.ACTIVE,
timeout: Duration.seconds(30),
...props,
});
}
}
<%_ } _%>

<%_ if (vendorExtensions['x-disconnect-handler']) { _%>
<%_ const language = vendorExtensions['x-disconnect-handler'].language; _%>
<%_ const isTypeScript = language === 'typescript'; _%>
<%_ const isJava = language === 'java'; _%>
<%_ const isPython = language === 'python'; _%>
/**
* Options for the $DisconnectFunction construct
*/
export interface $DisconnectFunctionProps extends Omit<<% if (isJava) { %>SnapStart<% } %>FunctionProps, 'code' | 'handler' | 'runtime'> {}
/**
* Lambda function construct which points to the <%- language %> implementation for the websocket disconnect event
*/
export class $DisconnectFunction extends <% if (isJava) { %>SnapStart<% } %>Function {
constructor(scope: Construct, id: string, props?: $DisconnectFunctionProps) {
super(scope, id, {
<%_ if (isTypeScript) { _%>
runtime: Runtime.<%- metadata['x-handlers-node-lambda-runtime-version'] %>,
<%_ } else if (isPython) { _%>
runtime: Runtime.<%- metadata['x-handlers-python-lambda-runtime-version'] %>,
<%_ } else if (isJava) { _%>
runtime: Runtime.<%- metadata['x-handlers-java-lambda-runtime-version'] %>,
<%_ } _%>
<%_ if (isTypeScript) { _%>
handler: "index.handler",
<%_ } else if (isPython) { _%>
handler: "<%- metadata['x-handlers-python-module'] %>.__disconnect.handler",
<%_ } else if (isJava) { _%>
handler: "<%- metadata['x-handlers-java-package'] %>.$DisconnectHandler",
<%_ } _%>
code: Code.fromAsset(path.resolve(__dirname, "..",
<%_ if (isTypeScript) { _%>
"<%- metadata['x-handlers-typescript-asset-path'] %>",
"$disconnect",
<%_ } else if (isPython) { _%>
"<%- metadata['x-handlers-python-asset-path'] %>",
<%_ } else if (isJava) { _%>
"<%- metadata['x-handlers-java-asset-path'] %>",
<%_ } _%>
)),
tracing: Tracing.ACTIVE,
timeout: Duration.seconds(30),
...props,
});
}
}
<%_ } _%>
<%_ allOperations.forEach((operation) => { _%>
<%_ if (operation.vendorExtensions && operation.vendorExtensions['x-handler']) { _%>
<%_ const language = operation.vendorExtensions['x-handler'].language; _%>
<%_ const isTypeScript = language === 'typescript'; _%>
<%_ const isJava = language === 'java'; _%>
<%_ const isPython = language === 'python'; _%>
/**
* Options for the <%- operation.operationIdPascalCase %>Function construct
*/
export interface <%- operation.operationIdPascalCase %>FunctionProps extends Omit<<% if (isJava) { %>SnapStart<% } %>FunctionProps, 'code' | 'handler' | 'runtime'> {}
/**
* Lambda function construct which points to the <%- language %> implementation of <%- operation.operationIdPascalCase %>
*/
export class <%- operation.operationIdPascalCase %>Function extends <% if (isJava) { %>SnapStart<% } %>Function {
constructor(scope: Construct, id: string, props?: <%- operation.operationIdPascalCase %>FunctionProps) {
super(scope, id, {
<%_ if (isTypeScript) { _%>
runtime: Runtime.<%- metadata['x-handlers-node-lambda-runtime-version'] %>,
<%_ } else if (isPython) { _%>
runtime: Runtime.<%- metadata['x-handlers-python-lambda-runtime-version'] %>,
<%_ } else if (isJava) { _%>
runtime: Runtime.<%- metadata['x-handlers-java-lambda-runtime-version'] %>,
<%_ } _%>
<%_ if (isTypeScript) { _%>
handler: "index.handler",
<%_ } else if (isPython) { _%>
handler: "<%- metadata['x-handlers-python-module'] %>.<%- operation.operationIdSnakeCase %>.handler",
<%_ } else if (isJava) { _%>
handler: "<%- metadata['x-handlers-java-package'] %>.<%- operation.operationIdPascalCase %>Handler",
<%_ } _%>
code: Code.fromAsset(path.resolve(__dirname, "..",
<%_ if (isTypeScript) { _%>
"<%- metadata['x-handlers-typescript-asset-path'] %>",
"<%- operation.operationIdKebabCase %>",
<%_ } else if (isPython) { _%>
"<%- metadata['x-handlers-python-asset-path'] %>",
<%_ } else if (isJava) { _%>
"<%- metadata['x-handlers-java-asset-path'] %>",
<%_ } _%>
)),
tracing: Tracing.ACTIVE,
timeout: Duration.seconds(30),
...props,
});
}
}
<%_ } _%>
<%_ }); _%>

This file was deleted.

Loading

0 comments on commit e098d97

Please sign in to comment.