get a particular object from jsonBody with query param of request url in wiremock - wiremock

What should be the mapping object if
1) I need to pass my query
2) the query should be used to send one object out of an array of objects
curl -X POST --data '
{ "request":
{ "url": "/jsons?id=someID", "method": "GET" },
"response":
{ "status": 200, "jsonBody": {"objs":[{"id":"1","name":"abc"},{"id":"2","name":"cde"
{"id":"someID","name":"efg"}]}}}
'http://localhost:8080/__admin/mappings/new
I want the above url to return just {"id":"someID","name":"efg"}
How should i change the above mapping to get the desired output

The response should have one object for that particular get request with query param and not array of objects.
For your example it should be something like this
curl -X POST --data '
{ "request":
{ "url": "/jsons?id=someID", "method": "GET" },
"response":
{ "status": 200, "jsonBody": {"objs": {"id":"someID","name":"efg"}}}}
'http://localhost:8080/__admin/mappings/new

Related

Implement different response with WireMock when no request(s) match

I'm trying to stub a RESTful API. One of the resources return the details when the resource is (indeed) found, or an HTTP 404 (Not Found) when, eventually, there is no resource for the given URL.
This is my simplified stub/mapping:
{
"mappings": [
{
"name": "Retrieve Items",
"request": {
"headers": {
"accept": {
"caseInsensitive": true,
"equalTo": "application/json"
}
},
"method": "GET",
"urlPathPattern": "/api/items/[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}"
},
"response": {
"bodyFileName": "items-api/responses/retrieve/{{ request.pathSegments.[2] }}.json",
"headers": {
"content-type": "application/json"
},
"status": 200
}
}
]
}
Then I have several JSON files (in /home/wiremock/__files/items-api/responses/retrieve/ to match the requests against — but I can't find a way to implement the HTTP 404 (Not Found) scenario:
{
"timestamp": {{ now }},
"status": 404,
"error": "Not Found",
"message": null,
"path": "{{ request.path }}"
}
With this config I get back (the expected, but not useful for my use case) response from WireMock that the file name uuid-sent-in-request.json is not found.
Is there a way to implement this behavior currently?
Tom's answer will work as well. I think the benefits to his solution are that they aren't tied to specific request URLs, but my suggestion is to have a specific mapping for the files that will match with their specific JSON files, and a catch-all mapping for un-matched files. By assigning the requests with JSON responses a higher priority, WireMock will check those first, and if the request does not match any of the values specified in that mapping, will then go on to check if the second mapping matches, and return a 404.
{
"mappings": [
{
"name": "Retrieve Items - Success",
"priority": 1, // arbitrary number lower than the second priority
"request": {
"headers": {
"accept": {
"caseInsensitive": true,
"equalTo": "application/json"
}
},
"method": "GET",
"urlPathPattern": "/api/items/(UUID1|UUID2|UUID3|UUID4)"
},
"response": {
"bodyFileName": "items-api/responses/retrieve/{{ request.pathSegments.[2] }}.json",
"headers": {
"content-type": "application/json"
},
"status": 200
}
},
{
"name": "Retrieve Items - 404 Not Found",
"priority": 5, // arbitrary number that is higher than 1
"request": {
"headers": {
"accept": {
"caseInsensitive": true,
"equalTo": "application/json"
}
},
"method": "GET",
"urlPathPattern": "/api/items/[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}"
},
"response": {
"status": 404
}
}
]
}
Currently you would need to write a ResponseDefinitionTransformer to get the behaviour you're looking for.
It would need to check whether the ResponseDefinition passed in the parameter required a file, then if so check whether the file exists by doing something like:
try {
fileSource.getBinaryFileNamed(bodyFileName).readContents();
} catch (FileNotFoundException e) {
return WireMock.notFound().withBody("custom body");
}
// Otherwise return the unmodified response definition

Artemis jolokia rest api returns no real data (Jsr160ProxyNotEnabledByDefaultAnymoreDispatcher)

I've an Artemis Broker (2.17) running on my dev machine for local testing.
From the web-console I've extractet the request to get the names of all queues.
When I execute the request from the browser console i get a JSON result like this:
{
"request": {
"mbean": "org.apache.activemq.artemis:broker=\"MyBroker\"",
"arguments": [
"ANYCAST"
],
"type": "exec",
"operation": "getQueueNames(java.lang.String)"
},
"value": [
"DLQ",
"ExpiryQueue"
],
"timestamp": 1624274952,
"status": 200
}
When I execute the same request from my code I get a very different result:
{
"request": {
"type": "version"
},
"value": {
"agent": "1.6.2",
"protocol": "7.2",
"config": {
"listenForHttpService": "true",
"authIgnoreCerts": "false",
"agentId": "192.168.1.41-30064-15b82644-servlet",
"debug": "false",
"agentType": "servlet",
"policyLocation": "file:/C:/Artemis/MyBroker/etc//jolokia-access.xml",
"agentContext": "/jolokia",
"serializeException": "false",
"mimeType": "text/plain",
"dispatcherClasses": "org.jolokia.http.Jsr160ProxyNotEnabledByDefaultAnymoreDispatcher",
"authMode": "basic",
"authMatch": "any",
"streaming": "true",
"canonicalNaming": "true",
"historyMaxEntries": "10",
"allowErrorDetails": "false",
"allowDnsReverseLookup": "true",
"realm": "jolokia",
"includeStackTrace": "false",
"mbeanQualifier": "qualifier=hawtio",
"useRestrictorService": "false",
"debugMaxEntries": "100"
},
"info": {
"product": "jetty",
"vendor": "Eclipse",
"version": "9.4.27.v20200227"
}
},
"timestamp": 1624274809,
"status": 200
}
Jsr160ProxyNotEnabledByDefaultAnymoreDispatcher seams very strange. But when searching for this name I couldn't realy find anything usefull. Also I cannot find any usefull information in the Artemis logs.
Here is my code:
using System;
using System.Net.Http;
using System.Text;
using System.Threading;
const String username = "admin";
const String password = "password";
var encoded = Convert.ToBase64String( Encoding.GetEncoding( "ISO-8859-1" )
.GetBytes( username + ":" + password ) );
var url = "http://localhost:8161/console/jolokia/?maxDepth=7&maxCollectionSize=50000&ignoreErrors=true&canonicalNaming=false";
var http = new HttpClient();
http.BaseAddress = new("http://localhost:8161/");
http.DefaultRequestHeaders.Add( "Authorization", "Basic " + encoded );
http.DefaultRequestHeaders.Add( "Origin", "http://localhost:8161/" );
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new(url),
Content = new StringContent( "{\"type\":\"exec\",\"mbean\":\"org.apache.activemq.artemis:broker=\\\"MyBroker\\\"\",\"operation\":\"getQueueNames(java.lang.String)\",\"arguments\":[\"ANYCAST\"]}" )
};
request.Content.Headers.ContentType = new("text/json");
var response = await http.SendAsync( request, HttpCompletionOption.ResponseHeadersRead, CancellationToken.None );
if ( response.IsSuccessStatusCode )
{
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine( content );
}
else
Console.WriteLine( "Request failed...." );
Console.ReadLine();
In the bootstrap.xml the binding is set to 0.0.0.0 which should be ok.
jolokia-access.xml contained <allow-origin>*://localhost*</allow-origin> which should be fine but just to be sure I've replaced it with <allow-origin>*</allow-origin>
Is there something I need to configure to make this work?
Jolokia requests can be sent in two ways: Either as a HTTP GET request, in which case the request parameters are encoded completely in the URL. Or as a POST request where the request is put into a JSON payload in the HTTP request's body. See the Jolokia Protocol for further details.
When the Jolokia service doesn't get any request it will answer with service information, ie:
{
"request": {
"type": "version"
},
"value": {
...
To request the queue names using an HTTP GET request
curl -H "Origin:http://localhost:8161" -u admin:admin http://localhost:8161/console/jolokia/exec/org.apache.activemq.artemis:broker=\"MyBroker\"/getQueueNames/ANYCAST
To request the queue names using an HTTP POST request
curl -X POST -H "Content-Type: application/json" -H "Origin:http://localhost:8161" -u admin:admin http://localhost:8161/console/jolokia -d '{"type" : "EXEC", "mbean" : "org.apache.activemq.artemis:broker=\"MyBroker\"", "operation" : "getQueueNames", "arguments" : ["ANYCAST"]}'
Your code is using an HTTP GET, but it is using a fixed URL (i.e. http://localhost:8161/console/jolokia/?maxDepth=7&maxCollectionSize=50000&ignoreErrors=true&canonicalNaming=false and a payload (i.e. {"type":"exec","mbean":"org.apache.activemq.artemis:broker="MyBroker","operation":"getQueueNames(java.lang.String)","arguments":["ANYCAST"]}"). This does not conform with the Jolokia protocol.
If you use an HTTP GET then everything should be in the URL itself presumably just like it was your browser console. For example, use this:
http://localhost:8161/console/jolokia/exec/org.apache.activemq.artemis:broker="MyBroker"/getQueueNames/ANYCAST

Wiremock not able to match the url

I have very basic mapping.json
{
"mappings": [
{
"priority": 1,
"request": {
"method": "GET",
"url": "/your/url?and=query"
},
"response": {
"status": 200,
"statusMessage": "query param test"
}
},
{
"priority": 2,
"request": {
"method": "GET",
"url": "/your"
},
"response": {
"status": 200,
"statusMessage": "no query param"
}
}
]
}
It's the exact same example as given in the documentation.
Result:
admin ~ % curl -i http://localhost:8081/your
HTTP/1.1 200 no query param
Matched-Stub-Id: 6ff84303-8abb-48d0-bd27-679de118afc7
Transfer-Encoding: chunked
Server: Jetty(9.2.z-SNAPSHOT)
admin ~ % curl -i http://localhost:8081/your/url?and=query
zsh: no matches found: http://localhost:8081/your/url?and=query
admin ~ %
Cannot figure out what I am doing wrong here. It's exactly the same example give in the documentation. I tried putting query parameter like this:
"queryParameters" : {
"search_term" : {
"equalTo" : "WireMock"
}
},
This also didn't help.
TIA
Check out the answer and comment from this question, but the tl;dr is that if you want to include query parameters in a CURL request, you have to have the URL in quotes.
That would explain why Postman worked, and the CURL request without query parameters also worked, but the CURL request with query parameters did not.
curl -i 'http://localhost:8081/your/url?and=query' should be enough to solve your problem (might need double quotes instead of single?)

First success, second same request error stub response

Here my wiremock stub mapping:
{
"request": {
"method": "POST",
"urlPattern": "/api/myApp"
},
"response": {
"headers": {
"Content-Type": "application/json"
},
"status": 200
}
}
So when client execute http request with url pattern = /api/myApp then WireMock return success http status = 200.
Nice. It's work fine.
But I need when client execute second request with same url pattern the WireMock must return this stub response:
{
"request": {
"method": "POST",
"urlPattern": "/api/myApp"
},
"response": {
"headers": {
"Content-Type": "application/json"
},
"status": 401
}
}
So:
First request -> stub response 200
Second same request -> stub response 401
Is it possible by WireMock ?
If you are always going to have the pattern of the first call is successful and the second call is unsuccessful, you can use Scenarios to achieve this.
{
"scenarioName": "My Scenario",
"requiredScenarioState": "Started",
"newScenarioState": "Triggered Once",
"request": {}
"response": {
"status": 200
}
}
{
"scenarioName": "My Scenario",
"requiredScenarioState": "Triggered Once",
"newScenarioState": "Started",
"request": {}
"response": {
"status": 401
}
}
scenarioName is any string that you want to name the scenario
requiredScenarioState is the state the scenario has to be in. All Scenarios begin at a state of "Started".
newScenarioState is any string to denote the new Scenario State.
In the above, it will always alternate between successful 200 calls and unsuccessful 401 calls.
For more information on Stateful Behavior in WireMock, check out the docs

Wiremock Capture path param and return in the response body

I am trying to create dynamic mocks using WireMock. I have a situation where if I specify URL like :
http://localhost:8089/api/account/abc#abc.com
then I should receive response like:
{
"account" : "abc#abc.com"
}
In brief, the path param is returned in the response body. I am able to make the request URL generic by using urlPathPattern set to /api/account/([a-z]*) however, I am not sure how should I capture abc#abc.com and return this in the response using regular expressions.
In WireMock the regular expressions can be used to recognize the email format in the Request Matching. For the purpose of this example I used a very crude example. Your production implementation may require a more robust approach.
This request:
http://localhost:8181/api/account/someone#somewhere.net
Is matched by this rule:
{
"request": {
"method": "GET",
"urlPathPattern": "/api/account/([a-z]*#[a-z]*.[a-z]*)"
},
"response": {
"status": 200,
"jsonBody": {
"account": "{{request.path.[2]}}"
},
"transformers": ["response-template"],
"headers": {
"Content-Type": "application/json"
}
}
}
And returns this response:
{
"account": "someone#somewhere.net"
}
It makes use of a Response Template processing functionality in WireMock. The Request Model variables [{{request.path.[2]}}] can be used to obtain sections from the request.
The same can be done using WireMock.Net - Response-Templating
The rule looks like:
{
"Request": {
"Path": {
"Matchers": [
{
"Name": "RegexMatcher",
"Pattern": "^/api/account/([a-z]*#[a-z]*.[a-z]*)$"
}
]
},
"Methods": [
"get"
]
},
"Response": {
"StatusCode": 200,
"BodyAsJson": {
"account": "{{request.PathSegments.[2]}}"
},
"UseTransformer": true,
"Headers": {
"Content-Type": "application/json"
}
}
}