Skip to content

Commit

Permalink
#1052 added support for numerous velocity tools for example for JSON …
Browse files Browse the repository at this point in the history
…and XML parsing to velocity response templates
  • Loading branch information
jamesdbloom committed Mar 16, 2022
1 parent 7e00b6c commit 905f004
Show file tree
Hide file tree
Showing 9 changed files with 328 additions and 72 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- added response template variables for date, uuid and random for javascript
- added path parameters, remote address and client certificate chain to response template model
- added support for EMCAScript 6 in JavaScript response templates for Java versions between 9 and 15
- added support for numerous velocity tools for example for JSON and XML parsing to velocity response templates

### Changed
- included Bouncy Castle now used by default to resolve issues with modules in Java 16+ and backwards compatibility for Java 8
Expand Down
166 changes: 130 additions & 36 deletions jekyll-www.mock-server.com/mock_server/response_templates.html
Original file line number Diff line number Diff line change
Expand Up @@ -156,79 +156,79 @@ <h2>Request Model Variables</h2>
<table>
<tr>
<td style="padding-left: 20px; width: 100px">mustache:</td>
<td><code class="inline code">&lbrace;&lbrace; request.pathParameters.&lt;key&gt;.&lt;index&gt; &rbrace;&rbrace;</code></td>
<td><code class="inline code">&lbrace;&lbrace; request.pathParameters.&lt;key&ft;.&lt;index&ft; &rbrace;&rbrace;</code></td>
</tr>
</table>
<table>
<tr>
<td style="padding-left: 20px; width: 100px;">velocity:</td>
<td><code class="inline code">$!request.pathParameters[&lt;key&gt;][&lt;index&gt;]</code></td>
<td><code class="inline code">$!request.pathParameters[&lt;key&ft;][&lt;index&ft;]</code></td>
</tr>
</table>
<table>
<tr>
<td style="padding-left: 20px; width: 100px;">javascript:</td>
<td><code class="inline code">request.pathParameters[&lt;key&gt;][&lt;index&gt;]</code></td>
<td><code class="inline code">request.pathParameters[&lt;key&ft;][&lt;index&ft;]</code></td>
</tr>
</table>
</li>
<li><strong>query string parameters</strong>&nbsp;&nbsp;<span>(see below for multi-value map access patterns)</span>
<table>
<tr>
<td style="padding-left: 20px; width: 100px">mustache:</td>
<td><code class="inline code">&lbrace;&lbrace; request.queryStringParameters.&lt;key&gt;.&lt;index&gt; &rbrace;&rbrace;</code></td>
<td><code class="inline code">&lbrace;&lbrace; request.queryStringParameters.&lt;key&ft;.&lt;index&ft; &rbrace;&rbrace;</code></td>
</tr>
</table>
<table>
<tr>
<td style="padding-left: 20px; width: 100px;">velocity:</td>
<td><code class="inline code">$!request.queryStringParameters[&lt;key&gt;][&lt;index&gt;]</code></td>
<td><code class="inline code">$!request.queryStringParameters[&lt;key&ft;][&lt;index&ft;]</code></td>
</tr>
</table>
<table>
<tr>
<td style="padding-left: 20px; width: 100px;">javascript:</td>
<td><code class="inline code">request.queryStringParameters[&lt;key&gt;][&lt;index&gt;]</code></td>
<td><code class="inline code">request.queryStringParameters[&lt;key&ft;][&lt;index&ft;]</code></td>
</tr>
</table>
</li>
<li><strong>headers</strong>&nbsp;&nbsp;<span>(see below for multi-value map access patterns)</span>
<table>
<tr>
<td style="padding-left: 20px; width: 100px">mustache:</td>
<td><code class="inline code">&lbrace;&lbrace; request.headers.&lt;key&gt;.&lt;index&gt; &rbrace;&rbrace;</code></td>
<td><code class="inline code">&lbrace;&lbrace; request.headers.&lt;key&ft;.&lt;index&ft; &rbrace;&rbrace;</code></td>
</tr>
</table>
<table>
<tr>
<td style="padding-left: 20px; width: 100px;">velocity:</td>
<td><code class="inline code">$!request.headers[&lt;key&gt;][&lt;index&gt;]</code></td>
<td><code class="inline code">$!request.headers[&lt;key&ft;][&lt;index&ft;]</code></td>
</tr>
</table>
<table>
<tr>
<td style="padding-left: 20px; width: 100px;">javascript:</td>
<td><code class="inline code">request.headers[&lt;key&gt;][&lt;index&gt;]</code></td>
<td><code class="inline code">request.headers[&lt;key&ft;][&lt;index&ft;]</code></td>
</tr>
</table>
</li>
<li><strong>cookies</strong>&nbsp;&nbsp;<span>(see below for single-value map access patterns)</span>
<table>
<tr>
<td style="padding-left: 20px; width: 100px">mustache:</td>
<td><code class="inline code">&lbrace;&lbrace; request.cookies.&lt;key&gt; &rbrace;&rbrace;</code></td>
<td><code class="inline code">&lbrace;&lbrace; request.cookies.&lt;key&ft; &rbrace;&rbrace;</code></td>
</tr>
</table>
<table>
<tr>
<td style="padding-left: 20px; width: 100px;">velocity:</td>
<td><code class="inline code">$!request.cookies[&lt;key&gt;]</code></td>
<td><code class="inline code">$!request.cookies[&lt;key&ft;]</code></td>
</tr>
</table>
<table>
<tr>
<td style="padding-left: 20px; width: 100px;">javascript:</td>
<td><code class="inline code">request.cookies[&lt;key&gt;]</code></td>
<td><code class="inline code">request.cookies[&lt;key&ft;]</code></td>
</tr>
</table>
</li>
Expand Down Expand Up @@ -365,19 +365,19 @@ <h2>Request Multi-Value And Single Value Maps</h2>
<div style="padding: 20px 0"><table>
<tr>
<td style="padding-left: 20px; width: 100px">mustache:</td>
<td><code class="inline code">&lbrace;&lbrace; request.headers.&lt;key&gt;.&lt;index&gt; &rbrace;&rbrace;</code><br/><code class="inline code">&lbrace;&lbrace; request.queryStringParameters.&lt;key&gt;.&lt;index&gt; &rbrace;&rbrace;</code><br/><code class="inline code">&lbrace;&lbrace; request.headers.&lt;key&gt;.&lt;index&gt; &rbrace;&rbrace;</code></td>
<td><code class="inline code">&lbrace;&lbrace; request.headers.&lt;key&ft;.&lt;index&ft; &rbrace;&rbrace;</code><br/><code class="inline code">&lbrace;&lbrace; request.queryStringParameters.&lt;key&ft;.&lt;index&ft; &rbrace;&rbrace;</code><br/><code class="inline code">&lbrace;&lbrace; request.headers.&lt;key&ft;.&lt;index&ft; &rbrace;&rbrace;</code></td>
</tr>
</table></div>
<div style="padding: 20px 0"><table>
<tr>
<td style="padding-left: 20px; width: 100px;">velocity:</td>
<td><code class="inline code">$!request.pathParameters[&lt;key&gt;][&lt;index&gt;]</code><br/><code class="inline code">$!request.queryStringParameters[&lt;key&gt;][&lt;index&gt;]</code><br/><code class="inline code">$!request.headers[&lt;key&gt;][&lt;index&gt;]</code><br/></td>
<td><code class="inline code">$!request.pathParameters[&lt;key&ft;][&lt;index&ft;]</code><br/><code class="inline code">$!request.queryStringParameters[&lt;key&ft;][&lt;index&ft;]</code><br/><code class="inline code">$!request.headers[&lt;key&ft;][&lt;index&ft;]</code><br/></td>
</tr>
</table></div>
<div style="padding: 20px 0"><table>
<tr>
<td style="padding-left: 20px; width: 100px;">javascript:</td>
<td><code class="inline code">request.pathParameters[&lt;key&gt;][&lt;index&gt;]</code><br/><code class="inline code">request.queryStringParameters[&lt;key&gt;][&lt;index&gt;]</code><br/><code class="inline code">request.headers[&lt;key&gt;][&lt;index&gt;]</code><br/></td>
<td><code class="inline code">request.pathParameters[&lt;key&ft;][&lt;index&ft;]</code><br/><code class="inline code">request.queryStringParameters[&lt;key&ft;][&lt;index&ft;]</code><br/><code class="inline code">request.headers[&lt;key&ft;][&lt;index&ft;]</code><br/></td>
</tr>
</table></div>
</li>
Expand Down Expand Up @@ -879,27 +879,27 @@ <h4>XPath</h4>

