mocking a request with a payload using wiremock - scala

I'm currently trying to mock external server using Wiremock.
One of my external server endpoint takes a payload.
This endpoint is defined as follow :
def sendRequestToMockServer(payload: String) = {
for {
request_entity <- Marshal(payload).to[RequestEntity]
response <- Http().singleRequest(
HttpRequest(
method = HttpMethods.GET,
uri = "http://localhost:9090/login",
entity = request_entity
)
)
} yield {
response
}
}
To mock this endpoint using Wiremock, I have written the following code :
stubFor(
get(urlEqualTo("/login"))
.willReturn(
aResponse()
.withHeader("Content-Type","application/json")
.withBodyFile("wireMockResponse.json")
.withStatus(200)
)
.withRequestBody(matchingJsonPath("requestBody.json"))
)
where I Have defined the request body in the requestBody.json file.
But when I run tests , I keep getting an error indicating that the requested Url is not found.
I'm thinking that the error is related to this line withRequestBody(matchingJsonPath("requestBody.json")), because when I comment it the error disappear.
Any suggestions on how to work around this?

matchingJsonPath does not populate a file at a provided filepath, but instead evaluates the JsonPath provided. See documentation.
I'm not entirely sure there is a way to provide the request body as a .json file. If you copy the contents of the file into the withRequest(equalToJson(_yourJsonHere_)), does it work? If it does, you could get the file contents as a JSON string above the definition and provide it to the function (or I guess, make a function to return a JSON string from a .json file).
Additionally, you could make a custom request matcher that does the parsing for you. I think I'd recommend this only if the above does not work.

Related

Access nested body property from HTTP resolver(AppSync)

I'm new to AWS AppSync and I am trying to access certain body property(from HTTP response) in my resolver's response mapping template.
For example: I am able to present the response as is via $util.toJson($ctx.result.body), but when I try to get some of the nested body properties it fails.
For example, imagine the body looks like this:
{
about:{
"firstName":"Chuck",
"lastName":"Norris"
}
}
and $util.toJson($ctx.result.body.about) returns null. Any thoughts?
I found a way extract the parsed body in the following way:
#set ($parsed_body = $util.parseJson($ctx.result.body))
And then I am able to access the properties via dot notation:
parsed_body.about.firstName
The part I was missing is $util.parseJson(<json-string>)
It seems that the body is a JSON string.

validating response outside of context manager?

