IHP - How to write a custom response at the end of an action? - ihp

I have POST action that ends in a custom IO operation. The server sends a 500 Internal Server Error even if the operation was successful. I need to send a custom response to deal with this. How should I do this?
My action is like this:
action MyAction { .. } = do
.
.
.
customIO
responseStatusShouldBe customResponse status200
How should I build customResponse?

So customIO has type customIO :: IO Response?
If that's the case you can do:
action MyAction = do
response <- customIO
respondAndExit response
Here's an example from the IHP codebase itself where ErrorController.buildNotFoundResponse is of type IO Response:
renderNotFound :: (?context :: ControllerContext) => IO ()
renderNotFound = do
response <- ErrorController.buildNotFoundResponse
respondAndExit response
The buildNotFoundResponse is defined here.

Related

Is there a way for postman to read the response data from a GET request and then use an IF THEN statement to run a POST request?

I am trying to run a script where postman sends a Get request, and if the get response contains a certain variable to then run a Post request. How do i do this?
(also is there a way to run a get request hourly)
In pre-requisite add:
// set initial value
const method = pm.variables.get("method")
// set initial value as GET if method is undefined
method ? null : pm.variables.set("method", "GET")
// Set this as method
pm.request.method =method
in test script add :
// the condition check
if (pm.response.json().somevalue === "somevalue") {
//then change the method
pm.variables.set("method", "POST")
//call the same request again using setNExtRequest
// pm.info.reqeustName gives current request's name
postman.setNextRequest(pm.info.requestName)
}

Reactive Spring - Request body is missing -