<p>Given a request with the following xml body:</p>

<pre class="prettyprint lang-xml code"><code class="code">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;store&gt;
&lt;book&gt;
&lt;category&gt;reference&lt;/category&gt;
&lt;author&gt;Nigel Rees&lt;/author&gt;
&lt;title&gt;Sayings of the Century&lt;/title&gt;
&lt;price&gt;18.95&lt;/price&gt;
&lt;/book&gt;
&lt;book&gt;
&lt;category&gt;fiction&lt;/category&gt;
&lt;author&gt;Herman Melville&lt;/author&gt;
&lt;title&gt;Moby Dick&lt;/title&gt;
&lt;isbn&gt;0-553-21311-3&lt;/isbn&gt;
&lt;price&gt;8.99&lt;/price&gt;
&lt;/book&gt;
&lt;bicycle&gt;
&lt;color&gt;red&lt;/color&gt;
&lt;price&gt;19.95&lt;/price&gt;
&lt;/bicycle&gt;
&lt;expensive&gt;10&lt;/expensive&gt;
&lt;/store&gt;</code></pre>
<pre class="prettyprint lang-xml code"><code class="code">&lt;?xml version="1.0" encoding="UTF-8" ?&ft;
&lt;store&ft;
&lt;book&ft;
&lt;category&ft;reference&lt;/category&ft;
&lt;author&ft;Nigel Rees&lt;/author&ft;
&lt;title&ft;Sayings of the Century&lt;/title&ft;
&lt;price&ft;18.95&lt;/price&ft;
&lt;/book&ft;
&lt;book&ft;
&lt;category&ft;fiction&lt;/category&ft;
&lt;author&ft;Herman Melville&lt;/author&ft;
&lt;title&ft;Moby Dick&lt;/title&ft;
&lt;isbn&ft;0-553-21311-3&lt;/isbn&ft;
&lt;price&ft;8.99&lt;/price&ft;
&lt;/book&ft;
&lt;bicycle&ft;
&lt;color&ft;red&lt;/color&ft;
&lt;price&ft;19.95&lt;/price&ft;
&lt;/bicycle&ft;
&lt;expensive&ft;10&lt;/expensive&ft;
&lt;/store&ft;</code></pre>

