From 1b5295e75ae144cacd8ede88c681d8537a9a846a Mon Sep 17 00:00:00 2001 From: Jasper Woudenberg Date: Tue, 29 Dec 2020 13:50:14 +0100 Subject: [PATCH] Query flags result in optional args When adding a query flag to an existing endpoint it would be nice if this were a backwards-compatible change. From the HTTP perspective it already is: the query flag is an optional element of the URI that can be omitted. But code generation produces a non-optional argument. This imposes a hard order-of-deploy between the service that supports the new parameter and the client that makes use of it (or not). This changes the code so the query flag is an optional argument in ruby generated code. That way the backwards-compatibility of adding a query parameter to an API is preserved into our generated code. --- src/Servant/Ruby.hs | 36 +++++++++++++++++++++++++----- test/golden/expected/query_flag.rb | 6 ++--- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/Servant/Ruby.hs b/src/Servant/Ruby.hs index ec85b09..8eb35a2 100644 --- a/src/Servant/Ruby.hs +++ b/src/Servant/Ruby.hs @@ -252,7 +252,7 @@ public indent req = ] ++ cleanCaptures ++ - [ Just $ " req = Net::HTTP::" <> method <> ".new(" <> functionName <> "_uri(" <> argsStr <> "))" + [ Just $ " req = Net::HTTP::" <> method <> ".new(" <> functionName <> "_uri(" <> callArgsStr <> "))" ] ++ requestHeaders ++ @@ -286,16 +286,22 @@ public indent req = ] argsStr :: Text - argsStr = T.intercalate ", " $ snake <$> args + argsStr = T.intercalate ", " args + + callArgsStr :: Text + callArgsStr = T.intercalate ", " callArgs + + callArgs :: [Text] + callArgs = captures ++ (paramToCallArg <$> queryparams) allArgsStr :: Text - allArgsStr = T.intercalate ", " $ snake <$> (args ++ bodyAndHeader) + allArgsStr = T.intercalate ", " (args ++ bodyAndHeader) args :: [Text] - args = captures ++ ((^. queryArgName.argPath) <$> queryparams) + args = captures ++ (paramToArg <$> queryparams) bodyAndHeader :: [Text] - bodyAndHeader = body ++ headerArgs + bodyAndHeader = snake <$> (body ++ headerArgs) segments :: [Segment NoContent] segments = filter isCapture paths @@ -306,7 +312,7 @@ public indent req = queryparams = req ^.. reqUrl.queryStr.traverse captures :: [Text] - captures = view argPath . captureArg <$> segments + captures = fmap snake $ view argPath . captureArg <$> segments body :: [Text] body = @@ -389,6 +395,24 @@ paramToStr qarg = key = qarg ^. queryArgName.argName._PathSegment val = snake key +paramToArg :: QueryArg f -> Text +paramToArg qarg = + case qarg ^. queryArgType of + Normal -> snake name + Flag -> snake name <> ": false" + List -> snake name + where + name = qarg ^. queryArgName.argPath + +paramToCallArg :: QueryArg f -> Text +paramToCallArg qarg = + case qarg ^. queryArgType of + Normal -> snake name + Flag -> snake name <> ": " <> snake name + List -> snake name + where + name = qarg ^. queryArgName.argPath + snake :: Text -> Text snake = T.pack . quietSnake . T.unpack diff --git a/test/golden/expected/query_flag.rb b/test/golden/expected/query_flag.rb index da39b9b..1e45c75 100644 --- a/test/golden/expected/query_flag.rb +++ b/test/golden/expected/query_flag.rb @@ -16,12 +16,12 @@ def initialize(origin, timeout = nil) @http.use_ssl = @origin.scheme == 'https' end - def get_uri(beetle) + def get_uri(beetle: false) URI("#{@origin}?#{beetle ? 'beetle' : ''}") end - def get(beetle) - req = Net::HTTP::Get.new(get_uri(beetle)) + def get(beetle: false) + req = Net::HTTP::Get.new(get_uri(beetle: beetle)) @http.request(req) end