All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer Maven / Gradle / Ivy

There is a newer version: 3.0.1
Show newest version
/*
 * Copyright (C) 2016-2023 Thomas Akehurst
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.tomakehurst.wiremock.extension.responsetemplating;

import static com.google.common.base.MoreObjects.firstNonNull;

import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Helper;
import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder;
import com.github.tomakehurst.wiremock.common.FileSource;
import com.github.tomakehurst.wiremock.common.TextFile;
import com.github.tomakehurst.wiremock.common.url.PathTemplate;
import com.github.tomakehurst.wiremock.extension.Parameters;
import com.github.tomakehurst.wiremock.extension.ResponseDefinitionTransformer;
import com.github.tomakehurst.wiremock.extension.StubLifecycleListener;
import com.github.tomakehurst.wiremock.http.*;
import com.github.tomakehurst.wiremock.stubbing.ServeEvent;
import com.github.tomakehurst.wiremock.stubbing.StubMapping;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class ResponseTemplateTransformer extends ResponseDefinitionTransformer
    implements StubLifecycleListener {

  public static final String NAME = "response-template";

  private final boolean global;
  private final TemplateEngine templateEngine;

  public static Builder builder() {
    return new Builder();
  }

  public ResponseTemplateTransformer(boolean global) {
    this(global, Collections.emptyMap());
  }

  public ResponseTemplateTransformer(boolean global, String helperName, Helper helper) {
    this(global, ImmutableMap.of(helperName, helper));
  }

  public ResponseTemplateTransformer(boolean global, Map> helpers) {
    this(global, new Handlebars(), helpers, null, null);
  }

  public ResponseTemplateTransformer(
      boolean global,
      Handlebars handlebars,
      Map> helpers,
      Long maxCacheEntries,
      Set permittedSystemKeys) {
    this.global = global;
    this.templateEngine =
        new TemplateEngine(handlebars, helpers, maxCacheEntries, permittedSystemKeys);
  }

  @Override
  public boolean applyGlobally() {
    return global;
  }

  @Override
  public String getName() {
    return NAME;
  }

  @Override
  public ResponseDefinition transform(
      Request request,
      final ResponseDefinition responseDefinition,
      FileSource files,
      Parameters parameters) {
    ResponseDefinitionBuilder newResponseDefBuilder =
        ResponseDefinitionBuilder.like(responseDefinition);

    final PathTemplate pathTemplate = getCurrentEventPathTemplate();

    final ImmutableMap model =
        ImmutableMap.builder()
            .put("parameters", firstNonNull(parameters, Collections.emptyMap()))
            .put("request", RequestTemplateModel.from(request, pathTemplate))
            .putAll(addExtraModelElements(request, responseDefinition, files, parameters))
            .build();

    if (responseDefinition.specifiesTextBodyContent()) {
      boolean isJsonBody = responseDefinition.getReponseBody().isJson();
      HandlebarsOptimizedTemplate bodyTemplate =
          templateEngine.getTemplate(
              HttpTemplateCacheKey.forInlineBody(responseDefinition),
              responseDefinition.getTextBody());
      applyTemplatedResponseBody(newResponseDefBuilder, model, bodyTemplate, isJsonBody);
    } else if (responseDefinition.specifiesBodyFile()) {
      HandlebarsOptimizedTemplate filePathTemplate =
          templateEngine.getUncachedTemplate(responseDefinition.getBodyFileName());
      String compiledFilePath = uncheckedApplyTemplate(filePathTemplate, model);

      boolean disableBodyFileTemplating = parameters.getBoolean("disableBodyFileTemplating", false);
      if (disableBodyFileTemplating) {
        newResponseDefBuilder.withBodyFile(compiledFilePath);
      } else {
        TextFile file = files.getTextFileNamed(compiledFilePath);
        HandlebarsOptimizedTemplate bodyTemplate =
            templateEngine.getTemplate(
                HttpTemplateCacheKey.forFileBody(responseDefinition, compiledFilePath),
                file.readContentsAsString());
        applyTemplatedResponseBody(newResponseDefBuilder, model, bodyTemplate, false);
      }
    }

    if (responseDefinition.getHeaders() != null) {
      Iterable newResponseHeaders =
          Iterables.transform(
              responseDefinition.getHeaders().all(),
              header -> {
                ImmutableList.Builder valueListBuilder = ImmutableList.builder();
                int index = 0;
                for (String headerValue : header.values()) {
                  HandlebarsOptimizedTemplate template =
                      templateEngine.getTemplate(
                          HttpTemplateCacheKey.forHeader(responseDefinition, header.key(), index++),
                          headerValue);
                  valueListBuilder.add(uncheckedApplyTemplate(template, model));
                }

                return new HttpHeader(header.key(), valueListBuilder.build());
              });
      newResponseDefBuilder.withHeaders(new HttpHeaders(newResponseHeaders));
    }

    if (responseDefinition.getProxyBaseUrl() != null) {
      HandlebarsOptimizedTemplate proxyBaseUrlTemplate =
          templateEngine.getTemplate(
              HttpTemplateCacheKey.forProxyUrl(responseDefinition),
              responseDefinition.getProxyBaseUrl());
      String newProxyBaseUrl = uncheckedApplyTemplate(proxyBaseUrlTemplate, model);

      ResponseDefinitionBuilder.ProxyResponseDefinitionBuilder newProxyResponseDefBuilder =
          newResponseDefBuilder.proxiedFrom(newProxyBaseUrl);

      if (responseDefinition.getAdditionalProxyRequestHeaders() != null) {
        Iterable newResponseHeaders =
            Iterables.transform(
                responseDefinition.getAdditionalProxyRequestHeaders().all(),
                header -> {
                  ImmutableList.Builder valueListBuilder = ImmutableList.builder();
                  int index = 0;
                  for (String headerValue : header.values()) {
                    HandlebarsOptimizedTemplate template =
                        templateEngine.getTemplate(
                            HttpTemplateCacheKey.forHeader(
                                responseDefinition, header.key(), index++),
                            headerValue);
                    valueListBuilder.add(uncheckedApplyTemplate(template, model));
                  }
                  return new HttpHeader(header.key(), valueListBuilder.build());
                });
        HttpHeaders proxyHttpHeaders = new HttpHeaders(newResponseHeaders);
        for (String key : proxyHttpHeaders.keys()) {
          newProxyResponseDefBuilder.withAdditionalRequestHeader(
              key, proxyHttpHeaders.getHeader(key).firstValue());
        }
      }
      return newProxyResponseDefBuilder.build();
    } else {
      return newResponseDefBuilder.build();
    }
  }

  private static PathTemplate getCurrentEventPathTemplate() {
    if (ServeEvent.getCurrent() == null) {
      return null;
    }

    return ServeEvent.getCurrent().getStubMapping().getRequest().getUrlMatcher().getPathTemplate();
  }

  /** Override this to add extra elements to the template model */
  protected Map addExtraModelElements(
      Request request,
      ResponseDefinition responseDefinition,
      FileSource files,
      Parameters parameters) {
    return Collections.emptyMap();
  }

  private void applyTemplatedResponseBody(
      ResponseDefinitionBuilder newResponseDefBuilder,
      ImmutableMap model,
      HandlebarsOptimizedTemplate bodyTemplate,
      boolean isJsonBody) {
    String bodyString = uncheckedApplyTemplate(bodyTemplate, model);
    Body body =
        isJsonBody
            ? Body.fromJsonBytes(bodyString.getBytes(StandardCharsets.UTF_8))
            : Body.fromOneOf(null, bodyString, null, null);
    newResponseDefBuilder.withResponseBody(body);
  }

  private String uncheckedApplyTemplate(HandlebarsOptimizedTemplate template, Object context) {
    return template.apply(context);
  }

  @Override
  public void beforeStubCreated(StubMapping stub) {}

  @Override
  public void afterStubCreated(StubMapping stub) {}

  @Override
  public void beforeStubEdited(StubMapping oldStub, StubMapping newStub) {}

  @Override
  public void afterStubEdited(StubMapping oldStub, StubMapping newStub) {}

  @Override
  public void beforeStubRemoved(StubMapping stub) {}

  @Override
  public void afterStubRemoved(StubMapping stub) {
    templateEngine.invalidateCache();
  }

  @Override
  public void beforeStubsReset() {}

  @Override
  public void afterStubsReset() {
    templateEngine.invalidateCache();
  }

  public long getCacheSize() {
    return templateEngine.getCacheSize();
  }

  public Long getMaxCacheEntries() {
    return templateEngine.getMaxCacheEntries();
  }

  public static class Builder {
    private boolean global = true;
    private Handlebars handlebars = new Handlebars();
    private Map> helpers = new HashMap<>();
    private Long maxCacheEntries = null;
    private Set permittedSystemKeys = null;

    public Builder global(boolean global) {
      this.global = global;
      return this;
    }

    public Builder handlebars(Handlebars handlebars) {
      this.handlebars = handlebars;
      return this;
    }

    public Builder helpers(Map> helpers) {
      this.helpers = helpers;
      return this;
    }

    public Builder helper(String name, Helper helper) {
      this.helpers.put(name, helper);
      return this;
    }

    public Builder maxCacheEntries(Long maxCacheEntries) {
      this.maxCacheEntries = maxCacheEntries;
      return this;
    }

    public Builder permittedSystemKeys(Set keys) {
      this.permittedSystemKeys = keys;
      return this;
    }

    public Builder permittedSystemKeys(String... keys) {
      this.permittedSystemKeys = ImmutableSet.copyOf(keys);
      return this;
    }

    public ResponseTemplateTransformer build() {
      return new ResponseTemplateTransformer(
          global, handlebars, helpers, maxCacheEntries, permittedSystemKeys);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy