Skip to content

feat(core/schema): add schema types #1593

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fresh-otters-tickle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@smithy/types": minor
---

add types for schemas
3 changes: 3 additions & 0 deletions packages/types/src/command.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Handler, MiddlewareStack } from "./middleware";
import { MetadataBearer } from "./response";
import { OperationSchema } from "./schema/schema";

/**
* @public
Expand All @@ -13,6 +14,8 @@ export interface Command<
> extends CommandIO<InputType, OutputType> {
readonly input: InputType;
readonly middlewareStack: MiddlewareStack<InputType, OutputType>;
readonly schema?: OperationSchema;

resolveMiddleware(
stack: MiddlewareStack<ClientInput, ClientOutput>,
configuration: ResolvedConfiguration,
Expand Down
3 changes: 3 additions & 0 deletions packages/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export * from "./pagination";
export * from "./profile";
export * from "./response";
export * from "./retry";
export * from "./schema/schema";
export * from "./schema/sentinels";
export * from "./serde";
export * from "./shapes";
export * from "./signature";
Expand All @@ -30,6 +32,7 @@ export * from "./streaming-payload/streaming-blob-payload-input-types";
export * from "./streaming-payload/streaming-blob-payload-output-types";
export * from "./transfer";
export * from "./transform/client-payload-blob-type-narrow";
export * from "./transform/mutable";
export * from "./transform/no-undefined";
export * from "./transform/type-transform";
export * from "./uri";
Expand Down
345 changes: 345 additions & 0 deletions packages/types/src/schema/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,345 @@
import type { EndpointV2 } from "../endpoint";
import type { HandlerExecutionContext } from "../middleware";
import type { MetadataBearer } from "../response";
import type { EndpointBearer, SerdeFunctions } from "../serde";
import type {
BigDecimalSchema,
BigIntegerSchema,
BlobSchema,
BooleanSchema,
DocumentSchema,
NumericSchema,
StreamingBlobSchema,
StringSchema,
TimestampDateTimeSchema,
TimestampDefaultSchema,
TimestampEpochSecondsSchema,
TimestampHttpDateSchema,
} from "./sentinels";
import type { TraitBitVector } from "./traits";

/**
* A schema is an object or value that describes how to serialize/deserialize data.
* @public
*/
export type Schema =
| UnitSchema
| TraitsSchema
| SimpleSchema
| ListSchema
| MapSchema
| StructureSchema
| MemberSchema
| OperationSchema
| NormalizedSchema;

/**
* Traits attached to schema objects.
*
* When this is a number, it refers to a pre-allocated
* trait combination that is equivalent to one of the
* object type's variations.
*
* @public
*/
export type SchemaTraits = TraitBitVector | SchemaTraitsObject;

/**
* A schema that has traits.
*
* @public
*/
export interface TraitsSchema {
name: string;
traits: SchemaTraits;
}

/**
* Simple schemas are those corresponding to simple Smithy types.
* @see https://smithy.io/2.0/spec/simple-types.html
* @public
*/
export type SimpleSchema =
| BlobSchemas
| StringSchema
| BooleanSchema
| NumericSchema
| BigIntegerSchema
| BigDecimalSchema
| DocumentSchema
| TimestampSchemas
| number;

/**
* Sentinel value for Timestamp schema.
* "Default" means unspecified and to use the protocol serializer's default format.
*
* @public
*/
export type TimestampSchemas =
| TimestampDefaultSchema
| TimestampDateTimeSchema
| TimestampHttpDateSchema
| TimestampEpochSecondsSchema;

/**
* Sentinel values for Blob schema.
* @public
*/
export type BlobSchemas = BlobSchema | StreamingBlobSchema;

/**
* Signal value for the Smithy void value. Typically used for
* operation input and outputs.
*
* @internal
*/
export type UnitSchema = "unit";

/**
* See https://smithy.io/2.0/trait-index.html for individual definitions.
*
* @public
*/
export type SchemaTraitsObject = {
idempotent?: 1;
idempotencyToken?: 1;
sensitive?: 1;
sparse?: 1;

/**
* timestampFormat is expressed by the schema sentinel values of 4, 5, 6, and 7,
* and not contained in trait objects.
* @deprecated use schema value.
*/
timestampFormat?: never;

httpLabel?: 1;
httpHeader?: string;
httpQuery?: string;
httpPrefixHeaders?: string;
httpQueryParams?: 1;
httpPayload?: 1;
/**
* [method, path, statusCode]
*/
http?: [string, string, number];
httpResponseCode?: 1;
/**
* [hostPrefix]
*/
endpoint?: [string];

xmlAttribute?: 1;
xmlName?: string;
/**
* [prefix, uri]
*/
xmlNamespace?: [string, string];
xmlFlattened?: 1;
jsonName?: string;

mediaType?: string;
error?: "client" | "server";

[traitName: string]: unknown;
};

/**
* Schema for the structure aggregate type.
* @public
*/
export interface StructureSchema extends TraitsSchema {
name: string;
traits: SchemaTraits;
members: Record<string, [SchemaRef, SchemaTraits]>;
}

