Skip to content

Derive HasClient good response status from Verb status #1469

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

Merged

Conversation

marinelli
Copy link
Contributor

@marinelli marinelli commented Oct 19, 2021

Hi Everyone,
There's a limitation/bug in the HasClient instances for the Verb datatype.
If I try to perform a client request with runClientM, I'll obtain a successful response if and only if the backend endpoint returns a response with status code >=200 and <300. This is due to the use of runRequest in the clientWithRoute definitions.

This PR brings the following changes:

  • Replace runRequest with runRequestAcceptStatus in the Verb instances for the HasClient class (as suggested by @alpmestan).
  • Derive the good response status from the Verb status.
  • Use statusIsSuccessful from Network.HTTP.Types.Status to lighten the code (not required to solve the issue).

@marinelli marinelli marked this pull request as ready for review October 20, 2021 16:09
@marinelli marinelli force-pushed the fix-client-response-status branch 2 times, most recently from 548a80b to 3c6a2b5 Compare October 31, 2021 14:36
Copy link
Contributor

@alpmestan alpmestan left a comment

Choose a reason for hiding this comment

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

Looks great thanks, and sorry for the delay!

Do you perhaps feel like adding a test case where the server returns e.g 201 but the client wants 200, to make sure this doesn't break in the future?

@tchoutri I suspect we'll want to be very loud and clear about this when announcing the release that ships this, including in the changelog. This might even upset some users ("but the response is a 2xx, it should be fine!"), perhaps? I don't know.

@tchoutri
Copy link
Contributor

You got it boss

@marinelli marinelli force-pushed the fix-client-response-status branch from 3c6a2b5 to 50bc905 Compare December 7, 2021 17:47
@marinelli marinelli requested a review from alpmestan December 7, 2021 18:04
@@ -83,6 +83,9 @@ successSpec = beforeAll (startWaiApp server) $ afterAll endWaiApp $ do
let p = Person "Clara" 42
left show <$> runClient (getBody p) baseUrl `shouldReturn` Right p

it "Servant.API.Get redirection" $ \(_, baseUrl) -> do
Copy link
Contributor

Choose a reason for hiding this comment

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

The idea of this test being that before your patch, we'd get a ClientError because we don't get a 2xx status code?

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, that's the idea. I also checked the same test in master and it returns, as expected, a FailureResponse.

Copy link
Contributor Author

@marinelli marinelli Dec 8, 2021

Choose a reason for hiding this comment

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

Btw, this is similar to the "Redirects when appropriate" test, that uses uverbGetSuccessOrRedirect True, but for Verb.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, sounds good. Since it wasn't 100% obvious to me initially, that might be the case for other contributors, perhaps indicating the purpose in the test label or a comment nearby would help. But the test otherwise looks good.

@marinelli
Copy link
Contributor Author

marinelli commented Dec 8, 2021

Do you perhaps feel like adding a test case where the server returns e.g 201 but the client wants 200, to make sure this doesn't break in the future?

I had a look at how to add this test, and I was not sure how to proceed.
To test that the proper status code for the client is the one derived from the public API signature of the server, I would change the status code in the server response before the client receives it. The only way I found to do that is to create a copy of the public API signature of the server and create another one specifically for the client. They would be identical except for the status code in the endpoint we want to test.
E.g.:

type ServerAPI = Verb GET 201 '[JSON] ()
type ClientAPI = Verb GET 200 '[JSON] ()

I tried to use also the free monad client in the Servant.Client.Free. At the end, that client is usefull to simulate a client, not to verify if the real client reports errors as expected.

@alpmestan
Copy link
Contributor

For testing this precise thing, I'd do exactly what you said, no need to appeal to the big common API type with a bunch of constructs in it.

Just the two tiny almost-identical, differing-only-in-status-code endpoint types you gave seem perfect. They're even short enough to write them inline, client (Proxy :: Proxy (Verb GET 200 '[JSON] ())), if you want.

@marinelli marinelli requested a review from alpmestan December 9, 2021 08:46
@marinelli
Copy link
Contributor Author

For testing this precise thing, I'd do exactly what you said, no need to appeal to the big common API type with a bunch of constructs in it.

Just the two tiny almost-identical, differing-only-in-status-code endpoint types you gave seem perfect. They're even short enough to write them inline, client (Proxy :: Proxy (Verb GET 200 '[JSON] ())), if you want.

I added the Servant.BrokenSpec module for checking client/server api inconsitencies.

Copy link
Contributor

@alpmestan alpmestan left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks!

@tchoutri tchoutri merged commit 29d2553 into haskell-servant:master Dec 9, 2021
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