how to create dynamic http body in elm - api

I am implementing the service where i have to create the dynamic http post request and my code is below.
postRequest: Int -> Http.Request
postRequest catId =
let
body =
"""{"categoryId:"""++catId++""","coupon":false,"domainId":1,"locations":[],"onlineMenu":false,"onlineOrder":false,"pageNo":1,"pageSize":10,"reservation":false,"searchText":"","subcategories":[]}"""
in
{ verb = "POST"
, headers =
[("Content-Type", "application/json")
]
, url = "http://xyz/businesses/list"
, body = Http.string body
}
but i am getting some error
how to concatenate the catId in the body and catId is integer type.
please anyone suggest what i have did wrong in the implementation.

As you declared catId as Int not String, so
(++) : String -> String -> String cannot not work on it.
You can use toString : a -> String before concatenating it with strings.
"categoryId:" ++ (toString catId)

Related

Avoid Http Race Condition in Elm

Let's assume we have a text input field and on every change of its content we send an Http request to a search API. Now, we don't have any guarantee that the Http responses get back to elm in the same order that we sent the requests.
What's the easiest way to make sure we react to the response corresponding to the latest request – rather than the latest response, which might correspond to an outdated search string? Is there an easy way to attach the query string to the message returned by Elm's http effect? Or any other way we can link the response to the request by which it was triggered?
I'd like to avoid including the query in the response of the search API if possible. Another remedy would be to debounce the search, but that would just decrease the probability of using the wrong response, whereas we'd like to eliminate it.
Thanks for your help!
Example:
import Html
import Html exposing (..)
import Html.Events exposing (onClick, onInput)
import Http
import Json.Decode as Decode
main = Html.program
{ init = ( { searchText = "", result = "" }, Cmd.none )
, update = update
, subscriptions = (\model -> Sub.none)
, view = view
}
type alias Model =
{ searchText : String
, result: SearchResult
}
type alias SearchResult = String
type Msg
= NewSearchText String
| ReceivedResponse (Result Http.Error SearchResult)
update msg model =
case msg of
NewSearchText newText ->
( { model | searchText = newText}
, getSearchResult newText
)
ReceivedResponse (Result.Ok response) ->
( { model | result = response }
, Cmd.none
)
ReceivedResponse (Result.Err error) ->
Debug.crash <| (toString error)
getSearchResult : String -> Cmd Msg
getSearchResult query =
let
url = "http://thebackend.com/search?query=" ++ query
request : Http.Request SearchResult
request = Http.get url Decode.string
in
Http.send ReceivedResponse request
view model =
div []
[ Html.input [onInput (\text -> NewSearchText text)] []
, Html.text model.result
]
Yes, it is possible to attach the query string to the response. First, augment your message type to handle the additional data:
type Msg
= NewSearchText String
| ReceivedResponse String (Result Http.Error SearchResult)
Then, change your Http.send call to attach the query text to the ReceivedResponse message:
Http.send (ReceivedResponse query) request
Finally, in your update, grab the query in your pattern match on the resulting Msg:
case msg of
ReceivedResponse query (Ok response) ->
...
ReceivedResponse query (Err err) ->
...
Why does this work?
The Http.send function's first argument can be an arbitrary function that consumes a Result Http.Error SearchResult and turns it into a Msg. In your original code, that function is just ReceivedResponse, the Msg constructor. When the Msg type is updated so that ReceivedResponse takes two arguments, the ReceivedResponse constructor function becomes a curried two-argument function, and ReceivedResponse "some query here" is a one-argument function that takes in a Result and returns a Msg.
Here's one way:
Add two integers to your model:
requestsSent : Int -- the number of requests made.
lastReceived : Int -- the latest request that you've processed.
Modify ReceivedResponse to have an Int as the first value:
| ReceivedResponse Int (Result Http.Error SearchResult)
Now, whenever you make a request, increment requestsSent by 1 in the model and "tag" the request by partially applying ReceivedResponse:
Http.send (ReceivedResponse model.requestsSent) request
In your update function, check if the Int in the ReceivedResponse is greater than lastReceived or not. If it is, process it, and set the value of lastReceived to this response's Int. If it isn't, discard it, because you've already processed a newer request.

How can I refactor two functions into one function that takes a generic argument?

