Skip to content
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

fix: allow error deserializers to populate error response body #1180

Merged
merged 1 commit into from
Mar 7, 2024

Conversation

kuhe
Copy link
Contributor

@kuhe kuhe commented Mar 5, 2024

Currently, deserializer collectors read response body streams prior to attempting to deserialize them.

If there is a parsing error, such as when a JSON service front end layer (load balancer, CDN, etc) has an error and returns non-JSON, the raw text of this error is lost since the stream collector has read the stream.

For this PR, addressing such cases, if the error contains a field called $responseBodyText, it will be written over the response body's (consumed and therefore empty) stream, so the user can read the body text instead of only having an empty stream.

It is up to the deserializer implementation to write the body text to this field.

Example:

export const parseJsonBody = (streamBody: any, context: SerdeContext): any =>
  collectBodyString(streamBody, context).then((encoded) => {
    if (encoded.length) {
      try {
        return JSON.parse(encoded);
      } catch (e: any) {
        if (e?.name === "SyntaxError") {
          Object.defineProperty(e, "$responseBodyText", {
            value: encoded,
          });
        }
        throw e;
      }
    }
    return {};
  });
export const parseXmlBody = (streamBody: any, context: SerdeContext): any =>
  collectBodyString(streamBody, context).then((encoded) => {
    if (encoded.length) {
      const parser = new XMLParser({
        attributeNamePrefix: "",
        htmlEntities: true,
        ignoreAttributes: false,
        ignoreDeclaration: true,
        parseTagValue: false,
        trimValues: false,
        tagValueProcessor: (_: any, val: any) => (val.trim() === "" && val.includes("\n") ? "" : undefined),
      });
      parser.addEntity("#xD", "\r");
      parser.addEntity("#10", "\n");

      let parsedObj;
      try {
        parsedObj = parser.parse(encoded);
      } catch (e: any) {
        if (e && typeof e === "object") {
          Object.defineProperty(e, "$responseBodyText", {
            value: encoded,
          });
        }
        throw e;
      }

      const textNodeName = "#text";
      const key = Object.keys(parsedObj)[0];
      const parsedObjToReturn = parsedObj[key];
      if (parsedObjToReturn[textNodeName]) {
        parsedObjToReturn[key] = parsedObjToReturn[textNodeName];
        delete parsedObjToReturn[textNodeName];
      }
      return getValueFromTextNode(parsedObjToReturn);
    }
    return {};
  });

@kuhe kuhe requested review from a team as code owners March 5, 2024 21:42
@kuhe kuhe requested a review from JordonPhillips March 5, 2024 21:42
@kuhe
Copy link
Contributor Author

kuhe commented Mar 5, 2024

related to aws/aws-sdk-js-v3#5851

@kuhe kuhe force-pushed the feat/error-handling branch 3 times, most recently from 4094086 to 1ebc1c5 Compare March 6, 2024 15:42
@kuhe kuhe merged commit 49640d6 into smithy-lang:main Mar 7, 2024
7 checks passed
@kuhe kuhe deleted the feat/error-handling branch March 7, 2024 15:49
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants