Mocking API calls using WireMock

Alex Hyett - May 28 '21 - - Dev Community

It is rare in software development that you are building something in complete isolation from everything else. Generally, you are going to be making calls to other systems or components.

If you are lucky you are building against an existing API that you can test against. If you are working with other teams to similar deadlines, you generally need to agree on a contract beforehand and build against it. In this case, you are going to need to mock the API to be able to test what you are building.

This is where Wiremock comes in. Other tools that can be used for mocking APIs but Wiremock is the one I have the most experience with.

Running Wiremock in a Docker container

If you need to run your component locally against a mocked source then running wiremock standalone from a docker container is the best way to do that. It works similarly to the way you mock AWS by running localstack. You can also use Wiremock to mock AWS services but I will save that for another post!

To save us some time we are going to use this popular (30 million pulls) docker image, rodolpheche/wiremock-docker.

If you want a one-liner to get this up and running you can use this:

docker run -it --rm -p 8080:8080 rodolpheche/wiremock
Enter fullscreen mode Exit fullscreen mode

When wiremock starts you should see something like this on the console:

 /$$ /$$ /$$ /$$ /$$ /$$
| $$ /$ | $$|__/ | $$$ /$$$ | $$
| $$ /$$$| $$ /$$ /$$$$$$ /$$$$$$ | $$$$ /$$$$ /$$$$$$ /$$$$$$$| $$ /$$
| $$/$$ $$ $$| $$ /$$ __$$ /$$__ $$| $$ $$/$$ $$ /$$ __$$ /$$_____ /| $$ /$$/
| $$$$_ $$$$| $$| $$ \__/| $$$$$$$$| $$ $$$| $$| $$ \ $$| $$ | $$$$$$/
| $$$/ \ $$$| $$| $$ | $$ _____ /| $$\ $ | $$| $$ | $$| $$ | $$_ $$
| $$/ \ $$| $$| $$ | $$$$$$$| $$ \/ | $$| $$$$$$/| $$$$$$$| $$ \ $$
| __/ \__ /| __/|__ / \ _______/|__ / | __/ \______ / \ _______/|__ / \__/

port: 8080
enable-browser-proxying: false
disable-banner: false
no-request-journal: false
verbose: false

Enter fullscreen mode Exit fullscreen mode

Got to love the ASCII art!

You should be able to get a list of mappings (which will be empty to start with) using http://localhost:8080/__admin/mappings which will give us this:

{
  "mappings": [],
  "meta": {
    "total": 0
  }
}
Enter fullscreen mode Exit fullscreen mode

Adding mappings using the API

You can use the wiremock API to add mappings, this is particularly useful if you want to test out examples on the go.

GET Request

Using postman you can import the following curl statement:

curl --location --request POST 'http://localhost:8080/__admin/mappings/new' \
--header 'Content-Type: application/json' \
--data-raw '{
    "request": {
        "method": "GET",
        "url": "/api/test"
    },
    "response": {
        "status": 200,
        "body": "{ \"test\": \"data\" }",
        "headers": {
            "Content-Type": "application/json"
        }
    }
}'
Enter fullscreen mode Exit fullscreen mode

Running this should give you a 201 created response.

Now when we call http://localhost:8080/api/test we should get back the following:

{
  "test": "data"
}
Enter fullscreen mode Exit fullscreen mode

All you need to do is change the request and response and you can mock any API call.

POST Request

Mocking GET request by URL is the simplest option but if you are doing POST requests you are probably going to want to mock based on the request body.

For example, lets mock the POST endpoint that maps based on the body content:

curl --location --request POST 'http://localhost:8080/__admin/mappings/new' \
--header 'Content-Type: application/json' \
--data-raw '{
    "request": {
        "method": "POST",
        "url": "/api/test",
        "bodyPatterns" : [{
          "matchesJsonPath" : {
             "expression": "$",
             "equalToJson": "{ \"test\": \"banana\" }"
          }
        }]
    },
    "response": {
        "status": 201,
        "body": "{ \"test\": \"banana created\" }",
        "headers": {
            "Content-Type": "application/json"
        }
    }
}'
Enter fullscreen mode Exit fullscreen mode

