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

Custom body decoding #555

Merged
merged 11 commits into from
Feb 14, 2021
Merged

Custom body decoding #555

merged 11 commits into from
Feb 14, 2021

Conversation

MiSikora
Copy link
Contributor

@MiSikora MiSikora commented Feb 10, 2021

πŸ“· Screenshots

Protobuf encoded request available in preview:

Screenshot_20210210_201958

πŸ“„ Context

There is an issue – #523.

πŸ“ Changes

I added BodyEncoder interface which instances can be installed in ChukcerInterceptor. They are then applied when bodies are being processed. First result that is non–null String is used as a body in transaction.

Exporting functionality was modified to accommodate for changes and export custom payloads as well.

I also edited sample to contain some custom processing. Unfortunately I did only for requests because I cannot find any public service that will echo proto data.

🚫 Breaking

No

πŸ› οΈ How to test

Run the sample, check postman echo request, check exporting.

⏱️ Next steps

ChuckerInterceptorTest needs some splitting into smaller units and/or moving test to respective processors. Also, HttpBinClient needs some clean-up because as mentioned some time ago it is now doing more than communicating with httpbin.
Closes #523.

@MiSikora MiSikora added the enhancement New feature or improvement to the library label Feb 10, 2021
@MiSikora
Copy link
Contributor Author

Lint decided to fail with versions updates for some reason on this PR. πŸ€·β€β™‚οΈ

Copy link
Member

@cortinico cortinico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work @MiSikora πŸš€ Really excited to see this coming!

The code looks good on my end, I left mostly minor comments and nits.

Comment on lines 271 to 272
} else if (bodyString.isBlank()) {
if (!isBodyPlainText) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you merge this into a single condition?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not in the current format, but I think it makes more sense to change to when. It'll make it clearer.

Comment on lines 711 to 714
private class LiteralBodyDecoder : BodyDecoder {
override fun decodeRequest(request: Request, body: ByteString) = "Request"
override fun decodeResponse(response: Response, body: ByteString) = "Response"
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that all the *Decoder + all the related tests should be moved to a ChuckerInterceptor_withDecoderTest

val pokemon = Pokemon("Pikachu", level = 99)
val body = pokemon.encodeByteString().toRequestBody("application/protobuf".toMediaType())
val request = Request.Builder()
.url("https://postman-echo.com/post")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class is getting bloated :( It's called HttpBinClient but we do a lot of other stuff inside:

        downloadSampleImage(colorHex = "fff")
        downloadSampleImage(colorHex = "000")
        getResponsePartially()
        getProtoResponse()

Can you please move this code into PostmanEchoClient and then we'll take care of refactoring the status quo?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't want to move focus from decoding in this PR. Like mentioned in "next steps" section I'd prefer to restructure it in a separate PR if you don't mind.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup let's follow up on this

Comment on lines +18 to +19
@Throws(IOException::class)
public fun decodeRequest(request: Request, body: ByteString): String?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This is more an API design question.

What we're modelling here is an operation that could have 3 outcomes: success (String), failure (IOException), skipped (null).

Have you considered different approaches (e.g. sealed classes or the Kotlin Result type)? I'm not saying that the approach here is wrong, but I was wondering if we have some benefit in modelling it differently.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with this nitpick that it might be a good idea to model the result to leave less ambiguity.
For example, we could have something like Failure instead of null in case of unsupported content.

Copy link
Contributor Author

@MiSikora MiSikora Feb 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I considered it and I don't think it is the right choice. I don't see how it helps us in the processing pipeline. We are interested only in the first successfully decoded body.

IOException does not model a type of respons. Methods are annotated with it because tools like adapters generally can throw this type of exception so it removes form users a burden of needing to deal with it. And in Kotlin it is easy to forget since exceptions are not checked. Also, it allows us to log exceptions for the user so they have feedback information when something goes wrong. I would be either for keeping this part as is or to remove @Throws and move the responsibility to the users.

Returning null instead of some type is a nod towards libraries like Retrofit or Moshi, where factories return it when they can't handle input. I don't mind modelling it with a sealed class but I don't know if it brings anything to the table. If you feel that it would be helpful I'll change it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your insights πŸ‘ I think we're fine with the current modelling for the reasons you mentioned + is the one that has the smaller API surface

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This thread started with nit annotation, so let's leave it as it is :)

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
public interface BodyDecoder {
/**
* Returns a text representation of [body] that will be displayed in Chucker UI transaction,
* or `null` if [request] cannot be handled by this decoder. [Body][body] is no longer than
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a typo with 2 body

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe is actually valid KDoc where you can specify the display text for a link πŸ€”

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is deliberate. It allows to link to body property and start the sentence with a capital letter.

Comment on lines +18 to +19
@Throws(IOException::class)
public fun decodeRequest(request: Request, body: ByteString): String?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with this nitpick that it might be a good idea to model the result to leave less ambiguity.
For example, we could have something like Failure instead of null in case of unsupported content.


/**
* Returns a text representation of [body] that will be displayed in Chucker UI transaction,
* or `null` if [response] cannot be handled by this decoder. [Body][body] is no longer than
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same typo with 2 body

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, not a typo. :)

@MiSikora MiSikora added this to the 4.0.0 milestone Feb 13, 2021
@MiSikora MiSikora merged commit 636bd6e into develop Feb 14, 2021
@MiSikora MiSikora deleted the custom-body-decoding branch February 14, 2021 08:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or improvement to the library
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improved handling of encoded/binary bodies
3 participants