Mocking API calls using WireMock

By Alex Hyett on in Software Development

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

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

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
  }
}

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"
        }
    }
}'

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"
}

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"
        }
    }
}'

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"
        }
    }
}'

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"
}'

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'

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

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"
    }
  }
}

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'

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'

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>

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

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.


Was this post useful?
If you found this post useful and would like to support me, you can do so by buying me a coffee. Donations help keep this blog ad-free.

ALSO ON ALEXHYETT.COM

Dealing with Imposter Syndrome as a Software Developer

Dealing with Imposter Syndrome as a Software Developer

  • 28 May 2021
I have been a professional software developer for over a decade and I have been writing code for over 25 years. However, sometimes I still…
Using WireMock.net for Integration Testing

Using WireMock.net for Integration Testing

  • 21 May 2021
Last week I showed you how you can use Wiremock in a docker container to mock API calls that your application uses. This week is on a…
Using ngrok to test local websites and APIs

Using ngrok to test local websites and APIs

  • 07 May 2021
Often when I am creating a new website, I want to see how it is going to look on an actual device like my phone or tablet. You can use…
Using GitHub Actions to Deploy to S3

Using GitHub Actions to Deploy to S3

  • 26 March 2021
Recently I went through the process of setting up Drone CI on my Raspberry Pi. The plan was to use my Raspberry Pi as a build server for…
Getting Started with AWS Step Functions

Getting Started with AWS Step Functions

  • 12 March 2021
I have recently been looking into AWS Step Functions. For those not familiar with them, Step Functions are Amazon’s way of providing a state…
Useful Docker Commands Worth Saving

Useful Docker Commands Worth Saving

  • 12 February 2021
I use docker every day. All the applications I write at work or at home end up in docker containers. Most of the time though, I am only…
Grafana Monitoring on a Raspberry Pi

Grafana Monitoring on a Raspberry Pi

  • 28 January 2021
As you might have seen from my last few posts I have quite a lot running on my Raspberry Pi. I am currently using a Raspberry Pi 2 B which…

Alex Hyett
WRITTEN BY

Alex Hyett

Software Developer, Entrepreneur, Father, and Husband. Engineering Lead at Checkout.com.

Want to get in touch? You can find me here:


Join the Newsletter

Subscribe to get my latest content by email.

    I won't send you spam. Unsubscribe at any time.