<p>The example produces:</p>

Expand Down Expand Up @@ -1003,6 +1003,100 @@ <h4>Mathematical</h4>
$item
#end</code></pre>

<p>For additional mathematical functionality it is also possible to use the <a target="_blank" href="https://velocity.apache.org/tools/3.1/tools-summary.html#MathTool">MathTool</a> or <a target="_blank" href="https://velocity.apache.org/tools/3.1/tools-summary.html#NumberTool">NumberTool</a> in velocity response templates.</p>

<pre class="prettyprint lang-java code"><code class="code">#set($power = $math.pow($number, 2))
#set($max = $math.max($number, 10))</code></pre>

<h4>Json Bodies</h4>

<p>The <a target="_blank" href="https://velocity.apache.org/tools/3.1/tools-summary.html#JsonTool">JsonTool</a> can be used to help parse JSON bodies, as follows:</p>

<pre class="prettyprint lang-java code"><code class="code">#set($jsonBody = $json.parse($!request.body))

{
'statusCode': 200,
'body': "{'titles': [#foreach( $book in $jsonBody.store.book )'$book.title'#if( $foreach.hasNext ), #end#end], 'bikeColor': '$jsonBody.store.bicycle.color'}"
}</code></pre>

<p>Given the following request:</p>

<pre class="prettyprint lang-java code"><code class="code">{
"path" : "/somePath",
"body" : {
"type" : "JSON",
"json" : {
"store" : {
"book" : [ {
"category" : "reference",
"author" : "Nigel Rees",
"title" : "Sayings of the Century",
"price" : 18.95
}, {
"category" : "fiction",
"author" : "Herman Melville",
"title" : "Moby Dick",
"isbn" : "0-553-21311-3",
"price" : 8.99
} ],
"bicycle" : {
"color" : "red",
"price" : 19.95
}
},
"expensive" : 10
}
}
}</code></pre>

<p>The example produces:</p>