/**
* Schema for the list aggregate type.
* @public
*/
export interface ListSchema extends TraitsSchema {
name: string;
traits: SchemaTraits;
valueSchema: SchemaRef;
}

/**
* Schema for the map aggregate type.
* @public
*/
export interface MapSchema extends TraitsSchema {
name: string;
traits: SchemaTraits;
keySchema: SchemaRef;
valueSchema: SchemaRef;
}

/**
* @public
*/
export type MemberSchema = [SchemaRef, SchemaTraits];

/**
* Schema for an operation.
*
* @public
*/
export interface OperationSchema extends TraitsSchema {
name: string;
traits: SchemaTraits;
input: SchemaRef;
output: SchemaRef;
}

/**
* Normalization wrapper for various schema data objects.
* @internal
*/
export interface NormalizedSchema extends TraitsSchema {
name: string;
traits: SchemaTraits;
getSchema(): Schema;
getName(): string | undefined;
isMemberSchema(): boolean;
isListSchema(): boolean;
isMapSchema(): boolean;
isStructSchema(): boolean;
isBlobSchema(): boolean;
isTimestampSchema(): boolean;
isStringSchema(): boolean;
isBooleanSchema(): boolean;
isNumericSchema(): boolean;
isBigIntegerSchema(): boolean;
isBigDecimalSchema(): boolean;
isStreaming(): boolean;
getMergedTraits(): SchemaTraitsObject;
getMemberTraits(): SchemaTraitsObject;
getOwnTraits(): SchemaTraitsObject;
/**
* For list/set/map.
*/
getValueSchema(): NormalizedSchema;
/**
* For struct/union.
*/
getMemberSchema(member: string): NormalizedSchema | undefined;
getMemberSchemas(): Record<string, NormalizedSchema>;
}

/**
* A schema "reference" is either a schema or a function that
* provides a schema. This is useful for lazy loading, and to allow
* code generation to define schema out of dependency order.
* @public
*/
export type SchemaRef = Schema | (() => Schema);

/**
* A codec creates serializers and deserializers for some format such as JSON, XML, or CBOR.
*
* @public
*/
export interface Codec<S, D> extends ConfigurableSerdeContext {
createSerializer(): ShapeSerializer<S>;
createDeserializer(): ShapeDeserializer<D>;
}

/**
* Configuration for codecs. Different protocols may share codecs, but require different behaviors from them.
*
* @public
*/
export type CodecSettings = {
timestampFormat: {
/**
* Whether to use member timestamp format traits.
*/
useTrait: boolean;
/**
* Default timestamp format.
*/
default: TimestampDateTimeSchema | TimestampHttpDateSchema | TimestampEpochSecondsSchema;
};
/**
* Whether to use HTTP binding traits.
*/
httpBindings?: boolean;
};

/**
* Turns a serialization into a data object.
* @public
*/
export interface ShapeDeserializer<SerializationType = Uint8Array> extends ConfigurableSerdeContext {
/**
* Optionally async.
*/
read(schema: Schema, data: SerializationType): any | Promise<any>;
}

/**
* Turns a data object into a serialization.
* @public
*/
export interface ShapeSerializer<SerializationType = Uint8Array> extends ConfigurableSerdeContext {
write(schema: Schema, value: unknown): void;

flush(): SerializationType;
}

/**
* A client protocol defines how to convert a message (e.g. HTTP request/response) to and from a data object.
* @public
*/
export interface ClientProtocol<Request, Response> extends ConfigurableSerdeContext {
/**
* @returns the Smithy qualified shape id.
*/
getShapeId(): string;

getRequestType(): { new (...args: any[]): Request };
getResponseType(): { new (...args: any[]): Response };

/**
* @returns the payload codec if the requests/responses have a symmetric format.
* It otherwise may return null.
*/
getPayloadCodec(): Codec<any, any>;

serializeRequest<Input extends object>(
operationSchema: OperationSchema,
input: Input,
context: HandlerExecutionContext & SerdeFunctions & EndpointBearer
): Promise<Request>;

updateServiceEndpoint(request: Request, endpoint: EndpointV2): Request;

deserializeResponse<Output extends MetadataBearer>(
operationSchema: OperationSchema,
context: HandlerExecutionContext & SerdeFunctions,
response: Response
): Promise<Output>;
}

/**
* Allows a protocol, codec, or serde utility to accept the serdeContext
* from a client configuration or request/response handlerExecutionContext.
*
* @public
*/
export interface ConfigurableSerdeContext {
setSerdeContext(serdeContext: SerdeFunctions): void;
}

// TODO(schema): transports are not required in the current implementation.
// /**
// * @public
// */
// export interface Transport<Request, Response> {
// getRequestType(): { new (...args: any[]): Request };
// getResponseType(): { new (...args: any[]): Response };
//
// send(context: HandlerExecutionContext, request: Request): Promise<Response>;
// }
Loading
Loading