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

Add a requiredBody() extension to RestClient.ResponseSpec #32703

Closed

Conversation

Donghh0221
Copy link
Contributor

@Donghh0221 Donghh0221 commented Apr 24, 2024

Description

In WebClientExtensions.kt, developers have the flexibility to handle responses with methods that either guarantee a non-null return type or can return null. This design caters to various nullability requirements, enhancing code safety and expressiveness. However, RestClientExtensionKt currently offers only a nullable return type method, which may lead to unnecessary null checks and potentially less idiomatic Kotlin code.

Given Kotlin's emphasis on type safety and explicit nullability, extending RestClientExtensionKt to include a non-nullable return type method would align with these principles, offering a more robust and intuitive toolset for REST client development.

Proposal

I propose the addition of a bodyNonNull method to RestClientExtensionKt:

inline fun <reified T : Any> RestClient.ResponseSpec.bodyNotNull(): T =
    body(object : ParameterizedTypeReference<T>() {}) ?: throw NoSuchElementException("Expected a non-null response body")

This method complements the existing nullable variant, providing a straightforward way to enforce non-null responses, thereby aligning with Kotlin's null safety features and reducing boilerplate code.

Impact and Use Cases

This enhancement introduces no breaking changes, enriching the API without affecting existing code. It particularly benefits scenarios where a non-null response is confidently expected, making error handling more explicit and idiomatic in Kotlin.

Seeking Feedback

I welcome feedback on this proposal, including alternative approaches, potential impacts on usability, and any concerns regarding implementation details.

Conclusion

By adopting this change, RestClientExtensionKt would not only align more closely with Kotlin's design principles but also offer developers a more expressive and safe way to handle REST responses. This proposal upholds the Kotlin ethos of safety and clarity, enhancing developer experience and code quality in REST client applications.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Apr 24, 2024
@jhoeller jhoeller added in: web Issues in web modules (web, webmvc, webflux, websocket) theme: kotlin An issue related to Kotlin support labels Apr 24, 2024
@sdeleuze sdeleuze self-assigned this Apr 24, 2024
@sdeleuze
Copy link
Contributor

Kotlin extensions try to stay as close as possible to the Java API, so I think I would not be in favor of a Kotlin specific API like the one proposed here.

@poutsma Could you please let me know what you think of the idea of introducing a non-nullable return value variant of ResponseSpec#body.

@snicoll snicoll added the status: waiting-for-internal-feedback An issue that needs input from a member or another Spring Team label Apr 24, 2024
@poutsma
Copy link
Contributor

poutsma commented Apr 25, 2024

I am not sure such a method is necessary in Java, where the use of null is more idiomatic than in Kotlin. For me, having a use case in Java is a requirement for adding any code on the Java side.

Instead, from a Java perspective, I think having a method that returns an Optional of the body would be much more useful, and more fitting within the functional API of RestClient. Using an Optional also gives the user the choice of returning a default value instead of throwing a NoSuchElementException, to filter out values, to map on them, etc.

Unless I am mistaken, such a optional-returning-method could then be used to implement the Kotlin extension described above, since I believe use of Optional is less idiomatic in Kotlin (?).

How does that sound, @sdeleuze?

@sdeleuze
Copy link
Contributor

I think the use case here is "I know this endpoint is expected to return a body 99.99% of the time and I don't want any "noise" in my code like !! in Kotlin to turn a nullable return value to a non-nullable one or optional unwrapping", so I am in not in favor of introducing an optional variant which typically won't be used from Kotlin side to avoid doing unnecessary wrapping/unwrapping (we would instead just leverage the current nullable variant with !!).

So I am leaning toward declining this PR and just recommend to use body()!! or other null-safety constructs in Kotlin like ?: to handle that. It is pretty concise and give the right level of flexibility to the Kotlin developer. Any thoughts @Donghh0221?

@Donghh0221
Copy link
Contributor Author

Thank you for your review, @sdeleuze @poutsma.

As you mentioned, using Optional as a return type does not seem to be a suitable way to solve our current issue.

Indeed, when calling the body method, it is typically presumed that a response body exists. Given this, I believe a method like bodyNotNull should be provided to handle responses without requiring additional !! or explicit exception throwing. Without such a method, developers must give extra consideration to which error should be thrown. Where a custom error is necessary, sticking with the existing body method would be more appropriate.

From a practical perspective, many teams in the existing MVC ecosystem have been using WebClient with runBlocking. These teams, which have been pragmatically handling nulls through WebClientExtensions.kt's awaitBody and awaitBodyOrNull, now need to reconsider whether to throw NoSuchElementException everywhere, or an NPE with !!, and change their error handling approach.

For these reasons, please reconsider adding an interface like bodyNotNull for Kotlin users.

@sdeleuze sdeleuze removed the status: waiting-for-internal-feedback An issue that needs input from a member or another Spring Team label Apr 25, 2024
@sdeleuze
Copy link
Contributor

@Donghh0221 I propose that we use requiredBody() instead of bodyNotNull() which seems conceptually a better fit with the fact it will throw a NoSuchElementException, could you please update the PR accordingly?

@sdeleuze sdeleuze added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Apr 26, 2024
@sdeleuze sdeleuze added this to the 6.2.0-M2 milestone Apr 26, 2024
@sdeleuze sdeleuze changed the title Add bodyNotNull for RestClient Kotlin extensions Add a requiredBody() extension to RestClient.ResponseSpec Apr 26, 2024
@sdeleuze sdeleuze added the status: waiting-for-feedback We need additional information before we can continue label Apr 26, 2024
@Donghh0221
Copy link
Contributor Author

@sdeleuze Of course! I've added a commit to respond to your review.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Apr 26, 2024
@sdeleuze sdeleuze removed the status: feedback-provided Feedback has been provided label Apr 26, 2024
@sdeleuze sdeleuze closed this in a662f5e Apr 26, 2024
@sdeleuze
Copy link
Contributor

Polished and merged, thanks for your contribution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) theme: kotlin An issue related to Kotlin support type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants