Smithy TypeScript

repository·main·Indexed 43 days ago

https://github.com/smithy-lang/smithy-typescript

Reference implementations of Smithy code generators for TypeScript, enabling the creation of extensible Client SDKs and type-safe Server SDKs. Includes packages for HTTP handlers (@smithy/fetch-http-handler, @smithy/node-http-handler), server runtime components (@smithy/server-common), and AWS Lambda integration via @smithy/server-apigateway.

Tokens
47.3K
Snippets
119
Records
254
Agent score
55%

What's inside Smithy TypeScript

  1. Overview of Smithy TypeScript

    main

    Smithy TypeScript provides reference implementations of Smithy code generators for TypeScript. It is currently in Developer Preview, meaning interfaces and supported JavaScript platforms are subject to change.

    Key components include:

    • typescript-client-codegen plugin: Generates extensible TypeScript clients supporting multiple platforms (Node.js >= 20, Browser, and React-Native).
    • typescript-server-codegen plugin: Generates high-level, type-safe server scaffolding.
    • typescript-codegen plugin: Provides unified and types-only code generation.
  2. Overview of @smithy/server-common

    main

    The @smithy/server-common library provides the runtime components for Smithy schema-based server SDKs in TypeScript. It is currently in alpha, meaning breaking changes may occur between minor versions in the 0.x range.

    Key features include:

    • SchemaServiceHandler request pipeline
    • Protocol implementations (Smithy RPC v2 CBOR, AWS REST JSON, AWS JSON RPC)
    • Routing and input validation
    • Interceptors, auth scheme support, and metrics integration.
  3. Use @smithy/fetch-http-handler for browser applications

    main

    The @smithy/fetch-http-handler package provides the default requestHandler implementation designed specifically for browser environments. It leverages the standard Fetch API available in modern browsers to handle HTTP requests within Smithy-generated clients.

    Note on Node.js usage: While you can use this package in Node.js (v16.5.0+ for experimental Web Streams, v21.0.0+ for stable), it is not recommended. For Node.js environments, you should use @smithy/node-http-handler instead.

  4. Understand the purpose of @smithy/signature-v4

    main

    The @smithy/signature-v4 package provides an implementation of the AWS Signature Version 4 authentication scheme.

    Note: This package is primarily intended for internal use by Smithy-TypeScript generated clients. It is not generally intended for standalone usage outside of the context of a generated client. If you require custom authentication logic, you should inspect the SignatureV4 class interface.

  5. Understand the differences between Traditional and Schema-based Server SDKs

    main

    Smithy TypeScript provides two approaches for building Server SDKs (SSDKs). While the Traditional SSDK relies heavily on code generation (creating specific classes for each input and handler), the New Schema-based SSDK uses the Smithy schema to drive behavior.

    Key Architectural Differences

    • Protocol Support: The Schema SSDK supports multi-protocol environments. Using createCombinedRouter, a single server can handle RPC v2, AWS JSON RPC, and HTTP binding routers simultaneously via automatic protocol claiming.
    • Handler Signature: In the Schema SSDK, handlers receive metadata through a dedicated context argument rather than requiring interceptor wiring. The signature is: handler(input, serverCtx, userCtx).
    • Error Handling: The Schema SSDK uses a unified onError hook which replaces the traditional ValidationCustomizer. This hook handles validation errors, authentication failures, and handler exceptions in one place.
    • Metadata Access: The ServerRequestContext provides typed access to headers, path, query, operation name, and caller identity.
    • Validation: The Schema SSDK uses validateServerSchema to traverse the schema (checking length, range, pattern, uniqueItems, and required fields) rather than relying solely on static .validate() methods on generated classes.

    Known Limitations

    • Per-operation configuration: The Schema SSDK uses a single service-level handler. This means all operations share one authentication and interceptor chain, unlike the Traditional SSDK where each operation can have independent configuration.
    • Event Streams: Neither the Traditional nor the Schema-based SSDK currently supports event streams.
  6. Implement Event Stream Operations (Streaming)

    main

    The schema-based server supports Amazon Event Stream wire format for three streaming patterns. In TypeScript, streaming members appear as AsyncIterable<T>.

    Streaming Patterns

    PatternClient sendsServer sends
    Output-onlyNormal requestEvent stream response
    Input-onlyEvent stream requestNormal response
    BidirectionalEvent stream requestEvent stream response

    Implementation Guide

    • Output-only: Return an async generator for the response stream.
    • Input-only: Use for await to consume the incoming stream.
    • Bidirectional: Use for await to consume the input and return an async generator for the output.

    Note on Lambda: AWS Lambda does not support incoming request streams or bidirectional streams. Output-only streams are supported via Lambda response streaming (awslambda.streamifyResponse) with HTTP API (v2). For full support, use @smithy/server-node on EC2/ECS/Fargate.

    const serviceHandler = new MyServiceHandler({
      protocols: [/* ... */],
      handlers: {
        // Output-only
        async SubscribeToEvents(input) {
          return {
            subscriptionId: "sub-123",
            events: (async function* () {
              yield { notification: { topic: "news", payload: "update" } };
            })(),
          };
        },
    
        // Input-only
        async PublishEvents(input) {
          let count = 0;
          for await (const event of input.events) {
            count++;
          }
          return { eventCount: count, message: "Done" };
        },
    
        // Bidirectional
        async Chat(input) {
          const inputMessages = input.messages;
          return {
            sessionId: "session-1",
            messages: (async function* () {
              for await (const msg of inputMessages) {
                yield { response: { text: `Got: ${msg.message?.text}` } };
              }
            })(),
          };
        },
      },
    });
  7. Use the unified onError hook for error handling in Schema-based SSDK

    main

    In the Schema-based Server SDK, the onError hook is the primary mechanism for managing errors. It is a more powerful successor to the traditional ValidationCustomizer because it covers multiple error types in a single callback:

    • Validation Errors: Errors arising from schema violations.
    • Authentication Failures: Errors occurring during the auth phase.
    • Handler Exceptions: Errors thrown by the business logic within the handler itself.

    You can use this hook to suppress specific errors or replace them with custom error responses per-operation.

  8. Understand the generated client directory structure

    main

    When generating a client, the artifacts are organized into a specific structure. If you are generating custom files (like paginators or waiters), it is recommended to use a separate directory for separation of concerns.

    A typical generated structure includes:

    • src/commands/: Individual command classes.
    • src/models/: Types and interfaces exported from the Smithy model.
    • src/runtimeConfig*.ts: Platform-specific runtime configurations (Shared, Node.js, Browser, React-Native).
    • src/index.ts: The main entry point.
    • package.json and tsconfig*.json: Configuration files for the generated package.
    build/smithy/source/typescript-client-codegen/
    ├── package.json
    ├── src
    │   ├── Weather.ts
    │   ├── WeatherClient.ts
    │   ├── commands/
    │   ├── extensionConfiguration.ts
    │   ├── index.ts
    │   ├── models/
    │   ├── pagination/
    │   ├── runtimeConfig.browser.ts
    │   ├── runtimeConfig.native.ts
    │   ├── runtimeConfig.shared.ts
    │   ├── runtimeConfig.ts
    │   └── runtimeExtensions.ts
    ├── tsconfig.cjs.json
    ├── tsconfig.es.json
    ├── tsconfig.json
    └── tsconfig.types.json
  9. How the generated GreetingServiceHandler works

    main

    The generated server SDK provides a subclass of SchemaServiceHandler. You implement the business logic by providing async functions for every operation defined in your Smithy model. The handler abstracts away HTTP request/response transformations and provides typed inputs and outputs.

    When implementing the handler, you provide a handlers object where each key corresponds to an operation. Each handler function receives:

    • input: The typed input shape for the operation.
    • context: A ServerRequestContext object.
    • userContext: A generic context object provided during instantiation.
    // Generated code example
    export class GreetingServiceHandler<Context = {}> extends SchemaServiceHandler<Context> {
      constructor(
        options: SchemaServiceHandlerOptions<Context> & {
          handlers: {
            SayHello: (
              input: SayHelloInput,
              context: ServerRequestContext,
              userContext: Context
            ) => Promise<SayHelloOutput>;
            GetItem: (input: GetItemInput, context: ServerRequestContext, userContext: Context) => Promise<GetItemOutput>;
          };
        }
      ) {
        super({
          ...options,
          validationEnabled: options.validationEnabled ?? true,
          operationSchemas: options.operationSchemas ?? OPERATION_SCHEMAS,
        });
      }
    
      public async handle(request: HttpRequest, context: Context): Promise<HttpResponse>;
    }
  10. Understand the @smithy/core package structure

    main

    The Smithy TypeScript monorepo is being consolidated into the @smithy/core package. Instead of importing many small, individual packages, most core functionality is now organized into submodules managed via package.json exports metadata.

    When building with Smithy TypeScript, you should look for the specific submodule relevant to your needs (e.g., core/client, core/config, core/retry) within the @smithy/core package. This structure provides a unified way to access core infrastructure while maintaining logical boundaries.

  11. Java Codegen Performance Best Practices

    main

    For developers working on the Java source code (specifically the "codegen" components):

    • Cache KnowledgeIndex: Optimize performance by creating and reusing KnowledgeIndex objects to avoid repeated service model traversals for static information.
    • Logging: Avoid excessive logging to the WARN and INFO channels to prevent performance degradation.