Referencing request from response (#238)

The best situation is to provide fixed values but sometimes you need to reference a request in your response. In order to do this you can profit from the fromRequest() method that allows you to reference a bunch of elements from the HTTP request. You can use the following options:

- `fromRequest().url()` - return the request URL
- `fromRequest().query(String key)` - return the first query parameter with a given name
- `fromRequest().query(String key, int index)` - return the nth query parameter with a given name
- `fromRequest().header(String key)` - return the first header with a given name
- `fromRequest().header(String key, int index)` - return the nth header with a given name
- `fromRequest().body()` - return the full request body
- `fromRequest().body(String jsonPath)` - return the element from the request that matches the JSON Path

fixes #237
This commit is contained in:
Marcin Grzejszczak
2017-03-02 10:14:10 +01:00
committed by GitHub
parent 7340f2893d
commit d6f2227f89
41 changed files with 1407 additions and 156 deletions

View File

@@ -0,0 +1,72 @@
package org.springframework.cloud.contract.spec
/**
* Contract for defining templated responses.
*
* If no implementation is provided then Handlebars will be picked as a default implementation.
*
* @author Marcin Grzejszczak
* @since 1.1.0
*/
interface ContractTemplate {
/**
* Handlebars is using the Mustache template thus it looks like this
* {{{ Mustache }}}. In this case the opening template would return {{{
*/
String openingTemplate()
/**
* Handlebars is using the Mustache template thus it looks like this
* {{{ Mustache }}}. In this case the closing template would return }}}
*/
String closingTemplate()
/**
* Returns the template for retrieving a URL from request
*/
String url()
/**
* Returns the template for retrieving first value of a query parameter e.g. {{{ request.query.search }}}
* @param key
*/
String query(String key)
/**
* Returns the template for retrieving nth value of a query parameter (zero indexed) e.g. {{{ request.query.search.[5] }}}
* @param key
* @param index
*/
String query(String key, int index)
/**
* Returns the template for retrieving the first value of a request header e.g. {{{ request.headers.X-Request-Id }}}
* @param key
*/
String header(String key)
/**
* Returns the template for retrieving the nth value of a request header (zero indexed) e.g. {{{ request.headers.X-Request-Id.[5] }}}
* @param key
* @param index
*/
String header(String key, int index)
/**
* Request body text (avoid for non-text bodies) e.g. {{{ request.body }}} . The body will not be escaped
* so you won't be able to directly embed it in a JSON for example.
*/
String body()
/**
* Request body text (avoid for non-text bodies) e.g. {{{ escapejsonbody }}} . The body will not be escaped
* so you will be able to embed it
*/
String escapedBody()
/**
* Request body text for the given JsonPath. e.g. {{{ jsonpath this '$.a.b.c' }}}
*/
String body(String jsonPath)
}

View File

@@ -205,4 +205,4 @@ class Common {
void assertThatSidesMatch(Object firstSide, Object secondSide) {
// do nothing
}
}
}

View File

@@ -0,0 +1,81 @@
package org.springframework.cloud.contract.spec.internal
import groovy.transform.CompileStatic
import org.springframework.cloud.contract.spec.ContractTemplate
/**
* Helper class to reference the request body parameters
*
* @author Marcin Grzejszczak
* @since 1.1.0
*/
@CompileStatic
class FromRequest {
private final ContractTemplate template
FromRequest() {
this.template = template()
}
private ContractTemplate template() {
return new HandlebarsContractTemplate()
}
/**
* URL path and query
*/
DslProperty url() {
return new DslProperty(template.url())
}
/**
* First value of a query parameter e.g. request.query.search
* @param key
*/
DslProperty query(String key) {
return new DslProperty(template.query(key))
}
/**
* nth value of a query parameter (zero indexed) e.g. request.query.search.[5]
* @param key
* @param index
*/
DslProperty query(String key, int index) {
return new DslProperty(template.query(key, index))
}
/**
* First value of a request header e.g. request.headers.X-Request-Id
* @param key
*/
DslProperty header(String key) {
return new DslProperty(template.header(key))
}
/**
* nth value of a request header (zero indexed) e.g. request.headers.X-Request-Id
* @param key
*/
DslProperty header(String key, int index) {
return new DslProperty(template.header(key, index))
}
/**
* Request body text (avoid for non-text bodies)
*/
DslProperty body() {
return new DslProperty(template.body())
}
/**
* Request body text for the given JsonPath
*/
DslProperty body(String jsonPath) {
return new DslProperty(template.body(jsonPath))
}
}

View File

@@ -0,0 +1,69 @@
package org.springframework.cloud.contract.spec.internal
import groovy.transform.CompileStatic
import org.springframework.cloud.contract.spec.ContractTemplate
/**
* Represents the structure of templates using Handlebars compatible with
* WireMock template model requirements.
*
* @author Marcin Grzejszczak
* @since 1.1.0
*/
@CompileStatic
class HandlebarsContractTemplate implements ContractTemplate {
@Override
String openingTemplate() {
return "{{{"
}
@Override
String closingTemplate() {
return "}}}"
}
@Override
String url() {
return wrapped("request.url")
}
@Override
String query(String key) {
return query(key, 0)
}
@Override
String query(String key, int index) {
return wrapped("request.query.${key}.[${index}]")
}
@Override
String header(String key) {
return header(key, 0)
}
@Override
String header(String key, int index) {
return wrapped("request.headers.${key}.[${index}]")
}
@Override
String body() {
return wrapped("request.body")
}
@Override
String escapedBody() {
return wrapped("escapejsonbody")
}
@Override
String body(String jsonPath) {
return wrapped("jsonpath this '${jsonPath}'")
}
private String wrapped(String text) {
return openingTemplate() + text + closingTemplate()
}
}

View File

@@ -118,6 +118,10 @@ class Response extends Common {
closure()
}
FromRequest fromRequest() {
return new FromRequest()
}
@Override
DslProperty value(ClientDslProperty client, ServerDslProperty server) {
if (client.clientValue instanceof Pattern) {