[EDITED: I realized after reading response that I oversimplified my question.]
I am new to Locust and not sure how to solve this problem.
I have function (call it "get_doc") that is passed a locust.HttpSession() and uses it to issue an HTTP request. It gets the response and parses it, returning it up several layers of call. One of these higher-level calls looks at the returned, parsed document to decide if the response was what was expected or not. If not, I want Locust to mark the request/response as failed. A code sketch would be:
class MyUser (HttpUser):
#task
def mytask(self):
behavior1 (self.client)
def bahavior1(session):
doc = get_doc(session, url1)
if not doc_ok (doc):
??? how to register a failure with Locust here...
doc2 = get_doc(session, url2)
...
def get_doc(http_session, url):
page = http_session.get(url)
doc = parse (page)
return doc
There may be several behavior[n] functions and several Locust users calling them.
A constraint is that I would like to keep Locust-specific stuff out of bahavior1() so that I can call it with an ordinary Requests session. I have tried to do something like this in get_doc() (the catch_response parameter and success/fail stuff is actually conditionalized on 'session' being an HttpSession object):
def get_doc (session, meth, url):
resp = session.request (meth, url, catch_response=True)
doc = parse (resp.content)
doc.logfns = resp.success, resp.failure
return doc
and then in behavior1() or some higher up-chain caller I can
doc.logfns[1]("Document not as expected")
or
doc.logfns[0] # Looks good!
Unfortunately this is not working; the calls to them produce no errors but Locust doesn't seem to record any successes or failures either. I am not sure if it should work or I bungled something in my code. Is this feasible? Is there a better way?
You can make get_doc a context manager, call .get with catch_response=True and yield instead of return inside it. Similar to how it is done here: https://github.com/SvenskaSpel/locust-plugins/blob/2cbbdda9ae37b6cbb0a11cf69aca80b164198aec/locust_plugins/users/rest.py#L22
And then use it like this
def mytask(self):
with get_doc(self.client, url) as doc:
if not doc_ok(doc):
doc.failure(”doc was not ok :(”)
If you want, you can add the parsed doc as a field on the response before yielding in your doc function, or call doc.failure() inside doc_ok.

Capture json response value and http status from cpprest sdk pplx task cpp to local variables

I want to write a generic function in cpp that gets JSON data using cpprestsdk and copy the http status response code and the JSON data. The calling method will use the json_resp and http_status codes. Later on, I want to further make this function more generic by passing the URL and use it to get data from different web services. Please let me know how I can accomplish this.
pplx::task<void> handleWebServerRequest( web::json::value json_resp, int *http_status)
{
..
http_client client(L"http://weburl.com:8000/getjsondata");
return client.request(methods::GET).then([](http_response response) -> pplx::task<json::value> {
// Store the http status code to be returned to calling function
*http_status = response.status_code();
..
if(response.status_code() == status_codes::OK) {
return response.extract_json();
}
return pplx::task_from_result(json::value()); }).then([](pplx::task<json::value> previousTask) {
try {
// capture json response to json_resp
json_resp = previousTask.get();
}
catch( const http_exception& e) {
// print error
}
});
}
In my research I have found that the only difference between using cpprest api to consume a PHP web service and a WCF web service is the function parameter. When consuming a PHP web service you can set the function parameter to an empty string. Where as when consuming a WCF service you need to pass it a function parameter-because the protocol for receiving requests and issuing responses in a WCF service is very different, but the process of sending requests and receiving responses is asynchronous so there will always be at least three modules, functions or tasks involved. One to make the request. The other to wait and receive the response and another to parse the data which is called asynchronously by the function that receives the response. I suppose you could put all three tasks into one function and use go to statements to execute each task, perhaps use some inline assembly to capture the response, and use pointers in place of parameters - but it is still three tasks anyway you slice it. The two others run in a thread and do not have access to the application data, but the last function that parses the data (the json object) which is called asynchronously you could make generic. I don't know which web services you want to consume, but I posted two samples on github-Example of Casablanca (cpprestsdk 2.9.1) consuming a PHP web service and Example of Casablanca (cpprestsdk 2.9.1) consuming a WCF (.net) web service. I believe this should get you off to a good start. To capture the json values you can convert your json values to std strings (as shown below) and then you can store them respectively in a local hashmap by adding a hashmap pointer argument to all three functions and passing a reference to the local hashmap variable from which ever function you are calling it from where they can be converted to what ever data type you need.
void get_field_map_json(json::value & jvalue, unordered_map <string, string> * hashmap)
{
if (!jvalue.is_null())
{
for (auto const & e : jvalue.as_object())
{
std::string key(conversions::to_utf8string(e.first));
std::string value(conversions::to_utf8string(e.second.as_string()));
(*hashmap)[key] = value;
}
}

Invalid_request_parameter (create and sending envelopes)

I'm trying to use a service of DocuSign API in an abap project. I want to send a document to a specific email so it can be signed. But im getting the following error:
"errorCode": "INVALID_REQUEST_PARAMETER",## "message": "The request contained at least one invalid parameter. Query parameter 'from_date' must be set to a valid DateTime, or 'envelope_ids' or 'transaction_ids' must be specified.
I tried the following:
CALL METHOD cl_http_client=>create_by_url
EXPORTING
url = l_url (https://demo.docusign.net/restapi/v2/accounts/XXXXXX')
proxy_host = co_proxy_host
proxy_service = co_proxy_service
IMPORTING
client = lo_http_client
lo_http_client->request->set_method( method = 'POST').
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'Accept'
value = 'application/json'.
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'X-DocuSign-Authentication'
value = get_auth_header( ). (json auth header)
CALL METHOD lo_http_client->request->set_cdata
EXPORTING
data = create_body( ).
This is my body:
CONCATENATE
`{`
`"emailSubject": "DocuSign REST API Quickstart Sample",`
`"emailBlurb": "Shows how to create and send an envelope from a document.",`
`"recipients": {`
`"signers": [{`
`"email": "test#email",`
`"name": "test",`
`"recipientId": "1",`
`"routingOrder": "1"`
`}]`
`},`
`"documents": [{`
`"documentId": "1",`
`"name": "test.pdf",`
`"documentBase64":` `"` l_encoded_doc `"`
`}],`
`"status": "sent"`
`}` INTO re_data.
The api request to get the Baseurl is working fine. (I know the error is quite specific what the problem is, but i cant find any sources on the docusign api documentation that one of the mentioned parameters should be added to the request)
Thank you in regards
The error message seems to indicate that you're Posting to an endpoint that requires certain query string parameters -- but you're not specifying them as expected in the query string. I'd suggest you check the DocuSign API documentation for the operation you are using, to determine what query string parameters it requires, and then ensure that you're including those parameters in your request URL.
If you can't figure this out using the documentation, then I'd suggest that you update your post to clarify exactly what URL (endpoint) you are using for the request, including any querystring parameters you're specifying in the URL. You can put fake values for things like Account ID, of course -- we just need to see the endpoint you are calling, and what qs params you're sending.
To create an envelope, use
https://demo.docusign.net/restapi/v2/accounts/XXXXXX/envelopes
instead of
https://demo.docusign.net/restapi/v2/accounts/XXXXXX
Thank you for all the answers, i found the mistake. Creating the request wasn´t the problem. I was using the wrong "sending"-method -_-.
now its working :)
lo_rest_client->post( EXPORTING io_entity = lo_request_entity ).

Web API calls with RestSharp - prepends application/json to body causing null parameter on action

I have a Web API service that I'm trying to access via the console using RestSharp. My RestSharp code looks like this:
RestClient client = new RestClient(baseUrlString);
RestRequest request = new RestRequest("controllername/actionname");
request.RequestFormat = DataFormat.Json;
ProcessQuestion model = new ProcessQuestion()
{
Id = "123456",
InstanceId = "123",
UniqueId = "bfb16a18-d0d6-46ab-a5b3-2f0ebbfe8626",
PostedAnswer = new Dictionary<string, string>() { { "question_7907_1", "selected" }, { "question_7907_2", "selected" } }
};
request.AddBody(model);
var response = client.Execute(request)
My Web API action takes a model that has the same parameters as the above model. When the call executes, the binding fails and the parameter is null. I suspect this is due to the RestRequest.AddBody method prepending application/json to the body value as shown below:
{application/json={"Id":"123456","InstanceId":"123","UniqueId":"bfb16a18-d0d6-46ab-a5b3-2f0ebbfe8626","PostedAnswer":{"question_7907_1":"selected","question_7907_2":"selected"}}}
If I post using Fiddler the body binds to the model properly. Below is the body value I provided in Fiddler:
{'Id':'123456','InstanceId':'123','Uniqueid':'bfb16a18-d0d6-46ab-a5b3-2f0ebbfe8626','PostedAnswer':{'question_7907_1':'selected','question_7907_2':'selected'}}
Note that the body value in fiddler is the same with the exception of prepending the application/json key.
Also to note: I've tried what seems like everything...I've separated the parameters out in the action, used FromBody and FromUri attributes, tried custom DictionaryModelBinder's, tried custom ValueBinders, tried changing the way I'm using RestSharp (AddParameter with a RequestBody parameter, AddObject, different URL styles, etc.).
Has anyone else encountered this, and if so, did you solve it? I chose Web API for this service with hopes the model binding would work as it does in MVC, but I'm seeing that isn't the case.
Thanks
EDIT (resolved):
RestSharp automatically uses the JsonSerializer for objects passed in the AddBody method. I figured I was missing something simple, and indeed I was... Adding the Method.Post parameter to the RestRequest instantiation solved the problem.
Specify the method when creating the request:
RestRequest request = new RestRequest("controllername/actionname", Method.POST);
Not sure what the default serializer is for body - you can try making it explicit:
request.AddBody(request.JsonSerializer.Serialize(model));
I'm not sure where the 'application/json' is coming from - that's the Content-Type header you should be sending with your request, definitely not part of the body. So do this instead:
request.AddHeader("Content-type", "application/json; charset=utf-8");
If this doesn't help, try making your code as similar to the example on their site as possible. Try removing complexity (even if it means changing the required functionality) - get it to a point when it works and build additional functionality on that.
http://restsharp.org/