ijpiantanida / talkback

A simple HTTP proxy that records and playbacks requests
MIT License
283 stars 41 forks source link

bug: tapes aren't recorded with human readable body #84

Closed cristianoliveira closed 1 year ago

cristianoliveira commented 1 year ago

Hello there šŸ‘‹ First of all thanks for the effort you have put into this project. We have been using it to mock our API, and its flexibility is key.

I have a bug to report tho, and I believe I found the culprit. The issue is that it isn't saving the tapes in human-readable form, which makes it a bit harder to debug them.

The issue is related to the case sensitivity of the content-type headers matcher (here) which I believe should be case insensitive.

For instance, our SDK uses the following request to communicate with the API:

  return api
    .request(`checkouts/${checkoutId}`, {
      method: 'PUT',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(formattedPayload),
    });

And that causes the tapes to be recorded like:

        body: 'ewogICJwYXltZW50X3R5cGUiOiAiYmFu...(content)',

How to reproduce

Make a request using the following content type format:

const talkbackURL = "http://localhost:3030"
fetch(talkbackURL, {
  headers: {
      'Content-Type': 'application/json'
   },
   body: JSON.stringify({"foo": "bar"}),
}).then(console.log)

Check the generated tape

Expected

Outcome

Suggested fix

When checking human-readable content type, ignore the case


// https://github.dev/ijpiantanida/talkback/blob/main/src/utils/headers.ts
static read(headers: any, headerName: string) {
    const caseInsensitiveKey = Object.key(headers)
         .find(h => h.toLowerCase() === headerName.toLowerCase())
    const value = headers[caseInsensitiveKey];
    if (Array.isArray(value)) {
      return value[0];
    } else {
      return value;
    }
  }```
cristianoliveira commented 1 year ago

After a bit of debugging my suggestion wasn't correct, I believe there's something else causing this issue

ijpiantanida commented 1 year ago

hi @cristianoliveira, glad you like talkback!

I don't seem to be able to reproduce the issue. The http server should already be lower-casing all the headers.

Do you have any decorators that might be modifying them on the tape directly? Could you also post the full tape that gets generated?

cristianoliveira commented 1 year ago

Hey thanks for the quick answer. Hmmm Let me check. I'll try to create a demo using our implementation so I can share, or maybe I can figure out the issue by doing so šŸ˜…. I'll come back with an answer

cristianoliveira commented 1 year ago

Here is a demo of the issue: https://github.com/cristianoliveira/talkback-issue-demo

If you look at the saved tapes: https://github.com/cristianoliveira/talkback-issue-demo/blob/main/tapes/

The request body from both is encoded https://github.com/cristianoliveira/talkback-issue-demo/blob/main/tapes/unnamed-1.json5#L11

I was expecting it to be stored in plain JSON. Is this the expected behavior?

ijpiantanida commented 1 year ago

Thanks for the demo, that was helpful!

The problem is allowHeaders: [], which strips the content-type header from the request before talkback can process it. Try allowHeaders: ['content-type']

cristianoliveira commented 1 year ago

Aha bingo! It works! I really didn't notice that! Maybe is worth adding a warning in the https://github.com/ijpiantanida/talkback#options about this behavior :)

If you feel it's a good idea I can open a PR. Anyway, thanks again!