How to display a Servant type signature as URL? [duplicate] - api

Suppose we have this simple API:
type FooAPI
= "foo"
:> QueryParam "age" Int
:> Get '[PlainText] Text
Is there a way to link type-level servant's API with a function that will generate URL for it? Like
someMagicFunction :: Proxy api -> SomeTypeFamily api
someMagicFunction = ?
generateURL :: Maybe Int -> Text
generateURL = someMagicFunction (Proxy #FooAPI)
>>> generateURL (Just 42)
"https://somehost/foo?age=42"
>>> generateURL Nothing
"https://somehost/foo"
I want to increase type-safety of URL generation so if I'll add some new parameter to FooAPI it will immediately appear in the type of generateURL and my code will not compile without editing the calls of generateURL.
I'm aware of servant-client library and I know that client function does somewhat similar but I couldn't figure out how to use this library in my case.

I would say that Servant.Links is exactly what you are looking for.
In particular, in your case I would use allLinks to generate a Link corresponding to the URL piece containing the path and query parameters:
>>> linkURI $ allLinks (Proxy #FooAPI) Nothing
foo
>>> linkURI $ allLinks (Proxy #FooAPI) (Just 18)
foo?age=18
Then I would transform the generated Link into an URI where I would specify required scheme and hostname. Here's a fully working module:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
import Data.Proxy
import Data.Text (Text)
import Network.URI
import Servant.API
import Servant.Links
type FooAPI
= "foo"
:> QueryParam "age" Int
:> Get '[PlainText] Text
generateURL :: Maybe Int -> String
generateURL age = show uri
{ uriScheme = "https:"
, uriAuthority = Just nullURIAuth
{ uriRegName = "somehost" }
, uriPath = "/" <> uriPath uri
}
where
uri = linkURI link
link = allLinks (Proxy #FooAPI) age
And demonstration:
>>> generateURL (Just 42)
"https://somehost/foo?age=42"
>>> generateURL Nothing
"https://somehost/foo"

Related

If then else implementation to chose baseURL in Karate DSL

I have a little tricky requirement in Karate. I have a set of baseURL's in my karate.config which are chosen based on the implementation. Here is the snippet of it:
if (env == 'qa') {
config.apiKey = apiKey;
config.tsp_api = 'https://api.qa.tceu.net';
config.svt_dcm = 'https://svt.qa.tceu.net';
config.acn_dcm = 'https://acn.qa.tceu.net';
config.sos_dcm = 'https://sos.qa.tceu.net';
config.cust_dcm = 'https://cust.qa.tceu.net';
Here tsp,svt,acn,sos,cust are some actions.
I have a feature file which passes the action as a parameter:
# Vehicle Initiates the action
When def Perform_Report_Notification = call read('./../common/performActionNotification.feature') { action: '#(action)' }
In the called performActionNotification.feature, I need to pick up the url from the karate.config file based on the action that is passed. For example if the action is sos, then the url should be sos_dcm. If the action is svt then the url should be svt_dcm
Here is the snippet from performActionNotification.feature and what I am currently doing for sos:
Given url sos_dcm
And path '/AU/v1.0/TSP/'+ action
And request RequestPayload
When method post
Then status 200
I want to implement something like an if then else similar to:
if (action == 'sos')
then myurl == 'sos_dcm'
else if (action == 'acn')
then myurl == 'acn_dcm'
else if (action == 'svt')
then myurl == 'svt_dcm'
Given url myurl
And...
And...
...
I tried a sort of a hack and it works but its not a clean way of doing it. Instead of reading the URL from karate.config I am hardcoding it this way:
Given url 'https://'+act+'.qa.tceu.net'
One more thing I tried was
* def myurl = action +'_dcm' #so if action is acn then the variable myurl would be acn_dcm
Given url myurl
...
....
But this hardcodes the url as 'acn_dcm' instead of picking the defined url up from karate.config.
Can someone kindly suggest the best way to implement this?
Here is a hint. JSON is actually a pretty useful data-structure (think hash-map or dictionary) and you can lookup a value without needing an if statement.
* def data =
"""
{
qa: {
sos: 'https://sos.qa.tceu.net',
acn: 'https://acn.qa.tceu.net'
}
}
"""
* def env = 'qa'
* def urls = data[env]
* def action = 'sos'
* def actionUrl = urls[action]
* match actionUrl == 'https://sos.qa.tceu.net'
This should get you on your way :)
EDIT - also see this: https://stackoverflow.com/a/67868935/143475
I've finally used Peter's most elegant solution and it works like a charm!
Here's what I've finally implemented that does not need hardcoding of the endpoint URL's and is driven by endpoints in the karate.config file.
* def data =
"""
{
qa: {
sos: '#(sos_dcm)', # sos_dcm endpoint defined in karate.config file
acn: '#(acn_dcm)',
svt: '#(svt_dcm)'
}
}
"""
* def env = karate.properties['env']; # Driven by maven commandline arg -Denv=qa as an example
* def urls = data[env]
* def action = act # act comes from the calling feature file and has values - sos/acn/svt
* def myUrl = urls[action]
Given url myUrl
...
...
I would suggest looking into using javascript for your conditional logic
So the javascript function takes a param of action and then the if and else statements returns the variable of the url that you need.
Perform the javascript function before you make the request call. and use the variable that is returned by js to determine the logic.
make that js file a common function that can be accessed by multiple feature files.
function determineUrl(action) {
var url = "${urDefaultUrl}";
if (action == "sos") url == "${full url}";
else if (action == "acn") url == "${full url}";
return url;
}
Then in your feature file
* def urlDecider = 'classpath to your js function'
* myUrl = urlDecider(action)
* url myUrl
* Given path ....
For the sake of the community learning, there is one other way I figured out on similar lines of Jawad's solution is using a Java function. They do exactly the same thing as Jawad's solution but just that its a java class doing it. If a project has java class files, then to maintain consistency this solution can be used too.
Here is the how the class file looks:
public class DCMUrlDecider {
static String dcmURL="";
public static String getDCMUrl(String action) {
if (action.matches("sos"))
{
dcmURL = "https://sos.qa.tceu.net";
}
else if (action.matches("acn"))
{
dcmURL = "https://acn.qa.tceu.net";
}
else if (action.matches("svt"))
{
dcmURL = "https://svt.qa.tceu.net";
}
return dcmURL;
}
}
And here is the associated code snippet from the feature file:
* def dcmURLDecider = Java.type('com.TCEU.KarateTests.DCMUrlDecider')
* def myUrl = dcmURLDecider.getDCMUrl(act)
Given url myUrl
....
.....
Once again this means we are still hardcoding URLs in the java class files. Need to learn a way of doing it via karate.config files if possible.

Validation of dynamic text in testing

I am trying to validate a pin code in my application. I am using Katalon and I have not been able to find an answer.
The pin code that I need to validate is the same length but different each time I run the test and looks like this on my page: PIN Code: 4938475948.
How can I account for the number changing each time I run the test?
I have tried the following regular expressions:
assertEquals(
"PIN Code: [^a-z ]*([.0-9])*\\d",
selenium.getText("//*[#id='RegItemContent0']/div/table/tbody/tr/td[2]/table/tbody/tr[2]/td/div[1]/div[3]/ul/li[2]/span")
);
Note: This was coded in Selenium and converted to Katalon.
In Katalon, use a combination of WebUI.getText() and WebUI.verifyMatch() to do the same thing.
E.g.
TestObject object = new TestObject().addProperty('xpath', ConditionType.EQUALS, '//*[#id='RegItemContent0']/div/table/tbody/tr/td[2]/table/tbody/tr[2]/td/div[1]/div[3]/ul/li[2]/span')
def actualText = WebUI.getText(object)
def expectedText = '4938475948'
WebUI.verifyMatch(actualText, expectedText, true)
Use also toInteger() or toString() groovy methods to convert types, if needed.
Editing upper example but to get this working
TestObject object = new TestObject().addProperty('xpath', ConditionType.EQUALS, '//*[#id='RegItemContent0']/div/table/tbody/tr/td[2]/table/tbody/tr[2]/td/div[1]/div[3]/ul/li[2]/span')
def actualText = WebUI.getText(object)
def expectedText = '4938475948'
WebUI.verifyMatch(actualText, expectedText, true)
This can be done as variable but in Your case I recommend using some java
import java.util.Random;
Random rand = new Random();
int n = rand.nextInt(9000000000) + 1000000000;
// this will also cover the bad PIN (above limit)
I'd tweak your regex just a little since your pin code is the same length each time: you could limit the number of digits that the regex looks for and make sure the following character is white space (i.e. not a digit, or another stray character). Lastly, use the "true" flag to let the WebUI.verifyMatch() know it should expect a regular expression from the second string (the regex must be the second parameter).
def regexExpectedText = "PIN Code: ([0-9]){10}\\s"
TestObject pinCodeTO = new TestObject().addProperty('xpath', ConditionType.EQUALS, '//*[#id='RegItemContent0']/div/table/tbody/tr/td[2]/table/tbody/tr[2]/td/div[1]/div[3]/ul/li[2]/span')
def actualText = WebUI.getText(pinCodeTO)
WebUI.verifyMatch(actualText, expectedText, true)
Hope that helps!

Can't change the language in microsoft cognitive services spellchecker

Here is the Microsoft Python example of using spellchecker API:
import http.client, urllib.parse, json
text = 'Hollo, wrld!'
data = {'text': text}
# NOTE: Replace this example key with a valid subscription key.
key = 'MY_API_KEY'
host = 'api.cognitive.microsoft.com'
path = '/bing/v7.0/spellcheck?'
params = 'mkt=en-us&mode=proof'
headers = {'Ocp-Apim-Subscription-Key': key,
'Content-Type': 'application/x-www-form-urlencoded'}
# The headers in the following example
# are optional but should be considered as required:
#
# X-MSEdge-ClientIP: 999.999.999.999
# X-Search-Location: lat: +90.0000000000000;long: 00.0000000000000;re:100.000000000000
# X-MSEdge-ClientID: <Client ID from Previous Response Goes Here>
conn = http.client.HTTPSConnection(host)
body = urllib.parse.urlencode(data)
conn.request ("POST", path + params, body, headers)
response = conn.getresponse()
output = json.dumps(json.loads(response.read()), indent=4)
print (output)
And it works well for mkt=en-us. But if I try to change it, for example to 'fr-FR'. It always answers me with a blank response to any input text.
{
"_type": "SpellCheck",
"flaggedTokens": []
}
Has anybody encountered the similar problem? May it be connected with my trial api key (though they do not mention that trial supports only English)?
Well, I've found out what the problem was. 'mode=proof' — advanced spellchecker currently available only if 'mkt=en-us' (for some Microsoft reasons it does not available even if 'mkt=en-uk'). For all other languages, you should use 'mode=spell'.
The main difference between 'proof' and 'spell' is described like this:
The Spell mode finds most spelling mistakes but doesn't find some of the grammar errors that Proof catches (for example, capitalization and repeated words).

Elm seed for Random.initialSeed - prefer current time [duplicate]

This question already has answers here:
elm generate random number
(2 answers)
Closed 7 years ago.
What's a simple way to do this?
The documentation for Random.initialSeed says:
"A good way to get an unexpected seed is to use the current time."
http://package.elm-lang.org/packages/elm-lang/core/2.1.0/Random#initialSeed
After a ton of reading, I can only find "solutions" that are well beyond my understanding of Elm and Functional Programming. They also don't seem to be solutions to this problem.
I'm currently hardcoding:
Random.initialSeed 314
If you use a library, please include the name used to get it from elm package. I've seen a solution that says use Native.now but I can't figure out how to get that one.
stackoverflow is suggesting this one but I can't understand how to apply it to my usecase Elm Current Date
You can try case nelson's answer from How do I get the current time in Elm?
From elm repl:
> import Now
> import Random
> Now.loadTime |> round -- get current time in Int
1455406828183 : Int
> Now.loadTime |> round |> Random.initialSeed -- get the Seed
Seed { state = State 1560073230 678, next = <function>, split = <function>, range = <function> }
: Random.Seed
I also have the code on my repo here.
Note: don't forget "native-modules": true in elm-package.json.
Edit:
to try the code,
git clone https://github.com/prt2121/elm-backup.git
cd elm-backup/now
elm make Now.elm
add "native-modules": true in elm-package.json
elm repl
The simplest way I can think of is to use the Elm Architecture and Effects.tick mechanism to initialise the seed with a time value.
Here is an example of how this works:
import Html exposing (..)
import Html.Events exposing (onClick)
import Random exposing (Seed, generate, int, initialSeed)
import Time exposing (Time)
import Effects exposing (Effects, Never)
import Task exposing (Task)
import StartApp
type alias Model = { seed : Seed, value : Int}
type Action = Init Time | Generate
init : (Model, Effects Action)
init = (Model (initialSeed 42) 0, Effects.tick Init)
modelFromSeed : Seed -> (Model, Effects Action)
modelFromSeed seed =
let
(value', seed') = generate (int 1 1000) seed
in
(Model seed' value', Effects.none)
update : Action -> Model -> (Model, Effects Action)
update action model =
case action of
Init time ->
modelFromSeed (initialSeed (round time))
Generate ->
modelFromSeed model.seed
view : Signal.Address Action -> Model -> Html
view address model =
div []
[ text ("Current value: " ++ (toString model.value))
, br [] []
, button [onClick address Generate] [text "New Value"]
]
app : StartApp.App Model
app = StartApp.start
{ init = init
, update = update
, view = view
, inputs = []
}
main : Signal Html
main = app.html
port tasks : Signal (Task Never ())
port tasks = app.tasks

How to use detailed-0.9 in cabal testing

I'm having a surprising amount of difficulty getting the unit tests to run under cabal. I've copied the test code verbatim from the cabal documentation, with the exception of changing the module name
{-# LANGUAGE FlexibleInstances #-}
module Test.Integral ( tests ) where
import Distribution.TestSuite
instance TestOptions (String, Bool) where
name = fst
options = const []
defaultOptions _ = return (Options [])
check _ _ = []
instance PureTestable (String, Bool) where
run (name, result) _ | result == True = Pass
| result == False = Fail (name ++ " failed!")
test :: (String, Bool) -> Test
test = pure
-- In actual usage, the instances 'TestOptions (String, Bool)' and
-- 'PureTestable (String, Bool)', as well as the function 'test', would be
-- provided by the test framework.
tests :: [Test]
tests =
[ test ("bar-1", True)
, test ("bar-2", False)
]
However, when I try to build the tests, I get the following messages:
Test/Integral.hs:6:10:
Not in scope: type constructor or class `TestOptions'
Test/Integral.hs:12:10:
Not in scope: type constructor or class `PureTestable'
I tried importing them directly from Distribution.TestSuite, but it said that they weren't exported. This is simple enough that I have to be doing something stupid, but I can't see what it is.
But for what it's worth, here is some code that works:
module Main (tests) where
import Distribution.TestSuite
tests :: IO [Test]
tests = do
return [
test "foo" Pass
, test "bar" (Fail "It did not work out!")
]
test :: String -> Result -> Test
test name r = Test t
where
t = TestInstance {
run = return (Finished r)
, name = name
, tags = []
, options = []
, setOption = \_ _ -> Right t
}
There is not much support for detailed-0.9 out there. It's possible to hook up existing testing libraries to use it, but even then you will not get progress information as tests pass.
I recommend to use the exitcode-stdio-1.0 interface together with an existing testing framework + use GHCi during development.
A full example for Hspec is here https://github.com/sol/hspec-example.