First success, second same request error stub response - wiremock

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

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

Avoid logging specific requests in Wiremock

I'm using Wiremock 2.28.1 in a Scala 2.13 project and I would like to skip logging specific requests/responses in Wiremock because they are just liveness/readiness HTTP calls targeting health/ready and health/alive endpoints:
{
"mappings": [
{
"request": {
"method": "GET",
"url": "/api/v1/health/ready"
},
"response": {
"status": 200,
"body": "",
"headers": {
"Content-Type": "text/plain"
}
}
},
{
"request": {
"method": "GET",
"url": "/api/v1/health/alive"
},
"response": {
"status": 200,
"body": "",
"headers": {
"Content-Type": "text/plain"
}
}
}
]
}
The WireMock server configuration is:
new WireMockConfiguration()
.bindAddress(configOptions.host)
.port(configOptions.port)
.stubCorsEnabled(configOptions.enableCors)
.disableRequestJournal() // avoid JVM heap exhaustion for recorded requests
.usingFilesUnderClasspath(s"$confBasePath/${configOptions.mappingsFolder}")
.notifier(new ConsoleNotifier(configOptions.verboseNotifier)) // <-- TRUE
.httpsPort(...)
Is there a way to tell WireMock to simply skip logging the /health/* API calls?
There are a couple of ways you could do this:
Write your own Notifier implementation that filters messages based on their content and use this in place of ConsoleNotifier in your startup options.
Make the healthcheck an admin API function by implementing AdminApiExtension and registering it in the startup options (this will mean the URL will have to be under /__admin/.

Mapping by request's body use two matches

I has http request with body:
endpoint = http://127.0.0.1:54400/json
reqBody:
{
"action": "Handler:GET_DICTIONARY",
"locale": "ro",
"data": {"dictionary_type":"MTS"}
}
I need to get stubbed response.
Here my Wiremock mapping:
{
"request": {
"method": "POST",
"bodyPatterns": [
{
"contains": "Handler:GET_DICTIONARY"
}
]
},
"response": {
"headers": {
"Content-Type": "application/json"
},
"status": 200,
"fixedDelayMilliseconds": 3000,
"bodyFileName": "t2a/micb/webclient/_mts_response.json"
}
}
But I has many another requests that content request's body with text:
"Handler:GET_DICTIONARY"
So as result I need to mapping also by
"dictionary_type":"MTS"
because text
and
"dictionary_type":"MTS" AND "Handler:GET_DICTIONARY" create UNIQUE request.
So how I can mapping by request's body use this two matches?
I would suggest to add "matchesJsonPath" in addition to your "contains"
"bodyPatterns": [
{
"matchesJsonPath": "$.data[?(#.dictionary_type == 'MTS')]"
}
]
That will guarantee that all the request with dictionary_type = MTS will mapped to that response.

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"
}
}
}

WireMock not mapping request by body contains

My http request send to this: https://myhost.com/ap
My http request with body :
{
"Body": {
"CommandName": "GetApplicationProfile"
},
"Header": {
"Command": "GetApplicationProfile",
}
}
I want to mapping this request by WireMock.
Here WireMock's mapping file.
{
"request": {
"url": "/my_host/ap",
"bodyPatterns": [
{
"contains": "GetApplicationProfile"
}
]
},
"response": {
"headers": {
"Content-Type": "application/json"
},
"status": 200,
"bodyFileName": "get_profile.json"
}
}
I start wireMock like this:
java -jar wiremock-standalone-2.18.0.jar --port 8080 --enable-browser-proxying -verbose
But when request was started the WireMock not map this request. Nothing happened.
why?
The problem you're having is that you shouldn't have the hostname in the url part. This is not needed. Your example message can be sent and will be matched using the following rule.
{
"request": {
"url": "/app",
"bodyPatterns": [
{
"contains": "GetApplicationProfile"
}
]
},
"response": {
"headers": {
"Content-Type": "application/json"
},
"status": 200,
"body": "ddd"
}
}
The URL should not contain the host name. It should only contain the resource path.
The url format should start with "/" e.g. /https://myhost.com/ap.
Now if u r trying this on localhost then the URL should be localhost:<port>/https://myhost.com/ap.
The file should be present at src/test/resources/__files
If not it will give error file not present.
I see 2 issues here:
1. you need to remove the host name from the url in the mapping file.
2. your request is HTTPS which means you need to start your wiremock port with https: --https-port 8080 or you change your request to HTTP