How can I refactor two functions into one function that has a generic parameter?
Example:
getVideo : Video -> Post
getVideo video =
let
(Video post) =
video
in
post
getPodcast : Podcast -> Post
getPodcast podcast =
let
(Podcast post) =
podcast
in
post
I would like to do something like this:
getPodcast : 'a -> Post
getPodcast 'a =
let
('a post) =
'a
in
post
Appendix:
type Video
= Video Post
type Podcast
= Podcast Post
You cannot have such an open-ended generic function in Elm. Here are two options:
Use a container type
You can create a container type that has a constructor for each of its valid types:
type PostContainer
= VideoContainer Video
| PodcastContainer Podcast
Now your getPost function consists of a case statement which returns the appropriate post.
getPost : PostContainer -> Post
getPost container =
case container of
VideoContainer (Video post) ->
post
PodcastContainer (Podcast post) ->
post
Include the post type in the Post value
Let's say your Post object looks like this:
type alias Post =
{ name : String
, body : String
}
You could create an enumeration of post types like this:
type PostType = Video | Podcast
You could redefine Post to include the type:
type alias Post =
{ name : String
, body : String
, postType : PostType
}
Or, if you choose to keep the post body separate from the type, you could do something like this:
type alias PostContents =
{ name : String
, body : String
}
type Post = Post PostType PostContents
and your getPostContents function would simply be
getPostContents : Post -> PostContents
getPostContents _ contents =
contents

How to pass Query String Parameters in GET url using Rest Assured?

How to pass Query String Parameters in GET url using Rest Assured?
URL is: http://example.com/building
My Query Strings are :
globalDates:{"startMs":1473672973818,"endMs":1481448973817,"period":90}
limitTo:6
loadTvData:true
startFrom:0
userId:5834fb36981baacb6a876427
You can pass them as a queryParam ..
given()
.queryParam("globalDates", "{\"startMs\":1473672973818,\"endMs\":1481448973817,\"period\":90}")
.queryParam("startFrom", "0").queryParam("limitTo", "6").queryParam("loadTvData", true)
.queryParam("startFrom", "0").queryParam("userId", "5834fb36981baacb6a876427")
.when().get("http://example.com/building"). ...
And also you can put this queryparams in Map like follows,
HashMap<String, String> params = new HashMap<String, String>() {{
put("globalDates", "{\"startMs\":1473672973818,\"endMs\":1481448973817,\"period\":90}");
put("limitTo","6" );
,...
}}
And post it like follows,
resp = RestAssured.given()
.headers(headers)
.queryParameters(params)
.post(apiURL).andReturn();
QueryParam can be passed as:
String endpoint = "http://example.com/building";
var response = given()
.queryParam("globalDates", "{\"startMs\":1473672973818,\"endMs\":1481448973817,\"period\":90}")
.queryParam("startFrom", "0").queryParam("limitTo", "6").queryParam("loadTvData", true)
.queryParam("startFrom", "0").queryParam("userId", "5834fb36981baacb6a876427")
.when().get(endpoint).then();
For our api with a type like this:
https://my.api.com/meeting?page=0&size=1
We have:
Response response = requestSpecification.queryParam("page", 0).queryParam("size", 1).get(baseEndpoint);
You can pass query string parameters in a GET URL using Rest Assured like this :
when()
.parameter("globalDates","startMs","1474260058054","endMs","1482036058051","period","90")
.parameters("limitTo","6")
.parameters("loadTvData","true")
.parameters("startFrom","0")
.parameters("userId","5834fb36981baacb6a876427");

How to convert Task Http.RawError Http.Response to Task String (Int, Int)

There are a type and a task
type Msg
= Fail String
| Success (Int, Int)
makeRequest =
let
req =
{ verb = "GET"
, headers = []
, url = "http://localhost:8080"
, body = empty
}
in
Task.perform Fail Success <| send defaultSettings req
The argument of Fail constructor is for error message (just "Error"), first argument of Succeess is for status from Http.Response, second is for size of value from Http.Response.
How to convert Task Http.RawError Http.Response to Task String (Int, Int)?
I'm looking at Task.map and Tsk.mapError and I don't understand how to combine them. Am I on a right way?
Yes, you can use Task.map and Task.mapError to achieve your results.
First off, you'll need a way to determine the size of your Http Response. Since it can be either a string or binary blob, and blob is not yet supported, you could define a function like this:
httpValueSize : Http.Value -> Int
httpValueSize val =
case val of
Text str -> String.length str
Blob blob -> Debug.crash "Blobs have no implementation yet"
Now you can use the mapping functions in your task like this:
send defaultSettings req
|> Task.map (\r -> (r.status, httpValueSize r.value))
|> Task.mapError (always "Error")
|> Task.perform Fail Success
You could also do this without the mapping functions like so:
send defaultSettings req
|> Task.perform (always <| Fail "Error") (\r -> Success (r.status, httpValueSize r.value))

sending string parameter in action=track leanplum Rest Api not working

I want to send string parameters in Leanplum api using action script
Eg param:{"Element":"Hi"}
var request:URLRequest = new URLRequest("https://www.leanplum.com/api");
request.method = URLRequestMethod.GET;
var variables:URLVariables = urlVariables;
variables.userId = userId;
variables.event = eventName;
var params:Object = new Object();
params.Element = "Hi";
var paramStr:String = JSON.stringify(params);
variables.params = paramStr;
variables.appId = appId;
variables.clientKey = clientKeyProduction;
variables.apiVersion = apiVersion;
variables.action = "track";
variables.versionName = AppInfo.getInstance().appVersion;
request.data = variables;
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, function(e:Event):void {
trace(e.target.data);
});
loader.addEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent):void {
trace(e.target.data);
});
loader.load(request);
This is actual Request (App ID and ClientKey are dummy):
https://www.leanplum.com/api?clientKey=V42fKaJaBuE&userId=1010&params={"Element":"Ur"}&appId=HEVdDlXiBVLwk&event=Element_Opened&action=track&versionName=2.3.0&apiVersion=1.0.6&info=Lu
Encoded Request:
https://www.leanplum.com%2Fapi%3FclientKey%3DV42fKaJaBuE%26userId%3D1010%26params%3D%7B%22Element%22%3A%22Ur%22
%7D%26appId%3DHEVdDlXiBVLwk%26event%3DElement_Opened%26action%3Dtrack%26versionName%3D2.3.0%26apiVersion%3D1.0.6%26info%3DLu
if I run above request in any rest client I get the same status success : true .
I am getting the response {"response": [{"success": true}]} but I can't find the parameters with value string in Leanplum dashboard, its listing parameter name but not the String Value for parameter.
If you apply some combination of filters then you can see values of parameter you sent to leanplum. like First select the occurrence of some event then apply Group by parameter then select parameter you want to see the data for.
Its a little different from flurry, Google analytics etc.