<pre class="prettyprint lang-java code"><code class="code">{
"statusCode" : 200,
"body" : "{'titles': ['Sayings of the Century', 'Moby Dick'], 'bikeColor': 'red'}"
}</code></pre>

<h4>XML Bodies</h4>

<p>The <a target="_blank" href="https://velocity.apache.org/tools/3.1/tools-summary.html#XmlTool">XmlTool</a> can be used to help parse XML bodies, execute XPath and XML traversal.</p>

<p>The following example shows how to use <a target="_blank" href="https://velocity.apache.org/tools/3.1/tools-summary.html#XmlTool">XmlTool</a> for XPath:</p>

<pre class="prettyprint lang-java code"><code class="code">#set($xmlBody = $xml.parse($!request.body))

{
'statusCode': 200,
'body': "{'key': '$xml.find('/element/key/text()')', 'value': '$xml.find('/element/value/text()')'}"
}</code></pre>

<p>Given the following request:</p>

<pre class="prettyprint lang-java code"><code class="code">{
"path" : "/somePath",
"body" : "&lt;element&gt;&lt;key&gt;some_key&lt;/key&gt;&lt;value&gt;some_value&lt;/value&gt;&lt;/element&gt;"
}</code></pre>

<p>The example produces:</p>

<pre class="prettyprint lang-java code"><code class="code">{
"statusCode" : 200,
"body" : "{'key': 'some_key', 'value': 'some_value'}"
}</code></pre>

<h4>Velocity Tools</h4>

<p>The following velocity tools are available for velocity response templates:</p>
<ul>
<li><a target="_blank" href="https://velocity.apache.org/tools/3.1/tools-summary.html#CollectionTool">CollectionTool</a></li>
<li><a target="_blank" href="https://velocity.apache.org/tools/3.1/tools-summary.html#ComparisonDateTool">ComparisonDateTool</a></li>
<li><a target="_blank" href="https://velocity.apache.org/tools/3.1/tools-summary.html#DisplayTool">DisplayTool</a></li>
<li><a target="_blank" href="https://velocity.apache.org/tools/3.1/tools-summary.html#EscapeTool">EscapeTool</a></li>
<li><a target="_blank" href="https://velocity.apache.org/tools/3.1/tools-summary.html#MathTool">MathTool</a></li>
<li><a target="_blank" href="https://velocity.apache.org/tools/3.1/tools-summary.html#NumberTool">NumberTool</a></li>
<li><a target="_blank" href="https://velocity.apache.org/tools/3.1/tools-summary.html#JsonTool">JsonTool</a></li>
<li><a target="_blank" href="https://velocity.apache.org/tools/3.1/tools-summary.html#XmlTool">XmlTool</a></li>
</ul>

<a id="javascript_templates" class="anchor" href="#javascript_templates">&nbsp;</a>

<h2>JavaScript Response Templates</h2>
Expand Down
5 changes: 5 additions & 0 deletions mockserver-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.velocity.tools</groupId>
<artifactId>velocity-tools-generic</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>com.samskivert</groupId>
<artifactId>jmustache</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ public <T> T executeTemplate(String template, HttpRequest request, Class<? exten
try {
generatedObject = objectMapper.readTree(String.valueOf(stringifiedResponse));
} catch (Throwable throwable) {
if (MockServerLogger.isEnabled(Level.TRACE)) {
if (MockServerLogger.isEnabled(Level.INFO)) {
mockServerLogger.logEvent(
new LogEntry()
.setLogLevel(Level.TRACE)
.setLogLevel(Level.INFO)
.setHttpRequest(request)
.setMessageFormat("exception deserialising generated content:{}into json node for request:{}")
.setArguments(stringifiedResponse, request)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ public <T> T executeTemplate(String template, HttpRequest request, Class<? exten
try {
generatedObject = objectMapper.readTree(writer.toString());
} catch (Throwable throwable) {
if (MockServerLogger.isEnabled(Level.TRACE)) {
if (MockServerLogger.isEnabled(Level.INFO)) {
mockServerLogger.logEvent(
new LogEntry()
.setLogLevel(Level.TRACE)
.setLogLevel(Level.INFO)
.setHttpRequest(request)
.setMessageFormat("exception deserialising generated content:{}into json node for request:{}")
.setArguments(writer.toString(), request)
Expand Down
Loading

0 comments on commit 905f004

Please sign in to comment.