Skip to content

[Storage] Support fine-grained parameter augmentation in client.tsp #1012

Description

@vincenttran-msft

Motivation / Current State

@@override is the only tool available when the change touches an operation's parameter list, and it is an all-or-nothing replacement:

  • Full clones for tiny changes. To change one parameter we must copy the operation's complete signature. The single intended edit is buried in a large duplicate.
  • Risk of definition drift. The override is a static snapshot. When the base operation changes (new parameter, new response header, route change, new API version), the override silently goes stale and must be kept in sync by hand. Nothing enforces parity.
  • Repeated across many operations. In a single service client.tsp this pattern recurs for numerous operations, each a large clone that exists to change one small thing.
  • Duplicated suppressions. Any suppressions applied to the definition in routes.tsp must be restated here.

Concrete example

In the Storage Blob client.tsp, making the metadata header required for Rust on container setMetadata requires a full operation redefinition.

alias MetadataHeadersRequired = {
  /** The metadata headers. */
  @alternateType(Record<string>, "rust")
  @header("x-ms-meta")
  metadata: string; // <-- the ONLY intended change vs. the base op, now required dropping the '?'
};

#suppress "@azure-tools/typespec-azure-core/use-standard-operations" "Existing API"
#suppress "@azure-tools/typespec-azure-core/no-response-body" "Existing API"
#suppress "@azure-tools/typespec-azure-core/use-standard-names" "Existing API"
@put
@sharedRoute
@route("?restype=container&comp=metadata")
op setMetadataRequiredMetadataContainer is StorageOperationNoBody<
  {
    ...TimeoutParameter;
    ...LeaseIdOptionalParameter;
    ...MetadataHeadersRequired;
    ...IfModifiedSinceParameter;
  },
  {
    ...EtagResponseHeaderPrivate;
    ...LastModifiedResponseHeaderPrivate;
  }
>;

@@override(Container.setMetadata, setMetadataRequiredMetadataContainer, "rust");

This is not a one-off

The same shape repeats throughout this single file: each a full operation clone whose only real purpose is a one-parameter delta:

  • setMetadataRequiredMetadataContainer (container setMetadata, Rust): making the metadata header required instead of optional (metadata?metadata).
  • setMetadataRequiredMetadataBlob (blob setMetadata, Rust): same as above
  • setAccessPolicyRequiredContainerAcl (container setAccessPolicy, Rust): containerAcl request body required instead of optional.
  • appendBlockNoStructuredMessage (append appendBlock, Rust): omitting the structured-message parameters (not yet implemented) from the request.
  • stageBlockNoStructuredMessage (block stageBlock, Rust): same as above
  • uploadPagesNoStructuredMessage (page uploadPages, Rust): same as above

Why every one of these requires a full clone today

All six deltas are parameter-level edits- flip one parameter's optionality or drop a couple of parameters from the request. None of them touch the route, the response shape, or the rest of the parameter list. Yet each currently require a full redefinition of 99% the same functionality but augmenting a handful of parameters. This also, as mentioned above, become a maintenance nightmare given that these are handwritten and must be maintained alongside the actual routes.tsp definition.

Metadata

Metadata

Assignees

No one assigned

    Labels

    StorageStorage Service (Queues, Blobs, Files)feature-requestThis issue requires a new behavior in the product in order be resolved.

    Projects

    Status
    Untriaged

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions