Skip to content

Commit

Permalink
feat(type-safe-api): include error header expected by smithy generate…
Browse files Browse the repository at this point in the history
…d client in handler wrappers (#468)

Clients generated directly from Smithy (using the typescript-codegen plugin) can deserialise error
responses into the appropriate generated model classes, but they do this by checking for a special
`x-amzn-errortype` header. This change updates the generated handler wrappers to include the
appropriate value for this header for error responses. Note that OpenAPI specs generated from Smithy
add "ResponseContent" as a suffix to all response data types, so we remove this in order to match
the appropriate error structure ID. If the response data type doesn't end with ResponseContent, it
didn't come from Smithy so there's no need to return this header anyway.

re #460
  • Loading branch information
cogwirrel authored Jun 13, 2023
1 parent 751ddf5 commit 293fab0
Show file tree
Hide file tree
Showing 6 changed files with 234 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,11 @@ public class Handlers {
private {{operationIdCamelCase}}{{code}}Response({{#dataType}}final {{#isPrimitiveType}}String{{/isPrimitiveType}}{{^isPrimitiveType}}{{.}}{{/isPrimitiveType}} body, {{/dataType}}final Map<String, String> headers) {
this.body = {{#dataType}}{{#isPrimitiveType}}body{{/isPrimitiveType}}{{^isPrimitiveType}}body.toJson(){{/isPrimitiveType}}{{/dataType}}{{^dataType}}""{{/dataType}};
this.headers = headers;
{{^is2xx}}
if ("{{dataType}}".endsWith("ResponseContent")) {
this.headers.put("x-amzn-errortype", "{{dataType}}".substring(0, "{{dataType}}".length() - "ResponseContent".length()));
}
{{/is2xx}}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,18 @@ def {{operationId}}_handler(_handler: {{operationIdCamelCase}}HandlerFunction =
interceptor_context,
), **kwargs)

response_headers = response.headers or {}
response_body = ''
if response.body is None:
pass
{{#responses}}
elif response.status_code == {{code}}:
{{^isPrimitiveType}}
response_body = json.dumps(JSONEncoder().default(response.body))
{{^is2xx}}
if "{{dataType}}".endswith("ResponseContent"):
response_headers["x-amzn-errortype"] = "{{dataType}}"[:-len("ResponseContent")]
{{/is2xx}}
{{/isPrimitiveType}}
{{#isPrimitiveType}}
response_body = response.body
Expand All @@ -244,7 +249,7 @@ def {{operationId}}_handler(_handler: {{operationIdCamelCase}}HandlerFunction =

return {
'statusCode': response.status_code,
'headers': response.headers,
'headers': response_headers,
'body': response_body,
}
return wrapper
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,33 @@ export const {{nickname}}Handler = (
return marshalledBody;
};

const errorHeaders = (statusCode: number): { [key: string]: string } => {
let headers = {};

switch(statusCode) {
{{#responses}}
{{^is2xx}}
case {{code}}: {
if ("{{dataType}}".endsWith("ResponseContent")) {
headers["x-amzn-errortype"] = "{{dataType}}".slice(0, -"ResponseContent".length);
}
break;
}
{{/is2xx}}
{{/responses}}
default:
break;
}

return headers;
};

return {
...response,
headers: {
...errorHeaders(response.statusCode),
...response.headers,
},
body: response.body ? marshal(response.statusCode, response.body) : '',
};
};
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 293fab0

Please sign in to comment.