The body function in Web.Spock.Action is supposed to return the raw request body. However, it just doesn't seem to be doing that:
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Data.Text.Encoding (decodeUtf8)
import Debug.Trace (trace)
import Web.Spock
import Web.Spock.Config
app :: SpockM () () () ()
app = do
get root $ text "Hello!"
post "test" $ do
b <- body -- b is always ""!
text $ trace ("b="++show b) decodeUtf8 b
main :: IO ()
main = do
spockCfg <- defaultSpockCfg () PCNoDatabase ()
runSpock 3000 (spock spockCfg app)
A curl --data 123123 localhost:3000/test returns nothing, and the trace output confirms that b is an empty string.
Spock is running on port 3000
b=""
The equivalent Scotty app works just fine:
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Data.Text.Lazy.Encoding (decodeUtf8)
import Web.Scotty
main = scotty 3000 $ do
get "/" $ text "Hello!"
post "/test" $ do
b <- body -- works fine
text $ decodeUtf8 b
I absolutely can't see what I'm doing wrong. Any input would be highly appreciated!
Update: Above example will work with Spock >= 0.12.0.0!
Related
I was trying to check that all links work on a Yesod website home page. I wrote this hSpec test.
module Handler.HomeSpec (spec) where
import Data.Either (fromRight)
import qualified Data.Text as T
import Network.Wai.Test (simpleBody)
import TestImport
import Yesod.Test.TransversingCSS (findAttributeBySelector)
getAllLinks :: YesodExample site [Text]
getAllLinks = withResponse $ \res -> do
let links = fromRight [] findAttributeBySelector (simpleBody res) "a" "href"
return $ T.concat <$> links
spec :: Spec
spec = withApp $
describe "Homepage" $ do
it "checks all links" $ do
get HomeR
statusIs 200
links <- getAllLinks
forM_ links $ \oneLink -> do
get HomeR
statusIs 200
get oneLink
statusIs 200
Everything compiles ok but the get function gets rid of the host part of the URLs you feed it. For example, when you give it https://github.com/zigazou/bazasso, it will try to fetch /zigazou/bazasso which returns a 404 code.
Is there a way to make it work like I want ?
Should I add a function that removes external links from the tests ?
Is it simply not the right place to do it ?
The simpler, the better: I've removed everything that starts with a protocol from the links that will be checked. Thanks to #ncaq for your comments.
module Handler.HomeSpec (spec) where
import Data.Either (fromRight)
import qualified Data.Text as T
import Network.Wai.Test (simpleBody)
import TestImport
import Yesod.Test.TransversingCSS (findAttributeBySelector)
isRelative :: Text -> Bool
isRelative url
| T.take 7 url == "http://" = False
| T.take 8 url == "https://" = False
| T.take 7 url == "mailto:" = False
| T.take 4 url == "tel:" = False
| otherwise = True
getAllLinks :: YesodExample site [Text]
getAllLinks = withResponse $ \res -> do
let currentHtml = simpleBody res
links = fromRight [] $ findAttributeBySelector currentHtml "a" "href"
return $ filter isRelative $ T.concat <$> links
spec :: Spec
spec = withApp $
describe "Homepage" $ do
it "checks all links" $ do
get HomeR
statusIs 200
links <- getAllLinks
forM_ links $ \oneLink -> do
get HomeR
statusIs 200
get oneLink
statusIs 200
As per last question about invoking remote RPCs, an additional example to the one included in the documentation would be this one:
$ cat nameko.sh
#!/bin/bash
/usr/local/bin/nameko run service1:Microservice1 &
nameko_id=$!
echo 'Microservice 1 PID: ' $nameko_id
/usr/local/bin/nameko run service2:Microservice2 &
nameko_id=$!
echo 'Microservice 2 PID: ' $nameko_id
wait 2> /dev/null
$ cat service1.py
# -*- coding: utf-8 -*-
from nameko.rpc import rpc, RpcProxy
class Microservice1(object):
name = "microservice1"
#rpc
def hello(self):
print 'Microservice1 hello method invoked'
return True
$ cat service2.py
# -*- coding: utf-8 -*-
from nameko.rpc import rpc, RpcProxy
class Microservice2(object):
name = "microservice2"
microservice1 = RpcProxy('microservice1')
#rpc
def remote_hello(self):
print 'Microservice2 invokes hello method from Microservice1'
self.microservice1.hello()
return True
I am trying to build an architecture where microservices register themselves against a central microservice on startup (basically this central microservice is in charge of displaying a REST API, where each microservice deal with their part of the REST API -this is done to avoid the usage of a reverse proxy and deal with the port numbers-).
In Nameko, how could you launch a remote procedure just when the microservice is registered? As mentioned in the above post's answers, remote RPC invoke can not be done outside a #rpc method.
Actually stand alone proxy as answered here is the way to achive this:
Nameko - invoking RPC method from another service
use the once entrypoint
from nameko.testing.service import once
class Microservice2(object):
name = "microservice2"
microservice1 = RpcProxy('microservice1')
#rpc
def remote_hello(self):
print 'Microservice2 invokes hello method from Microservice1'
self.microservice1.hello()
return True
I'm totally ok with writing a "normal" test capturing the IO for this.
Would just like to know if it is possible to use Doctest.
An example would be:
defmodule CLI do
#doc """
Politely says Hello.
## Examples
iex> CLI.main([])
"Hello dear person." # this would be the expected IO output
"""
def main(args) do
IO.puts "Hello dear person."
end
end
defmodule CLITest do
use ExUnit.Case
doctest CLI
end
You can use the same function as you'd use in a normal test: ExUnit.CaptureIO.capture_io. This might not be a function suited for doctests though when you add more functionality to the function.
defmodule CLI do
#doc """
Politely says Hello.
## Examples
iex> import ExUnit.CaptureIO
iex> capture_io(fn -> CLI.main([]) end)
"Hello dear person.\\n"
"""
def main(args) do
IO.puts "Hello dear person."
end
end
$ mix test
.
Finished in 0.03 seconds
1 test, 0 failures
I want to import some python functions from url for security purposes.
I got a solution from here:
How can a Python module be imported from a URL?
It kind of works; I can run first function (func1) fine, but when I try to run second function (func2) then python says func2 is not defined, why is that so ?
module.py on webserver:
def func1(string):
data = string+"world"
return data
def func2(string):
data = string+"bar"
return data
main.py on my pc:
import urllib
def import_py_from_url(URL):
exec urllib.urlopen(URL).read() in globals()
import_py_from_url("http://somehost.com/module.py")
#try first function
str = "hello "
data = func1(str)
print (data) # OUTPUT: hello world
#try seccond function
str = "foo "
data = func2(str)
print (data) # OUTPUT: NameError: name 'func2' is not defined
Is it even possible to do what i am trying to achive ? Not much info about it around.
How can I emulate this Python idiom in OCaml?
if __name__=="__main__":
main()
See RosettaCode for examples in other programming languages.
There is no notion of main module in Ocaml. All the modules in a program are equal. So you can't directly translate this Python idiom.
The usual way in Ocaml is to have a separate file containing the call to main, as well as other stuff like command line parsing that only make sense in a standalone executable. Don't include that source file when linking your code as a library.
There is a way to get at the name of the module, but it's rather hackish, as it is intended for debugging only. It violates the usual assumption that you can rename a module without changing its behavior. If you rely on it, other programmers reading your code will curse you. This method is provided for entertainment purposes only and should not be used in real life.
let name_of_this_compilation_unit =
try assert false with Assert_failure (filename, _, _) -> filename
You can compare the name of the compilation unit with Sys.executable_name or Sys.argv.(0). Note that this is not really the same thing as the Python idiom, which does not rely on the toplevel script having a particular name.
$ ocamlc -o scriptedmain -linkall str.cma scriptedmain.ml
$ ./scriptedmain
Main: The meaning of life is 42
$ ocamlc -o test -linkall str.cma scriptedmain.ml test.ml
$ ./test
Test: The meaning of life is 42
scriptedmain.ml:
let meaning_of_life : int = 42
let main () = print_endline ("Main: The meaning of life is " ^ string_of_int meaning_of_life)
let _ =
let program = Sys.argv.(0)
and re = Str.regexp "scriptedmain" in
try let _ = Str.search_forward re program 0 in
main ()
with Not_found -> ()
test.ml:
let main () = print_endline ("Test: The meaning of life is " ^ string_of_int Scriptedmain.meaning_of_life)
let _ =
let program = Sys.argv.(0)
and re = Str.regexp "test" in
try let _ = Str.search_forward re program 0 in
main ()
with Not_found -> ()
Posted on RosettaCode.