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

Taking a Creative Sabbatical as a Software Engineer

Taking a Creative Sabbatical as a Software Engineer

  • 28 September 2022
The last couple of years have been tough for many people. A mix of lockdowns and general anxiety has left many feeling burnt out and exhausted. For software developers, the move to working 100% remotely wasn’t as much of an upheaval as it has been fo...
Adding Inline Javascript to a React App

Adding Inline Javascript to a React App

  • 11 February 2022
Let me start this with a disclaimer, I am not a React expert and I am sure there are probably other ways to do this. If you know of a better way then please let me know in the comments! I have recently added Giscus to my blog which is a great way to ...
Privacy Focused Blog Services

Privacy Focused Blog Services

  • 28 January 2022
Towards the end of 2021, I started getting into web3 a lot more. Not only did I join the Developer DAO but I also launched my own NFT collection and wrote a few blog posts on the topic. One of the key components of web3 is the ownership of data. In w...
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...