Just to prove it works we are now going to map another one based on a different body (fruit).

curl --location --request POST 'http://localhost:8080/__admin/mappings/new' \
--header 'Content-Type: application/json' \
--data-raw '{
    "request": {
        "method": "POST",
        "url": "/api/test",
        "bodyPatterns" : [{
          "matchesJsonPath" : {
             "expression": "$",
             "equalToJson": "{ \"test\": \"apple\" }"
          }
        }]
    },
    "response": {
        "status": 201,
        "body": "{ \"test\": \"apple created\" }",
        "headers": {
            "Content-Type": "application/json"
        }
    }
}'
Enter fullscreen mode Exit fullscreen mode

You can test it out by running the following:

curl --location --request POST 'http://localhost:8080/api/test' \
--header 'Content-Type: application/json' \
--data-raw '{
    "test": "banana"
}'

curl --location --request POST 'http://localhost:8080/api/test' \
--header 'Content-Type: application/json' \
--data-raw '{
    "test": "apple"
}'
Enter fullscreen mode Exit fullscreen mode

This is just a simple example, if you need something more advanced, check out the request matching documentation for more examples.

Resetting Mappings

If you want to reset all your mappings at any point then you can do so by sending a POST request to http://localhost:8080/_admin/reset

curl --location --request POST 'http://localhost:8080/__admin/reset'
Enter fullscreen mode Exit fullscreen mode

Adding mappings using files

The other way to add your mock mappings is by using files that are loaded when the container is started. This is particularly useful if you want other developers to be able to run your code.

I prefer to run all my docker containers using docker-compose. That way all people need to do is run docker-compose up and everything will be set up for them.

Your docker-compose.yml file should look something like this:

version: '3.4'

services:
  wiremock:
    image: rodolpheche/wiremock
    container_name: wiremock
    volumes:
      - ./ __files:/home/wiremock/__ files
      - ./mappings:/home/wiremock/mappings
    ports:
      - 8080:8080
Enter fullscreen mode Exit fullscreen mode

When you run docker-compose up it will create a __files and a mappings folder in your current directory that are mounted to the same folders in your container.

The mappings folder is where you save your json mappings. Each file is exactly the same as the body of the request that we were sending earlier.

For example:

{
  "request": {
    "url": "/api/test",
    "method": "GET"
  },
  "response": {
    "status": 200,
    "body": "{ \"test\": \"data\" }",
    "headers": {
      "Content-Type": "application/json"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

If you want you can even just save the mappings we created by API earlier by sending a POST request to http://localhost:8080/__admin/mappings/save.

curl --location --request POST 'http://localhost:8080/__admin/mappings/save'
Enter fullscreen mode Exit fullscreen mode

If you update any of the files that are saved in the mappings folder then you will need to run a reset before they take effect.

curl --location --request POST 'http://localhost:8080/__admin/reset'
Enter fullscreen mode Exit fullscreen mode

The __files folder can be used to serve static files. For example if we put a simple index.html file in this folder like this:

<!DOCTYPE html>
<html>
  <body>
    <h1>Mocked File</h1>
    <p>Something interesting here</p>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Then go to http://localhost:8080 you should see this:

Mocked Website

Final Thoughts

Using mocks can be a great way to simulate the behaviour of external APIs. Wiremock is one of the simplest ways to get started. That being said, I have found that wiremock isn’t the fastest way to mock an API. I recently had to mock an FX rate endpoint with a set of static FX rates. It was much faster to do this with a simple API written in Node.js.

There is another version of Wiremock that I use regularly called Wiremock.Net which is particularly useful when writing .NET integration tests. I will cover that in my next post as it is a bit more involved than this one.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player