Skip to content

MasonM/wiremock-jsextend

Repository files navigation

Overview

wiremock-jsextend is a "meta-extension" for WireMock that lets you create and manage extensions written in Javascript using the Nashorn JavaScript engine (with a fallback to Rhino for Java 7). It adds API endpoints to create, list, edit, and delete extensions. Example:

# Stub mapping for testing
$ curl -s -d '{
    "request": { "url": "/test" },
    "response": { "body": "TESTING" }
}' http://localhost:8080/__admin/mappings > /dev/null

# Test mapping
$ curl -s http://localhost:8080/test
TESTING

# Create response transformer
$ curl -s -d '
    function transform(request, response) {
        return Response.Builder
            .like(response)
            .but()
            .body(response.getBodyAsString() + ", and transformed!")
            .build();
   }
' http://localhost:8080/__admin/extensions/response-transformer > /dev/null

# Test transformer
$ curl -s http://localhost:8080/test
TESTING, and transformed!

Caveats/Limitations

  • This extension allows arbitrary code execution. Do not use this unless you fully understand the security implications.
  • AdminApiExtension and PostServeAction extensions are not supported.
  • Due to limitations in Wiremock, transformer extensions are always global. Transformer parameters can be used as a workaround.
  • Due to limitations in Wiremock, you cannot name request matcher extensions. See the Request Matching section below.
  • No load testing has been done yet, so I have no idea how well this will work with a large number of requests.

Building

Run gradle jar to build the JAR without dependencies or gradle fatJar to build a standalone JAR. These will be placed in build/libs/.

Running

Standalone server:

java -jar build/libs/wiremock-jsextend-0.1a-standalone.jar

With WireMock standalone JAR:

java \
        -cp wiremock-standalone.jar:build/libs/wiremock-snapshot-0.3a.jar \
        com.github.tomakehurst.wiremock.standalone.WireMockServerRunner \
        --extensions="com.github.masonm.wiremock.extension.JsExtendApiExtension,com.github.masonm.wiremock.extension.CompositeRequestMatcherExtension,com.github.masonm.wiremock.extension.CompositeResponseDefinitionTransformer,com.github.masonm.wiremock.extension.CompositeResponseTransformer,com.github.masonm.wiremock.extension.JsExtendStubMappingTransformerExtension"

Programmatically in Java:

new WireMockServer(
    wireMockConfig().extensions(
        "com.github.masonm.wiremock.extension.JsExtendApiExtension",
        "com.github.masonm.wiremock.extension.CompositeRequestMatcherExtension",
        "com.github.masonm.wiremock.extension.CompositeResponseDefinitionTransformer",
        "com.github.masonm.wiremock.extension.CompositeResponseTransformer",
        "com.github.masonm.wiremock.extension.CompositeStubMappingTransformer"
    )
)

Usage

API Endpoints

The extension adds the following admin API endpoints. The URL parameter {type} should be one of response-transformer, response-definition-transformer, request-matcher, or stub-mapping-transformer.

  • PUT /__admin/extensions/{type}/{name} - Create new extension with type {type} and name {name}. The request body should be the Javascript source for the transformer or matcher function.
  • GET /__admin/extensions/{type}/{name} - Retrieves extension of type {type} and name {name}.
  • DELETE /__admin/extensions/{id}/{name} - Deletes extension of type {type} and name {name}.
  • GET /__admin/extensions/{type} - Returns array of all registered extensions of type {type}.
  • DELETE /__admin/extensions/{type} - Deletes all registered extensions of the type {type}.

Javascript API

Extensions must consist of a single Javascript function with a prototype matching the corresponding Java class:

  • ResponseTransformer. Example:

    function transform(request, response, files, parameters) {
        return Response.Builder.like(response).but().body("TRANSFORMED!").build();
    }
  • ResponseDefinitionTransformer. Example:

    function transform(request, responseDefinition, files, parameters) {
        return new ResponseDefinition(201, "TRANSFORMED!");
    }
  • RequestMatcherExtension. Example:

    function match(request, parameters) {
        var queryParam = parameters.getString("queryParam");
        return MatchResult.of(request.queryParameter(queryParam).isPresent());
    }
  • StubMappingTransformer. Example:

    function transform(stubMapping) {
        var newRequest = RequestPatternUpdater
            .like(stubMapping.getRequest())
            .withUrl("http://example.com")
            .build();
        stubMapping.setRequest(newRequest);
        return stubMapping;
    }

If you're using Java 8, then many classes are already imported for you are already imported for you. To import other classes, use the Java.type() extension.

Request Matching

Due to Wiremock limitations, it's not possible to specify the name for a new request matcher. To use a request matcher, pass "composite-request-matcher-extension" as the name, along with any parameters you want to use. This will cause wiremock-jsextend to match the request against every matcher you've registered, in the order they were registered. The results are aggregated using MatchResult.aggregate() and returned. You can use a parameter to ensure only one of your matchers if used, e.g.:

# Define request matcher that returns MatchResult.exactMatch() unless the parameter "urlHasFoo" is present
$ curl -s -d '{
    function match(request, parameters) {
        if (!parameters || !parameters.containsKey("urlHasFoo")) {
            return MatchResult.exactMatch();
        }
        return MatchResult.of(request.getUrl().indexOf("foo") != -1);
    }
' http://localhost:8080/__admin/extensions/RequestMatcherExtension/hasFoo > /dev/null

# Define test stub mapping that passes the "urlHasFoo" parameter
$ curl -s -d '{
    "request": {
        "customMatcher": {
            "name": "composite-request-matcher-extension",
            "parameters": {
                "urlHasFoo": true
            }
        }
    },
    "response": { "body": "MATCHED!" }
}' http://localhost:8080/__admin/mappings > /dev/null

# Test it!
$ curl -s http://localhost:8080/foo
MATCHED!

$ curl -I -s http://localhost:8080/bar
HTTP/1.1 404 Not Found
Cache-Control: must-revalidate,no-cache,no-store
Content-Type: text/html; charset=ISO-8859-1
Content-Length: 286
Server: Jetty(9.2.13.v20150730)

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors