diff --git a/Response-Templating.md b/Response-Templating.md new file mode 100644 index 0000000..23d6ab9 --- /dev/null +++ b/Response-Templating.md @@ -0,0 +1,119 @@ +## Response Templating +Response headers and bodies can optionally be rendered using [Handlebars.Net](https://github.com/rexm/Handlebars.Net) templates. +This enables attributes of the request to be used in generating the response e.g. to pass the value of a request ID header as a response header or render an identifier from part of the URL in the response body. To use this functionality, add `.WithTransformer()` to the response builder. + +Example: +```csharp +var server = FluentMockServer.Start(); +server + .Given( + Request.Create().WithPath("/some/thing").UsingGet() + ) + .RespondWith( + Response.Create() + .WithStatusCode(200) + .WithHeader("Content-Type", "text/plain") + .WithBody("Hello world! Your path is {{request.path}}.") + .WithTransformer() + ); +``` + +### The request model +The model of the request is supplied to the header and body templates. The following request attributes are available: + +* `request.url` - URL path and query +* `request.absoluteurl` - URL path and query (absolute) +* `request.path` - URL path +* `request.absolutepath` - URL path (absolute) +* `request.PathSegments.[]` - URL path segment (zero indexed) e.g. request.PathSegments.[2] +* `request.AbsolutePathSegments.[]` - URL absolute path segments (zero indexed) e.g. request.AbsolutePathSegments.[2] +* `request.query.`- First value of a query parameter e.g. request.query.search +* `request.query..[]`- nth value of a query parameter (zero indexed) e.g. request.query.search.[5] +* `request.headers.` - First value of a request header e.g. request.headers.X-Request-Id +* `request.headers.[]` - Header with awkward characters e.g. request.headers.[$?blah] +* `request.headers..[]` - nth value of a header (zero indexed) e.g. request.headers.ManyThings.[1] +* `request.cookies.` - Value of a request cookie e.g. request.cookies.JSESSIONID +* `request.body` - Request body text as string +* `request.bodyAsJson` - Request body as dynamic Json Object. Note that the request **must** contain the header `Content-Type` with value `application/json`! + +### Handlebars helpers +All of the standard helpers (template functions) provided by the C# Handlebars implementation plus all of the string helpers are available e.g. +`{{capitalize request.query.search}}` + +### JsonPath support +JsonPath support is also present (internal logic is based on Newtonsoft.Json). + +Two functions are present: +1. JsonPath.SelectToken +2. JsonPath.SelectTokens + +#### JsonPath.SelectToken +This can be used in C# like: +```csharp +var server = FluentMockServer.Start(); +server + .Given(Request.Create().WithPath("/jsonpathtestToken").UsingPost()) + .RespondWith(Response.Create() + .WithHeader("Content-Type", "application/json") + .WithBody("{{JsonPath.SelectToken request.body \"$.Manufacturers[?(@.Name == 'Acme Co')]\"}}") + .WithTransformer() + ); +``` + +Or using the admin mapping file: +``` js +{ + "Request": { + "Path": { + "Matchers": [ + { + "Name": "WildcardMatcher", + "Pattern": "/jsonpathtestToken" + } + ] + }, + "Methods": [ + "post" + ] + }, + "Response": { + "StatusCode": 200, + "BodyDestination": "SameAsSource", + "Body": "{{JsonPath.SelectToken request.body \"$.Manufacturers[?(@.Name == 'Acme Co')]\"}}", + "UseTransformer": true, + "Headers": { + "Content-Type": "application/json" + } + } +} +``` + +Note that also replacing values in a Json Object and returning a the body as Json is supported, to use this, use a mapping file like this: +``` js +{ + "Request": { + "Path": { + "Matchers": [ + { + "Name": "WildcardMatcher", + "Pattern": "/test" + } + ] + }, + "Methods": [ + "post" + ] + }, + "Response": { + "StatusCode": 200, + "BodyAsJson": { + "path": "{{request.path}}", + "result": "{{JsonPath.SelectToken request.bodyAsJson \"username\"}}" + }, + "UseTransformer": true, + "Headers": { + "Content-Type": "application/json" + } + } +} +``` \ No newline at end of file