Skip to content

feat: allow to modify HTTP response in middleware before deserialization #1732

@Petroniuss

Description

@Petroniuss

use-case

I was experimenting with Smithy for codegeneration of API clients (@restJson1 protocol).
I was trying to model errors that a service can return in Smithy - in my case the service has only a few types of errors. However, the server does not respond with predefined auxiliary data that could disambiguate the errors schema, as noted in operation-error-deserialization:

  • X-Amzn-Errortype
  • __type
  • code

This makes it impossible for deserialization code to know which error type to use for deserialization and all errors are returned as $CLIENTServiceException. Due to the nature of the service that I was modeling error types can be disambiguated by status codes (4xx and 5xx), hence I thought about writing a custom middleware that would tell Smithy what the error type is based on status code (by adding an HTTP header to the response before deserialization)

For this to work though, there needs to be a middleware that has access to modify raw http response before deserialization.

Here's the code that I tried - it doesn't work because deserialization middleware only has access to $reponse after running deserialization.

const errorByStatusMiddleware = (statusCodeErrorTypeMapping: Record<number, string>) => <Input extends object, Output extends object>(
  next: DeserializeHandler<Input, Output>,
  context: HandlerExecutionContext
): DeserializeHandler<Input, Output> => async (
  args: DeserializeHandlerArguments<Input>
): Promise<DeserializeHandlerOutput<Output>> => {
  if (!HttpRequest.isInstance(args.request)) {
    return next(args);
  }

  // problem: args.response is not available before running deserialization.
  // feature proposal: args.response should be available to modify by middleware before deserialization.
  // args.response

  const output = await next(args);
  if (!HttpResponse.isInstance(output.response)) {
    return output;
  }

  // response is only available AFTER running deserialization.
  const errorType = statusCodeErrorTypeMapping[output.response!!.statusCode];
  if (errorType) {
    // In order for this to work, this could would be need to be executed before deserialization.
    output.response!!.headers[SMITHY_ERROR_TYPE_HEADER] = errorType;
  }

  return output;
};

feature request

Add a possibility to access & modify raw response (well at least headers) in deserialization middleware before running deserialization.

justification

There should be a way to model errors for Smithy-unaware services - I don't see other way of doing it (assuming that we can't change operation-error-deserialization](https://smithy.io/2.0/aws/protocols/aws-restjson1-protocol.html#operation-error-serialization)) than by modifying HTTP response on client-side before deserialization is executed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions