-
-
Notifications
You must be signed in to change notification settings - Fork 416
empty path when using CaptureAll results to [""] #1243
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
Comments
Hi, I just started using Servant, and I am interested in trying to contribute this fix. I am pretty comfortable with Haskell. I have found the definition for Also, I am familiar with how higher kinded types when dealing with type classes and their instanciation, but I am not familiar with some of the cool type wizardry going on with the Thanks, and hopefully I can figure out how to fix this ;) |
Also, @domenkozar if you could give some information about how to reproduce this I would be grateful. By PS. I found where |
Is it related to this part of the test specification? -- taken from line 291 of the file it "can capture when there are no elements in 'pathInfo'" $ do
response <- get "/"
liftIO $ decode' (simpleBody response) `shouldBe` Just beholder In the So, it seems like it is defaulting to It seems like I must be on to something here, but I still haven't found the source lines that will confirm my suspicions. Looking forward to solving this, but I will make a concerted effort to wait for a response before continuing to blow up this thread. EDIT: I believe I have found the relevant source. At line 497 of file instance (ToHttpApiData v, HasLink sub)
=> HasLink (CaptureAll sym v :> sub)
where
type MkLink (CaptureAll sym v :> sub) a = [v] -> MkLink sub a
toLink toA _ l vs = toLink toA (Proxy :: Proxy sub) $
foldl' (flip $ addSegment . escaped . Text.unpack . toUrlPiece) l vs the addSegment :: Escaped -> Link -> Link
addSegment seg l = l { _segments = _segments l <> [seg] } I still need to check out what the I will continue to investigate. It looks more intentional as I continue to dive into the source. |
Exactly.
I'd expect it to be an empty list. |
Sure, I understand wanting it to be an empty list (another case of Thank you for feedback on my questions ;) @domenkozar Do you know where in the source the behavior is programmed? I have been away from home, and without my computers since I last got on here, so no chances for further source diving yet. |
The |
@alpmestan thank you very much. I'll get to it this week before I start work and classes again ;) @domenkozar I think I can get this fixed pretty soon. Thank you for opening an issue that is friendly to new contributors. I am excited to get involved with this project ;) |
@guygastineau Thanks for looking into this. :-) |
Just a little update about where I am on working through this:
type CaptureAllApi = "legs" :> CaptureAll "legs" Integer :> Get '[JSON] Animal
:<|> "arms" :> CaptureAll "arms" String :> Get '[JSON] [Animal]
captureAllApi :: Proxy CaptureAllApi
captureAllApi = Proxy
captureAllServer :: Server CaptureAllApi
captureAllServer = handleLegs :<|> handleArms
where
handleLegs :: [Integer] -> Handler Animal
handleLegs legs = case sum legs of
4 -> return jerry
2 -> return tweety
0 -> return beholder
_ -> throwError err404
handleArms :: [String] -> Handler [Animal]
handleArms = mapM animalFromString
where
animalFromString :: String -> Handler Animal
animalFromString "tweety" = return tweety
animalFromString "jerry" = return jerry
animalFromString "beholder" = return beholder
animalFromString "" = return beholder
animalFromString _ = throwError err404
captureAllSpec :: Spec
captureAllSpec = do
describe "Servant.API.CaptureAll" $ do
with (return (serve captureAllApi captureAllServer)) $ do
it "can capture a single element of the 'pathInfo'" $ do
response <- get "/legs/2"
liftIO $ decode' (simpleBody response) `shouldBe` Just tweety
it "can capture multiple elements of the 'pathInfo'" $ do
response <- get "/legs/2/2"
liftIO $ decode' (simpleBody response) `shouldBe` Just jerry
it "can capture arbitrarily many elements of the 'pathInfo'" $ do
response <- get "/legs/1/1/0/1/0/1"
liftIO $ decode' (simpleBody response) `shouldBe` Just jerry
it "can capture when there are no elements in 'pathInfo'" $ do
response <- get "/legs"
liftIO $ decode' (simpleBody response) `shouldBe` Just beholder
it "returns 400 if the decoding fails" $ do
get "/legs/notAnInt" `shouldRespondWith` 400
it "returns 400 if the decoding fails, regardless of which element" $ do
get "/legs/1/0/0/notAnInt/3/" `shouldRespondWith` 400
it "returns 400 if the decoding fails, even when it's multiple elements" $ do
get "/legs/1/0/0/notAnInt/3/orange/" `shouldRespondWith` 400
-- Test the string capturing half of the API
it "can capture a single element of 'pathinfo'" $ do
response <- get "/arms/tweety"
liftIO $ decode' (simpleBody response) `shouldBe` Just [tweety]
it "can capture multiple elements of 'pathinfo'" $ do
response <- get "/arms/tweety/jerry"
liftIO $ decode' (simpleBody response) `shouldBe` Just [tweety, jerry]
it "can capture arbitrarily many elements of 'pathinfo'" $ do
response <- get "/arms/tweety/jerry/beholder/tweety/jerry"
liftIO $ decode' (simpleBody response) `shouldBe`
Just [tweety, jerry, beholder, tweety, jerry]
it "can capture when no elements are in 'pathinfo'" $ do
response <- get "/arms/"
liftIO $ decode' (simpleBody response) `shouldBe` Just [beholder] Currently it is testing if the behavior is the same for Strings and Integers getting captured. The first thing I have noticed about this:
EDIT: UPDATE -
If these quirks simply reside in Thanks for letting me store these progress notes up here ;) |
Okay, I confirmed some of my suspicions. The following passed, but I imagine the specification would be for it "wont ignore empty slots in 'pathinfo'" $ do
response <- get "/arms/jerry///tweety"
liftIO $ decode' (simpleBody response) `shouldBe`
Just [jerry, beholder, beholder, tweety] So empty path segments are getting turned into empty |
After playing with At least I am having fun and learning more about multiple libraries ;) |
I think I will finally have some time this weekend to look into this again. At least I left all that documentation of the journey and thought process above ;) |
Okay, I found this again. It has been a LONG time since I last looked into this. At least I have a lot more experience, and haskell build tooling is also more powerful/easier to use. I will take another stab at this. Wish me luck! |
@guygastineau Godspeed! |
I am only able to reproduce the buggy behavior when the "empty" path piece is in a sub route. That is, tests for This problem is happening before |
It is actually happening in the usage of |
Okay, so I fixed it for routes that have a previoous path piece, ie. |
Actually, I think I arrived at the solution everyone would want :) |
0.20.2 ---- - Fix build of examples/greet.hs. Add "429 Too Many Requests" error. [#1591](haskell-servant/servant#1591) - Full query string helpers [#1604](haskell-servant/servant#1604) This involves a new instance `HasServer (QueryString :> api) context`. - Add `MkHandler` pattern synonym [#1732](haskell-servant/servant#1732) [#1733](haskell-servant/servant#1733) Add a bidirectional pattern synonym to construct `Handler a` values from `IO (Either ServerError a)` ones, and match in the other direction. - Add instance `HasServer (EmptyAPI :> api) context` [#1775](haskell-servant/servant#1775) - Bugfix - CaptureAll produces [""] for empty paths due to trailing slash. [#1243](haskell-servant/servant#1243) [#1516](haskell-servant/servant#1516) CaptureAll resulted in `[""]` for empty paths due to trailing slash. Similar oddities occurred around these edge cases like `"/"` resulted in `[]` correctly, but `"//"` resulted in `["", ""]`. This patch simply eliminates the first `""` in the pathinfo list as taken from the wai response. This might break user code that relies on personal shims to solve the problem, however simply removing their workarounds should fix their code as the behavior is now sane.
Uh oh!
There was an error while loading. Please reload this page.
Expected would be
[]
.The text was updated successfully, but these errors were encountered: