Wiremock: xpath not working if xmlns is present - xpath

I am creating stub in wiremock. If I have xmlns in xml then it doesn't match however, without that It works.
Request
curl -d '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><a xmlns="http://www.example.com/namespaces/ad"><b>1</b><c>2</c><d>9407339517</d></a>' -i -H "Content-Type: text/xml" -X POST "http://localhost:8080/test"
Stub Json
{
"request": {
"method": "POST",
"url": "/test",
"headers" : {
"Content-Type" : {
"equalTo" : "text/xml"
}
},
"bodyPatterns" : [ {
"matchesXPath" : "/stuff:a[b='1'][c='2']",
"xPathNamespaces" : {
"stuff" : "http://www.example.com/namespaces/ad"
}
} ]
},
"response": {
"body": "Hello world!",
"status": 200
}
}
Along with above mentioned way, I have tried with local-name() too.

When there is a namespace present on a (grand) parent then on the (grand) children inherit the same namespace. So your /b and /c should be prefixed with /stuff:b or /stuff:c
{
"request": {
"method": "POST",
"url": "/test",
"headers" : {
"Content-Type" : {
"equalTo" : "text/xml"
}
},
"bodyPatterns" : [ {
"matchesXPath" : "/stuff:a[./stuff:b='1'][./stuff:c='2']",
"xPathNamespaces" : {
"stuff" : "http://www.example.com/namespaces/ad"
}
} ]
},
"response": {
"body": "Hello world!",
"status": 200
}
}

Related

Wiremock request.query not working with a paramter that contains dots

I'm using sprint-boot with wiremock-jre8, what i'm trying to to is to get a value from URL params, but this value contains dots "product.productCharacteristic.value"
{
"request": {
"urlPath": "/exampleOfPath",
"method": "GET",
"queryParameters": {
"product.productCharacteristic.name": {
"equalTo": "MSISDN"
},
"product.productCharacteristic.value": {
"matches": ".*"
}
}
},
"response": {
"status": 200,
"jsonBody": {
"key": "the value should be here {{request.query['product.productCharacteristic.value']}}"
},
"transformers": [
"response-template"
],
"headers": {
"Content-Type": "application/json"
}
}
}
i have tested all of those
{{request.query.['product.productCharacteristic.value']}}
{{request.query['product.productCharacteristic.value']}}
{{request.query['product%2EproductCharacteristic%2Evalue']}}
{{request.query.['product%2EproductCharacteristic%2Evalue']}}
{{request.query.product%2EproductCharacteristic%2Evalue}}
{{request.query.product.productCharacteristic.value}}
{{lookup request.query 'product.productCharacteristic.value'}}
{{lookup request.query 'product%2EproductCharacteristic%2Evalue'}}
You can use this format:
{{request.query.[product.productCharacteristic.value]}}
See WireMock - Response Templating - The request model:
request.headers.[<key>] - Header with awkward characters e.g. request.headers.[$?blah]

How to execute a bulk ElasticSearch operation from an AppSync resolver?

I'm trying to execute a bulk operation over an ElasticSearch index from a VTL AppSync resolver.
Specifically this mutation:
input CreateTopicsInput {
language: String!
texts: [String!]!
}
type Mutation {
createTopics(input: CreateTopicsInput!): [Topic!]
}
And I created the following resolver:
Mutation.createTopics.req.vtl
#set( $body = "" )
#set( $q = '"' )
#foreach( $text in $ctx.args.input.texts )
#set( $body = $body.concat("{ ${q}index${q}: { ${q}_id${q}: ${q}${text}${q} } }
") )
#set( $body = $body.concat("{ ${q}text${q}: ${q}$text${q}, ${q}suggest${q}: { ${q}input${q}: ${q}$text${q} } }
") )
#end
{
"version": "2017-02-28",
"operation": "POST",
"path": "/topic-${ctx.args.input.language}/doc/_bulk",
"params": {
"headers" : [ { "Content-Type" : "application/x-ndjson" } ],
"body": "$body"
}
}
And when executed for example with this data:
mutation CreateTopic {
createTopics(input: {
language: "en",
texts: [ "COVID", "Election" ]}) {
text
}
}
Seems to output a correct invocation:
{
"version": "2017-02-28",
"operation": "POST",
"path": "/topic-en/doc/_bulk",
"params": {
"headers" : [ { "Content-Type" : "application/x-ndjson" } ],
"body": "{ "index": { "_id": "COVID" }
{ "text": "COVID" }
{ "index": { "_id": "Election" }
{ "text": "Election" }
"
}
}
but it doesn't work. Specifically it throws:
{
"data": {
"createTopics": null
},
"errors": [
{
"path": [
"createTopics"
],
"data": null,
"errorType": "MappingTemplate",
"errorInfo": null,
"locations": [
{
"line": 2,
"column": 3,
"sourceName": null
}
],
"message": "Unexpected character ('i' (code 105)): was expecting comma to separate Object entries\n at [Source: (String)\"{\n \"version\": \"2017-02-28\",\n \"operation\": \"POST\",\n \"path\": \"/topic-en/doc/_bulk\",\n \"params\": {\n \"headers\" : { \"Content-Type\" : \"application/x-ndjson\" },\n \"body\": \"{ \"index\": { \"_id\": \"CODID\" } }\n{ \"text\": \"CODID\", \"suggest\": { \"input\": \"CODID\" } }\n{ \"index\": { \"_id\": \"Election\" } }\n{ \"text\": \"Election\", \"suggest\": { \"input\": \"Election\" } }\n\"\n }\n}\n\"; line: 7, column: 18]"
}
]
}
Some idea?
i played a little bit around and figure out that you would need to
quote your double quotes
write all in one line, divided by a "\n"
the last part in that line needs to be an "\n" again
As example:
{
"version": "2018-05-29",
"method": "POST",
"resourcePath": "/_msearch/template",
"params": {
"headers": {
"Content-Type": "application/x-ndjson"
},
"body": "{ \"index\": { \"_id": \"COVID\" }\n{ \"text\": \"COVID\" }\n"
}
}
Of course, this is not very convinced and for your use case this could work better:
#set($ndjson = [])
$util.qr($ndjson.add({ "index": "COVID" }))
$util.qr($ndjson.add({ "text": "COVID", "Param2": "vaccine" } }))
{
"version": "2018-05-29",
"method": "POST",
"resourcePath": "/_msearch/template",
"params": {
"headers": {
"Content-Type": "application/x-ndjson"
},
"body": "#foreach ($line in $ndjson)$util.escapeJavaScript($util.toJson($line))\n#end"
}
}
The (maybe) problematic part could be the JavaScript Escaping. Not sure how your data looks like but it could result into some more quoted data as needed.
P.s: i switched my implementation to the last mentioned example and it works fine for the multi search.

Amplify get Hosting URL in lambda as environment variable

I need the URL of Cloudfront distribution that I added with amplify cli as an environment variable.
Status:
I found how template variables are added in file "api-cloudformation-template.json" under my function config.
Desired Output variable from "hosting/S3AndCloudFront/template.json" is CloudFrontSecureURL.
So I added rows to lambda config file, like so:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Lambda resource stack creation using Amplify CLI",
"Parameters": {
...
"hostingS3AndCloudFrontHostingBucketName": { // working example
"Type": "String",
"Default": "hostingS3AndCloudFrontHostingBucketName"
},
"hostingS3AndCloudFrontCloudFrontSecureURL": { // my example
"Type": "String",
"Default": "hostingS3AndCloudFrontCloudFrontSecureURL"
},
},
"Resources": {
"LambdaFunction": {
"Type": "AWS::Lambda::Function",
"Metadata": {
"aws:asset:path": "./src",
"aws:asset:property": "Code"
},
"Properties": {
...
"Environment": {
"Variables": {
...
"HOSTING_S3ANDCLOUDFRONT_HOSTINGBUCKETNAME": {
"Ref": "hostingS3AndCloudFrontHostingBucketName"
},
"HOSTING_S3ANDCLOUDFRONT_CLOUDFRONTSECUREURL": {
"Ref": "hostingS3AndCloudFrontCloudFrontSecureURL"
}
}
},
}
}
....
},
....
}
I'm getting hostingS3AndCloudFrontCloudFrontSecureURL (default value) in process.env.HOSTING_S3ANDCLOUDFRONT_CLOUDFRONTSECUREURL after publishing function.
Try using the Outputs section of the template along with Fn::ImportValue function documentation HERE
CloudFront Stack:
{
...
"Outputs" : {
"CloudfrontDomainOutput" : {
"Description" : "The cloudfront domain",
"Value" : {
"Fn::GetAtt": [
"hostingS3AndCloudFrontCloudFrontSecureURL",
"DomainName"
]
},
"Export" : {
"Name" : {"Fn::Sub": "${AWS::StackName}-hostingS3AndCloudFrontCloudFrontSecureURL" }
}
}
}
Lambda Stack
{
...
"Environment": {
"Variables": {
"HOSTING_S3ANDCLOUDFRONT_HOSTINGBUCKETNAME": {
"Ref": "hostingS3AndCloudFrontHostingBucketName"
},
"HOSTING_S3ANDCLOUDFRONT_CLOUDFRONTSECUREURL": {
"Fn::ImportValue" : {"Fn::Sub" : "${CloudFront_Stack_Name}-hostingS3AndCloudFrontCloudFrontSecureURL"}
}
}
}
}

How to create xPath for soap header and body

I am trying to create a stub for soap request that has header and body following is the soap request:
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns3="http://example.com/ws/Namespaces/CustomerCareProductAndInsurance/Types/Public/CommonDataModel.xsd"
xmlns:inq="http://example.wsproduct.com/ws/Namespaces/Container/Public/InquireProductDetailsRequest.xsd"
xmlns="http://example.wsproduct.com/ws/Namespaces/Types/Public/MessageHeader.xsd">
<soap:Header>
<MessageHeader>
<TrackingMessageHeader>
<version>224</version>
</TrackingMessageHeader>
</MessageHeader>
</soap:Header>
<soap:Body>
<inq:InquireProductDetailsRequest>
<inq:ProductSelector>
<inq:code>013881004138416</inq:code>
</inq:ProductSelector>
</inq:InquireProductDetailsRequest>
</soap:Body>
</soap:Envelope>
Following is the stub that I have created with xPath matcher, however it's not working and I am getting body does not match everytime.
{
"request": {
"method": "POST",
"url": "/inquireProductDetails",
"headers": {
"Content-Type": {
"contains": "text/xml"
}
},
"bodyPatterns": [
{
"matchesXPath": "//version='224'"
},{
"matchesXPath": "//code='013881004138416'"
}
]
},
"response": {
"transformers": [
"response-template"
],
"bodyFileName": "productDetails-Success-Response.xml",
"status": 200
}
}
Can someone help to create matching xPath for above soap request. Thanks in advance!!
Try this
{
"request": {
"method": "POST",
"url": "/inquireProductDetails",
"headers": {
"Content-Type": {
"contains": "text/xml"
}
},
"bodyPatterns": [
{
"matchesXPath": "//*[local-name()='code'][text()='224']"
},{
"matchesXPath": "//*[local-name()='version'][text()='013881004138416']"
}
]
},
"response": {
"transformers": [
"response-template"
],
"bodyFileName": "productDetails-Success-Response.xml",
"status": 200
}
}

Why WireMock says that the Request not matches? Spring cloud contract

Wiremock logs that the following request not matches:
WireMock : Request was not matched:
{
"url" : "/api/accounts?username=defaultuser",
"absoluteUrl" : "http://localhost:11651/api/accounts?username=defaultuser",
"method" : "GET",
"clientIp" : "127.0.0.1",
"headers" : {
"authorization" : "bearer test123",
"accept" : "application/json, application/*+json",
"user-agent" : "Java/1.8.0_121",
"host" : "localhost:11651",
"connection" : "keep-alive"
},
"cookies" : { },
"browserProxyRequest" : false,
"loggedDate" : 1500711718016,
"bodyAsBase64" : "",
"body" : "",
"loggedDateString" : "2017-07-22T08:21:58Z"
}
Closest match:
{
"urlPath" : "/api/accounts",
"method" : "GET",
"headers" : {
"authorization" : {
"matches" : "^bearer"
},
"accept" : {
"equalTo" : "application/json, application/*+json"
},
"user-agent" : {
"equalTo" : "Java/1.8.0_121"
},
"host" : {
"matches" : "^localhost:[0-9]{5}"
},
"connection" : {
"equalTo" : "keep-alive"
}
},
"queryParameters" : {
"username" : {
"matches" : "^[a-zA-Z0-9]*$"
}
}
}
Is the problem because of the difference of url and urlPath?
I also tried to specify absoluteUrl in the Contract. but it is ignored. I guess because it is not defined in Contract DSL.
The request side of the contract looks like this:
request{
method 'GET'
url('/api/accounts'){
queryParameters {
parameter('username', $(consumer(regex('^[a-zA-Z0-9]*$')), producer('defaultuser')))
}
}
headers {
header('authorization', $(consumer(regex('^bearer')), producer(execute('authClientBearer()'))))
header('accept', $(consumer('application/json, application/*+json')))
header('user-agent', $(consumer('Java/1.8.0_121')))
header('host', $(consumer(regex('^localhost:[0-9]{5}'))))
header('connection', $(consumer('keep-alive')))
}
}
It turned out to be a missing / at the end of the URL in the contract/stub
Not directly related to the question but for all who came here from Google:
In my case I was in the wrong scenario state.
More about scenario states here: http://wiremock.org/docs/stateful-behaviour/
If you have the same problem, maybe it's about your problem:
JSON configuration for matching mvcMock example:
"request": {
"urlPath": "/hello?name=pavel",
"method": "GET",
..
}
And you can see in log:
"/hello?name=pavel" | "/hello?name=pavel" - URL does not match
This is correct.
You have to change:
"request": {
"urlPath": "/hello",
"method": "GET",
"queryParameters": {
"name": {
"equalTo": "pavel"
}
},
..
}

Resources