Mocking API calls using WireMock

Published | 5 min read

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:

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.


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

What is DeFi? Understanding Decentralized Finance

What is DeFi? Understanding Decentralized Finance

  • 19 November 2021
If you are new to the crypto space the concepts of decentralised finance can seem a bit overwhelming. There are so many new terms to try and understand, it can be challenging to see how everything fits together. I have been working in the traditional...
Using Hashnode as a Source for Gatsby

Using Hashnode as a Source for Gatsby

  • 05 November 2021
I have done quite a few website migrations over the years. My blog like many first started out on WordPress. After several attempts at optimisation, I ended up generating a static version of my WordPress website. On my static site generation journey...
What is Web3? The Decentralised Internet Explained

What is Web3? The Decentralised Internet Explained

  • 15 October 2021
If you have stumbled upon this article you have probably seen the term web3 being mentioned around the internet. Especially on Twitter at the moment it seems to be the latest buzzword. With all the hype around NFTs and crypto at the moment, a lot of ...
Ditch the Ads: The Future of Website Monetization

Ditch the Ads: The Future of Website Monetization

  • 08 October 2021
Do you remember that scene in Ready Player One, when IOI are showing what the future of the Oasis will look like once they take over? “We have determined that we’ll be able to fill 80% of the user’s display with advertising before inducing seizures”...
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 feel like a fraud. It turns out, I am not the only one that feels this way and they have a name for it, it is c...
Using ngrok to test local websites and APIs

Using ngrok to test local websites and APIs

  • 07 April 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 Chrome Web Tools for mimicking a device but it isn’t the same as an actual phone. Chances are however that if you t...
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 this website as well as other projects. However, the Sharp image library that Gatsby uses to resize images doesn’...

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.