I have a Reactive Rest Controller that makes a POST call along with Flux<> Request Body.
I want to do sequential steps in this Post call
Validate Request Body input
Delete all rows based on one field inside Request Body.
Save all data from this Flux Request Body
Return all updated saved data from Flux to Controller
Sample Code
public Mono<Boolean> update(Flux<RequestBody> body, Long id) {.
return body.
.flatMap(d -> this.repo.deleteCriteria(id, d.getValue);
.thenMany(body)
.flatMap(m-> {mapper to convert from DTO to Entity});
.flatMap(s -> this.repo.save(s.name, s.data)
.then(c -> this.repo.findById(id).count)
.then(n-> n.intValue() > 0 ? Mono.just(true) : Mono.just(false));
}.
Controller code -
#ResponseStatus(HttpStatus.CREATED).
#PostMapping("/abc").
public Mono<ResponseEntity<Void> update(Long id, Flux<Body> body) {
Mono<Boolean> onSuccess = this.service.update(id, body);
onSuccess
.log()
.flatMap(b -> b ? Mono.just(new ResponseEntity<>(HttpStatus.CREATED) :
Mono.just(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR));
}
I see in Logs that Delete statement getting executed n times. Ideally I wanted it only one time to run but I only know flatMap().
But after delete statement I see below error in logs.
"Error - 400 Bad Request - Request body is missing ....."
FYI - Before when I only had a delete statement and I was not fetching value from Flux Request Body everything was working fine.
Please let me know if there is a way to
read values from Request Body and do validations.
perform multiple operations on this Request body like Delete, save and find by reading some values from the RequestBody.
Any help appreciated :)

How to write a test for an http get request in elm

I'm trying to check the data received after sending a request and for that I need to write a test to make sure of it.
These are the three functions handling the data.
fetchConfigs : Cmd Msg
fetchConfigs =
Http.get
{ url = "http://localhost:8080/api/sso/configs"
, expect = Http.expectJson GotConfigs responseDecoder
}
responseDecoder : Decoder Config
responseDecoder =
map2 Config
(field "identifier" string)
(field "ssoType" int)
type Msg
= GotConfigs (Result Http.Error Config)
Have a look at https://package.elm-lang.org/packages/avh4/elm-program-test/latest/ProgramTest. From the package description:
This module allows you to interact with your program by simulating
user interactions and external events (like HTTP responses and ports),
and making assertions about the HTML it renders and the external
requests it makes.

How to avoid Expect msg with HTTP 2.0.0 in elm?

In elm's Http 1.0.0 package, I could send a custom request like:
post : Endoint -> List (Http.Header) -> Http.Body -> Decoder a -> Http.Request a
post url headers body decoder =
Http.request
{ method = "POST"
, headers = headers
, url = url
, body = body
, expect = Http.expectJson decoder
, timeout = Nothing
, withCredentials = False
}
With the post function I wrote above, I can simply call it with, say, a Decoder String, and after the Http request sends, the response string will be decoded and returned. period. No need to create a Msg like:
type Msg
= GotText (Result Http.Error String)
And no need to write a branch in update to handle this Msg.
However, as of Http 2.0.0, the expect argument is of type Expect msg, not Expect a, meaning that writing the Msg variation and additional branch to update will now be required.
I am writing an Api.elm file which makes Http requests. However, this means that now it will have to have its own Msg type and update function to run after these requests respond.
I used to think that Home.elm should only respond to messages from Home.Msg and Home.update not Api.Msg and Api.update. Am I wrong? Should Api.elm have its own Msg type and update function that changes other pages? Or would there be a better way to do this?
To clarify what I was explaining in my question:
A custom request in Elm's HTTP 2.0.0 package looks like this:
request :
{ method : String
, headers : List Header
, url = String
, body = Body
, expect = Expect msg
, timeout = Maybe Float
, withCredentials = Maybe String
}
-> Cmd msg
Wheras in Http 1.0.0 it looked like this:
request :
{ method : String
, headers : List Header
, url : String
, body : Body
, expect : Expect a
, timeout : Maybe Float
, withCredentials : Bool
}
-> Request a
The difference is that using the custom request from HTTP 2.0.0, I needed to pass-in a Msg to use this request.
Now, my problem was: I was using an Api.elm file. Every time I needed to issue an HTTP request, I would call Api.request arg1 arg2... from, say, Login.elm.
Since the request function in Api.elm demanded a Msg type, for, in this case, a login request I thought I would have to define a Msg of GotLogin within Api.elm and then handle how GotLogin would update Login.elm by writing an update branch for GotLogin within Api.elm.
However, I could just define a GotLogin Msg in Login.elm and pass that into Api.request. Since I've defined GotLogin in Login.elm, I would put a GotLogin branch in the update function of Login.elm, instead of Api.elm.
This also applies for any other request type from any other page (Signup.elm, Home.elm,...), meaning that Api.elm, should not have its own update function that updates other pages.
The whole point of Login.elm having its own update function, is that it should only be affected by the branches of its own update function, not ones from Api.elm.

Alamofire returning status Failure Always

I am using Alamofire in my App. This is my Alamofire request code
let params: [String:AnyObject] = ["email": self.signin_Email.text!, "password": self.signin_Password.text!]
Alamofire.request(.GET, "http://DomainName/api/App/Sign_Up", parameters: params, encoding:.JSON)
.responseJSON { response in
debugPrint(response)
}
when i put debugPrint(reponse)
what i got is this
[Request]: { URL:
http://Domain/api/App/Sign_Up } [Response]: nil [Data]:
0 bytes [Result]: FAILURE: Error Domain=NSURLErrorDomain Code=-1017
"cannot parse response" UserInfo={NSUnderlyingError=0x7ffe0840e700
{Error Domain=kCFErrorDomainCFNetwork Code=-1017 "(null)"
UserInfo={_kCFStreamErrorCodeKey=-1, _kCFStreamErrorDomainKey=4}},
NSErrorFailingURLStringKey=http://Domain/api/App/Sign_Up,
NSErrorFailingURLKey=http://Domain/api/App/Sign_Up,
_kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-1, NSLocalizedDescription=cannot parse response}
Here i am always getting the response status as Failure. I am not able to figure out what's going on. (using mvc4 as backend).
This is the Api method that accepts the above given request and returns a JSON Data
[System.Web.Http.HttpGet]
public JsonResult Sign_Up(string email,string password)
{
email = email;
password = password;
System.Web.Mvc.JsonResult usertoreturn = new System.Web.Mvc.JsonResult();
SignUpViewModel signupviewmodel = new SignUpViewModel();
usermodeltocheck.SetPassword(password);
usermodeltocheck.MembershipDate = DateTime.Now;
usermodeltocheck.IsMember = true;
usermodeltocheck.PublicKey = Guid.NewGuid().ToString("N");
usermodeltocheck.MembershipStatus = true;
usertoreturn.Data = Helper.UpdateUser(usermodeltocheck);
}
usertoreturn.JsonRequestBehavior = System.Web.Mvc.JsonRequestBehavior.AllowGet;
return usertoreturn;
}
UPDATE #1 I have created a new method named test that accepts a parameter.The method just returns the parameter value .I tried the sample code available in Github and its working. I am able to get proper response if I am avoiding parameters argument in Alamofire request Method. like
Alamofire.request(.GET, "http://DomainName/api/App/Test", encoding: .JSON).responseJSON{
response in
debugPrint(response)
}
here I am getting a SUCCESS response. I have updated my code like this
Alamofire.request(.GET, "http://DomianName/api/App/Test?test=testing", encoding: .JSON).responseJSON{
response in
debugPrint(response)
}
here also I am getting SUCCESS response. The Error occurs when I pass parameter value to the argument parameters parameters: ["test":"testing"].
also I set my parameters like this
let params = ["test":"testing"]
Alamofire.request(.GET, "http://DomianName/api/App/Test", parameters : params ,encoding: .JSON).responseJSON{
response in
debugPrint(response)
}
in this way also i am getting my response to FAILURE
May be its not an answer you are looking for but for me removing a parameter from Alamofire request method did the trick. Here is the change:
let params : [String:AnyObject] = ["email":self.signin_Email.text!,"password":self.signin_Password.text!]
let request = Alamofire.request(.GET, "http://DomianName/api/App/Sign_Up", parameters: params).responseJSON{
response in
switch response.result{
case .Success(let data) :
let json = JSON(data)
print(json)
case .Failure(let error):
print("Error : \(error)" )
}
}
I have removed encoding:.JSON from my Alamofire request method parameter list and that's it...
Try to print out all the data in response using the following:
let URLString = "http://DomainName/api/App/Sign_Up"
Alamofire.request(.GET, URLString, parameters: params, encoding:.JSON)
.responseJSON { response in
debugPrint(response)
}
Once you print it out, if you could update your question, we could help further. I'll update my answer accordingly afterwards. 👍🏼
Update #1
Okay, so the NSURLErrorDomain Code=-1017 points out that your server is most likely misbehaving. Are you able to successfully use cURL, Postman, Paw or some other HTTP client to hit the service? Once you get one of those working, you should use debugPrint on the `request object to compare.
let URLString = "http://DomainName/api/App/Sign_Up"
let request = Alamofire.request(.GET, URLString, parameters: params, encoding:.JSON)
.responseJSON { response in
debugPrint(response)
}
debugPrint(request)
This will show you the cURL command for the request.
I know this is kind of old but I stumbled upon this looking for something else. From what I have seen, I tend to get errors in this situation any time params are passed as JSON encoded with a .GET instead of a .POST
Changing the server to take a post for the URI makes everything flow correctly, and I guess in theory that is correct behavior, since if you aren't passing the values in the URL, you are technically posting the JSON to the endpoint.