From f795990df98e6e90dbee3ffda72bed64ead462a1 Mon Sep 17 00:00:00 2001 From: Stoeffel Date: Tue, 11 Jun 2019 14:51:09 +0200 Subject: [PATCH 01/10] QueryParams should produce val[]=key pairs in the generated url. --- src/Servant/Ruby.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Servant/Ruby.hs b/src/Servant/Ruby.hs index 9474d57..bb89848 100644 --- a/src/Servant/Ruby.hs +++ b/src/Servant/Ruby.hs @@ -134,7 +134,7 @@ Captures and query parameters are translated into required arguments, in that or The request body and headers are translated into keyword arguments, in that order. ->>> let api = Proxy :: Proxy ("foo" :> Capture "fooId" Int :> ReqBody '[JSON] () :> QueryParam "barId" Bool :> Header "Max-Forwards" Int :> Post '[JSON] ()) +>>> let api = Proxy :: Proxy ("foo" :> Capture "fooId" Int :> ReqBody '[JSON] () :> QueryParam "barId" Bool :> QueryParams "ids" Int :> Header "Max-Forwards" Int :> Post '[JSON] ()) >>> Data.Text.IO.putStr $ ruby (NameSpace [] "Foo") api require "json" require "net/http" @@ -146,8 +146,8 @@ class Foo @http = Net::HTTP.new(@origin.host, @origin.port) end - def post_foo_by_foo_id(foo_id, bar_id, body:, max_forwards:) - uri = URI("#{@origin}/foo/#{foo_id}?barId=#{bar_id}") + def post_foo_by_foo_id(foo_id, bar_id, ids, body:, max_forwards:) + uri = URI("#{@origin}/foo/#{foo_id}?barId=#{bar_id}&#{ ids.collect { |x| 'ids[]=' + x.to_s }.join('&') }") req = Net::HTTP::Post.new(uri) req["Content-Type"] = "application/json" @@ -319,7 +319,7 @@ paramToStr qarg = case qarg ^. queryArgType of Normal -> key <> "=#{" <> val <> "}" Flag -> key - List -> key <> "[]=#{" <> val <> "}" + List -> "#{ " <> val <> ".collect { |x| '" <> key <> "[]=' + x.to_s }.join('&') }" where key = qarg ^. queryArgName.argName._PathSegment val = snake key From 097ed97f05e8431340fa5dacf799d38e32e418bc Mon Sep 17 00:00:00 2001 From: Stoeffel Date: Tue, 11 Jun 2019 16:39:47 +0200 Subject: [PATCH 02/10] add spec to check if an attribute is a list --- src/Servant/Ruby.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Servant/Ruby.hs b/src/Servant/Ruby.hs index 9474d57..12cf207 100644 --- a/src/Servant/Ruby.hs +++ b/src/Servant/Ruby.hs @@ -147,6 +147,7 @@ class Foo end def post_foo_by_foo_id(foo_id, bar_id, body:, max_forwards:) + foo_id = if foo_id.kind_of?(Array) then foo_id.join(',') else foo_id end uri = URI("#{@origin}/foo/#{foo_id}?barId=#{bar_id}") req = Net::HTTP::Post.new(uri) From 05abdc38118b1d6d10227007c7a241fe2d2bc39c Mon Sep 17 00:00:00 2001 From: Stoeffel Date: Tue, 11 Jun 2019 16:40:19 +0200 Subject: [PATCH 03/10] add code to join lists with a "," --- src/Servant/Ruby.hs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Servant/Ruby.hs b/src/Servant/Ruby.hs index 12cf207..6881608 100644 --- a/src/Servant/Ruby.hs +++ b/src/Servant/Ruby.hs @@ -209,7 +209,10 @@ public indent req = properIndent indent $ [ Nothing , Just $ "def " <> functionName <> "(" <> argsStr <> ")" - , Just $ " uri = URI(" <> url <> ")" + ] + ++ (Just <$> cleanCaptures) + ++ + [ Just $ " uri = URI(" <> url <> ")" , Nothing , Just $ " req = Net::HTTP::" <> method <> ".new(uri)" ] @@ -223,6 +226,12 @@ public indent req = functionName :: Text functionName = req ^. reqFuncName.snakeCaseL.to snake + cleanCaptures :: [Text] + cleanCaptures = cleanCapture . snake <$> captures + + cleanCapture :: Text -> Text + cleanCapture c = " " <> c <> " = if " <> c <> ".kind_of?(Array) then " <> c <> ".join(',') else " <> c <> " end" + argsStr :: Text argsStr = T.intercalate ", " $ snake <$> args From bc353117b2278a7ad83c0c4a5bb8912b801f77c4 Mon Sep 17 00:00:00 2001 From: Stoeffel Date: Tue, 11 Jun 2019 16:41:45 +0200 Subject: [PATCH 04/10] cleanup --- src/Servant/Ruby.hs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Servant/Ruby.hs b/src/Servant/Ruby.hs index 6881608..8ec3e30 100644 --- a/src/Servant/Ruby.hs +++ b/src/Servant/Ruby.hs @@ -230,7 +230,18 @@ public indent req = cleanCaptures = cleanCapture . snake <$> captures cleanCapture :: Text -> Text - cleanCapture c = " " <> c <> " = if " <> c <> ".kind_of?(Array) then " <> c <> ".join(',') else " <> c <> " end" + cleanCapture c = + T.concat + [ " " + , c + , " = if " + , c + , ".kind_of?(Array) then " + , c + , ".join(',') else " + , c + , " end" + ] argsStr :: Text argsStr = T.intercalate ", " $ snake <$> args From 4e9da12deacb5ed7cb02dc273856e429062e44c4 Mon Sep 17 00:00:00 2001 From: Stoeffel Date: Tue, 11 Jun 2019 17:18:34 +0200 Subject: [PATCH 05/10] cleanup --- src/Servant/Ruby.hs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Servant/Ruby.hs b/src/Servant/Ruby.hs index 8ec3e30..4f0ead8 100644 --- a/src/Servant/Ruby.hs +++ b/src/Servant/Ruby.hs @@ -227,13 +227,12 @@ public indent req = functionName = req ^. reqFuncName.snakeCaseL.to snake cleanCaptures :: [Text] - cleanCaptures = cleanCapture . snake <$> captures + cleanCaptures = (<>) " " . cleanCapture . snake <$> captures cleanCapture :: Text -> Text cleanCapture c = T.concat - [ " " - , c + [ c , " = if " , c , ".kind_of?(Array) then " From dda9666bf76eaca049f2e957f922814258bff9ea Mon Sep 17 00:00:00 2001 From: Stoeffel Date: Tue, 11 Jun 2019 17:23:06 +0200 Subject: [PATCH 06/10] add blankline after clean capture code --- src/Servant/Ruby.hs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Servant/Ruby.hs b/src/Servant/Ruby.hs index 4f0ead8..9c66fae 100644 --- a/src/Servant/Ruby.hs +++ b/src/Servant/Ruby.hs @@ -148,6 +148,7 @@ class Foo def post_foo_by_foo_id(foo_id, bar_id, body:, max_forwards:) foo_id = if foo_id.kind_of?(Array) then foo_id.join(',') else foo_id end + uri = URI("#{@origin}/foo/#{foo_id}?barId=#{bar_id}") req = Net::HTTP::Post.new(uri) @@ -210,7 +211,7 @@ public indent req = [ Nothing , Just $ "def " <> functionName <> "(" <> argsStr <> ")" ] - ++ (Just <$> cleanCaptures) + ++ cleanCaptures ++ [ Just $ " uri = URI(" <> url <> ")" , Nothing @@ -226,8 +227,13 @@ public indent req = functionName :: Text functionName = req ^. reqFuncName.snakeCaseL.to snake - cleanCaptures :: [Text] - cleanCaptures = (<>) " " . cleanCapture . snake <$> captures + cleanCaptures :: [Maybe Text] + cleanCaptures = + case captures of + [] -> [] + xs -> + (Just . (<>) " " . cleanCapture . snake <$> xs) + ++ [ Nothing ] cleanCapture :: Text -> Text cleanCapture c = From ed9bd617d7b0cde6469fbb5a35d4f74fb46110fa Mon Sep 17 00:00:00 2001 From: Stoeffel Date: Wed, 12 Jun 2019 13:22:08 +0200 Subject: [PATCH 07/10] expose api uri --- src/Servant/Ruby.hs | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/Servant/Ruby.hs b/src/Servant/Ruby.hs index 9474d57..a608f73 100644 --- a/src/Servant/Ruby.hs +++ b/src/Servant/Ruby.hs @@ -95,10 +95,12 @@ class Baz @http = Net::HTTP.new(@origin.host, @origin.port) end - def get() - uri = URI("#{@origin}") + def get_uri() + URI("#{@origin}") + end - req = Net::HTTP::Get.new(uri) + def get() + req = Net::HTTP::Get.new(get_uri()) @http.request(req) end @@ -119,10 +121,12 @@ module Foo @http = Net::HTTP.new(@origin.host, @origin.port) end - def get() - uri = URI("#{@origin}") + def get_uri() + URI("#{@origin}") + end - req = Net::HTTP::Get.new(uri) + def get() + req = Net::HTTP::Get.new(get_uri()) @http.request(req) end @@ -146,10 +150,12 @@ class Foo @http = Net::HTTP.new(@origin.host, @origin.port) end - def post_foo_by_foo_id(foo_id, bar_id, body:, max_forwards:) - uri = URI("#{@origin}/foo/#{foo_id}?barId=#{bar_id}") + def post_foo_by_foo_id_uri(foo_id, bar_id) + URI("#{@origin}/foo/#{foo_id}?barId=#{bar_id}") + end - req = Net::HTTP::Post.new(uri) + def post_foo_by_foo_id(foo_id, bar_id, body:, max_forwards:) + req = Net::HTTP::Post.new(post_foo_by_foo_id_uri(foo_id, bar_id)) req["Content-Type"] = "application/json" req["Max-Forwards"] = max_forwards @@ -207,10 +213,12 @@ public :: Int -> Req NoContent -> [Text] public indent req = properIndent indent $ [ Nothing - , Just $ "def " <> functionName <> "(" <> argsStr <> ")" - , Just $ " uri = URI(" <> url <> ")" + , Just $ "def " <> functionName <> "_uri(" <> argsStr <> ")" + , Just $ " URI(" <> url <> ")" + , Just "end" , Nothing - , Just $ " req = Net::HTTP::" <> method <> ".new(uri)" + , Just $ "def " <> functionName <> "(" <> allArgsStr <> ")" + , Just $ " req = Net::HTTP::" <> method <> ".new(" <> functionName <> "_uri(" <> argsStr <> "))" ] ++ requestHeaders ++ @@ -225,12 +233,14 @@ public indent req = argsStr :: Text argsStr = T.intercalate ", " $ snake <$> args + allArgsStr :: Text + allArgsStr = T.intercalate ", " $ snake <$> (args ++ bodyAndHeader) + args :: [Text] - args = - captures - ++ ((^. queryArgName.argPath) <$> queryparams) - ++ body - ++ headerArgs + args = captures ++ ((^. queryArgName.argPath) <$> queryparams) + + bodyAndHeader :: [Text] + bodyAndHeader = body ++ headerArgs segments :: [Segment NoContent] segments = filter isCapture paths From 166c90a4988a0e687db43f9bac1dd142e94526e6 Mon Sep 17 00:00:00 2001 From: Stoeffel Date: Thu, 13 Jun 2019 09:30:47 +0200 Subject: [PATCH 08/10] set timeout of requests --- src/Servant/Ruby.hs | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/Servant/Ruby.hs b/src/Servant/Ruby.hs index 9474d57..584fda8 100644 --- a/src/Servant/Ruby.hs +++ b/src/Servant/Ruby.hs @@ -90,9 +90,14 @@ require "net/http" require "uri" class Baz - def initialize(origin) + def initialize(origin, timeout = nil) @origin = URI(origin) @http = Net::HTTP.new(@origin.host, @origin.port) + + unless timeout.nil? + @http.open_timeout = timeout + @http.read_timeout = timeout + end end def get() @@ -114,9 +119,14 @@ require "uri" module Foo module Bar class Baz - def initialize(origin) + def initialize(origin, timeout = nil) @origin = URI(origin) @http = Net::HTTP.new(@origin.host, @origin.port) + + unless timeout.nil? + @http.open_timeout = timeout + @http.read_timeout = timeout + end end def get() @@ -141,9 +151,14 @@ require "net/http" require "uri" class Foo - def initialize(origin) + def initialize(origin, timeout = nil) @origin = URI(origin) @http = Net::HTTP.new(@origin.host, @origin.port) + + unless timeout.nil? + @http.open_timeout = timeout + @http.read_timeout = timeout + end end def post_foo_by_foo_id(foo_id, bar_id, body:, max_forwards:) @@ -197,9 +212,14 @@ properIndent indent = initialize :: Int -> [Text] initialize indent = properIndent indent - [ Just "def initialize(origin)" + [ Just "def initialize(origin, timeout = nil)" , Just " @origin = URI(origin)" , Just " @http = Net::HTTP.new(@origin.host, @origin.port)" + , Nothing + , Just " unless timeout.nil?" + , Just " @http.open_timeout = timeout" + , Just " @http.read_timeout = timeout" + , Just " end" , Just "end" ] From 58399a70828053e0d05fc22006f44eeb480692ca Mon Sep 17 00:00:00 2001 From: Stoeffel Date: Thu, 13 Jun 2019 11:43:40 +0200 Subject: [PATCH 09/10] clean captures in uri method --- src/Servant/Ruby.hs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Servant/Ruby.hs b/src/Servant/Ruby.hs index 6f15b72..2adc7c0 100644 --- a/src/Servant/Ruby.hs +++ b/src/Servant/Ruby.hs @@ -166,6 +166,8 @@ class Foo end def post_foo_by_foo_id_uri(foo_id, bar_id, ids) + foo_id = if foo_id.kind_of?(Array) then foo_id.join(',') else foo_id end + URI("#{@origin}/foo/#{foo_id}?barId=#{bar_id}&#{ ids.collect { |x| 'ids[]=' + x.to_s }.join('&') }") end @@ -236,7 +238,10 @@ public indent req = properIndent indent $ [ Nothing , Just $ "def " <> functionName <> "_uri(" <> argsStr <> ")" - , Just $ " URI(" <> url <> ")" + ] + ++ cleanCaptures + ++ + [ Just $ " URI(" <> url <> ")" , Just "end" , Nothing , Just $ "def " <> functionName <> "(" <> allArgsStr <> ")" From 99af3bb09f1358e76aebf38f346449c165e57323 Mon Sep 17 00:00:00 2001 From: Luke Westby Date: Mon, 24 Jun 2019 20:29:29 -0700 Subject: [PATCH 10/10] It seems you have to explicitly tell the client to use TLS --- src/Servant/Ruby.hs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Servant/Ruby.hs b/src/Servant/Ruby.hs index 9474d57..4d70057 100644 --- a/src/Servant/Ruby.hs +++ b/src/Servant/Ruby.hs @@ -93,6 +93,7 @@ class Baz def initialize(origin) @origin = URI(origin) @http = Net::HTTP.new(@origin.host, @origin.port) + @http.use_ssl = @origin.scheme == 'https' end def get() @@ -117,6 +118,7 @@ module Foo def initialize(origin) @origin = URI(origin) @http = Net::HTTP.new(@origin.host, @origin.port) + @http.use_ssl = @origin.scheme == 'https' end def get() @@ -144,6 +146,7 @@ class Foo def initialize(origin) @origin = URI(origin) @http = Net::HTTP.new(@origin.host, @origin.port) + @http.use_ssl = @origin.scheme == 'https' end def post_foo_by_foo_id(foo_id, bar_id, body:, max_forwards:) @@ -200,6 +203,7 @@ initialize indent = [ Just "def initialize(origin)" , Just " @origin = URI(origin)" , Just " @http = Net::HTTP.new(@origin.host, @origin.port)" + , Just " @http.use_ssl = @origin.scheme == 'https'" , Just "end" ]