-
Notifications
You must be signed in to change notification settings - Fork 120
Description
Description
When a Smithy operation has a @required @httpQuery parameter, the generated SSDK throws UnknownOperationException instead of ValidationException when the parameter is missing from the request.
Expected Behavior
A request missing a required query parameter should return a ValidationException with details about the missing field.
Actual Behavior
The request fails to match any operation in HttpBindingMux, resulting in UnknownOperationException with message: "request did not match the expected service operation".
Root Cause
The HttpBindingMux uses required query parameters as part of operation routing/matching, not just validation. In UriSpec.match():
for (const querySegment of this.querySegments) {
if (!(querySegment.key in req.query)) {
return false; // Routing fails here
}
}This means the mux cannot distinguish between:
- A genuinely unknown operation
- A known operation with missing required query parameters
Deeper Issue: Query Params Used for Routing Instead of Validation
The SSDK generates both:
- Per-operation handlers (e.g.,
GetResourceHandler) - one Lambda per operation - Monolithic service handler (
MyServiceHandler) - single Lambda for all operations
In both cases, the mux includes required query params for routing:
// Monolithic handler mux - routes between operations
const mux = new HttpBindingMux([
new UriSpec('GET',
[{ type: 'path_literal', value: "item" }],
[{ type: 'query', key: "id" }], // Used for routing!
{ operation: "GetItem" }
),
new UriSpec('PUT',
[{ type: 'path_literal', value: "item" }],
[],
{ operation: "UpdateItem" }
),
]);The mux legitimately needs to distinguish operations on the same path with different methods. But using required query params for this distinction is wrong - they should be validated after routing, not used for routing.
Meanwhile, the SSDK does generate proper validation for required query params:
case "id": {
memberValidators["id"] = new CompositeValidator([
new RequiredValidator(),
]);
break;
}But this validation runs after the mux, so it never executes when the query param is missing.
Reproduction
Smithy model:
@http(method: "GET", uri: "/resource")
@readonly
operation GetResource {
input: GetResourceInput
}
structure GetResourceInput {
@required
@httpQuery("id")
id: String
}Request:
GET /resource
Expected response:
{
"__type": "ValidationException",
...
}Actual response:
{
"__type": "UnknownOperationException",
...
}Suggested Fix
The mux should only use path and method for routing. Required query params should be handled by validation, not routing. Options:
- Don't include
@required@httpQueryparams in muxquerySegments- only use query params for routing when they disambiguate operations (e.g.,@httpQueryParamswith literal values) - Two-pass matching - match on path/method first, then return partial match info for missing query params so the handler can throw
ValidationException
Environment
@aws-smithy/server-common- TypeScript SSDK