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

Adds support for sttp client 4 #4299

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
Draft

Conversation

MichalStopyra
Copy link

@MichalStopyra MichalStopyra commented Jan 29, 2025

Adds support for describing the endpoints using sttp client 4

It is advised to review in a commit-by-commit fashion:

First three commits are just about copying the sttpClient3 module and making it compile (although the scalajs was fixed in Adam's commit later).
Other commits contain actual changes necessary to support sttp client 4.

@MichalStopyra MichalStopyra force-pushed the sttp-client-4-module branch 21 times, most recently from 159e44c to 9ed2a31 Compare February 7, 2025 13:14
@MichalStopyra MichalStopyra marked this pull request as ready for review February 7, 2025 16:56
@MichalStopyra MichalStopyra changed the title [WIP] Adds support for sttp client 4 Adds support for sttp client 4 Feb 7, 2025
adamwkaczmarek and others added 7 commits February 7, 2025 18:03
* It is no longer possible to return a Request instance for all the possible request types. From now on a GenericRequest is returned where needed.
* GenericRequest does not contain a .response method, hence the pattern match to each type was necessary.
* fromMetadata method is still used for the Request (and ResponseAs) type in order to handle the failed requests cases
* GenericRequestExtensions have been added so as to be able to call .send on a GenericRequest instance. Pattern matching to given types happens there under the hood
* Passing custom headers together with web socket responses is not supported for HttpClientFs2Backend, hence the test was removed
* Instead of passing the stream as req.body it is necessary to use the Request.streamBody method (when we deal with non-blocking/async streams. For this reason, the pattern match distinguishing request types has been enhanced to check if the request body is supposed to be a stream and if yes, the .streamBody method is called to set it.
@adamw
Copy link
Member

adamw commented Feb 17, 2025

One thing we're missing for sure are the docs :)

*
* For capabilities `R`, where web sockets aren't included, the implementation just throws an unsupported exception (and this logic
* shouldn't ever be used). For capabilities which include web sockets, appropriate implementations should be imported, e.g. from the
* `sttp.tapir.client.sttp.ws.fs2._` or `sttp.tapir.client.sttp.ws.akka._` packages.
Copy link
Member

Choose a reason for hiding this comment

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

wrong package in comment

Copy link
Author

@MichalStopyra MichalStopyra Feb 17, 2025

Choose a reason for hiding this comment

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

fixed ;)


object GenericRequestExtensions {

def sendRequest[F[_], T](backend: Backend[F], genReq: GenericRequest[T, _]): F[Response[T]] = {
Copy link
Member

Choose a reason for hiding this comment

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

hm this looks bad ;) and we have to somehow avoid this by providing a better interpreter interface

* parameters: path, query, headers and body. The request is sent using the given backend, and the result of decoding the response (error
* or success value) is returned.
*/
def toClient[F[_], I, E, O, R](e: PublicEndpoint[I, E, O, R], baseUri: Option[Uri], backend: Backend[F])(implicit
Copy link
Member

Choose a reason for hiding this comment

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

for these calls I think we have to require that R == Any (no capabilities), as this corresponds to the capabilities supported by backend (which are none)

separately, we should probably have toClientStreaming and toClientWebSocket. It is a proliferation of methods (depending on the combination of capabilities used), but then this corresponds to the proliferation of Backend subtypes in sttp

to organize the code we could potentially split these functionalities in separate traits

alternatively, we could have overloaded toClient methods, which accept an implicit witness that R is equal exactly to a specific capability set

Underneath, everything could boil down to calling the same low-level method, and something like GenericRequestExtension, but this should be tapir-private

*/
def toRequest[I, E, O, R](e: PublicEndpoint[I, E, O, R], baseUri: Option[Uri])(implicit
wsToPipe: WebSocketToPipe[R]
): I => GenericRequest[DecodeResult[Either[E, O]], Any] = {
Copy link
Member

Choose a reason for hiding this comment

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

here, we should return a specific Request subtype. GenericRequest is not something end-users should be working with

@MichalStopyra MichalStopyra marked this pull request as draft February 20, 2025 12:07
@MichalStopyra MichalStopyra force-pushed the sttp-client-4-module branch 3 times, most recently from 16f173e to 771360e Compare February 20, 2025 17:13
Michal Stopyra added 3 commits February 21, 2025 15:04
* adds XYZEndpointToSttpClient classes too for each request type
* The only thing that can be found there is related to WebSockets, hence the renaming and extending the trait by WebSocketEndpointToSttpClient, not the base one
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.

4 participants