docs/content/guides/wiremock.md

298 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: Mocking API services in development and testing with WireMock
description: &desc Mocking API services in development and testing with WireMock
keywords: WireMock, container-supported development
linktitle: Mocking API services with WireMock
summary: *desc
tags: [app-dev, distributed-systems]
languages: [js]
params:
time: 20 minutes
---
During local development and testing, it's quite common to encounter situations where your app is dependent on the remote APIs. Network issues, rate limits, or even downtime of the API provider can halt your progress. This can significantly hinder your productivity and make testing more challenging. This is where WireMock comes into play.
WireMock is an open-source tool that helps developers to create a mock server that simulates the behavior of real APIs, providing a controlled environment for development and testing.
Imagine you have both an API and a frontend app, and you want to test how the frontend interacts with the API. Using WireMock, you can set up a mock server to simulate the API's responses, allowing you to test the frontend behavior without relying on the actual API. This can be particularly helpful when the API is still under development or when you want to test different scenarios without affecting the actual API. WireMock supports both HTTP and HTTPS protocols and can simulate various response scenarios, including delays, errors, and different HTTP status codes.
In this guide, you'll learn how to:
- Use Docker to launch up a WireMock container.
- Use mock data in the local development without relying on an external API
- Use a Live API in production to fetch real-time weather data from AccuWeather.
## Using WireMock with Docker
The official [Docker image for WireMock](https://hub.docker.com/r/wiremock/wiremock) provides a convenient way to deploy and manage WireMock instances. WireMock is available for various CPU architectures, including amd64, armv7, and armv8, ensuring compatibility with different devices and platforms. You can learn more about WireMock standalone on the [WireMock docs site](https://wiremock.org/docs/standalone/docker/).
### Prerequisites
The following prerequisites are required to follow along with this how-to guide:
- [Docker Desktop](https://www.docker.com/products/docker-desktop/)
### Launching WireMock
Launch a quick demo of WireMock by using the following steps:
1. Clone the [GitHub repository](https://github.com/dockersamples/wiremock-node-docker) locally.
```console
$ git clone https://github.com/dockersamples/wiremock-node-docker
```
2. Navigate to the `wiremock-endpoint` directory
```console
$ cd wiremock-node-docker/
```
WireMock acts as the mock API that your backend will communicate with to retrieve data. The mock API responses have already been created for you in the mappings directory.
3. Start the Compose stack by running the following command at the root of the cloned project directory
```console
$ docker compose up -d
```
After a moment, the application will be up and running.
![Diagram showing the WireMock container running on Docker Desktop ](./images/wiremock-using-docker.webp)
You can check the logs by selecting the `wiremock-node-docker` container:
![Diagram showing the logs of WireMock container running on Docker Desktop ](./images/wiremock-logs-docker-desktop.webp)
4. Test the Mock API.
```console
$ curl http://localhost:8080/api/v1/getWeather\?city\=Bengaluru
```
It will return the following canned response with mock data:
```plaintext
{"city":"Bengaluru","temperature":27.1,"conditions":"Mostly cloudy","forecasts":[{"date":"2024-09-02T07:00:00+05:30","temperature":83,"conditions":"Partly sunny w/ t-storms"},{"date":"2024-09-03T07:00:00+05:30","temperature":83,"conditions":"Thunderstorms"},{"date":"2024-09-04T07:00:00+05:30","temperature":83,"conditions":"Intermittent clouds"},{"date":"2024-09-05T07:00:00+05:30","temperature":82,"conditions":"Dreary"},{"date":"2024-09-06T07:00:00+05:30","temperature":82,"conditions":"Dreary"}]}
```
With WireMock, you define canned responses using mapping files.
For this request, the mock data is defined in the JSON file at
`wiremock-endpoint/mappings/getWeather/getWeatherBengaluru.json`.
For more information about stubbing canned responses, refer to the
[WireMock documentation](https://wiremock.org/docs/stubbing/).
## Using WireMock in development
Now that you have tried WireMock, lets use it in development and testing. In this example, you will use a sample application that has a Node.js backend. This app stack has the following configuration:
- Local Development Environment: The context in which the Node.js backend and WireMock are running.
- Node.js Backend: Represents the backend application that handles HTTP requests.
- External AccuWeather API: The real API from which live weather data is fetched.
- WireMock: The mock server that simulates the API responses during testing. It runs as a Docker container.
![Diagram showing the architecture of WireMock in development ](./images/wiremock-arch.webp)
- In development, the Node.js backend sends a request to WireMock instead of the actual AccuWeather API.
- In production, it connects directly to the live AccuWeather API for real data.
## Use mock data in local development
Lets set up a Node app to send requests to the WireMock container instead of the actual AccuWeather API.
### Prerequisite
- Install [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)
- Ensure that WireMock container is up and running (see [Launching Wiremock](#launching-wiremock)
Follow the steps to setup a non-containerized Node application:
1. Navigate to the `accuweather-api` directory
Make sure you're in the directory where your `package.json` file is located.
2. Set the environment variable.
Open `.env` file placed under `accuweather-api/` directory. Remove the old entries and ensure that it just contains the following single line.
```plaintext
API_ENDPOINT_BASE=http://localhost:8080
```
This will tell your Node.js application to use the WireMock server for API calls.
3. Examine the Application Entry Point
- The main file for the application is `index.js`, located in the `accuweather-api/src/api` directory.
- This file starts the `getWeather.js` module, which is essential for your Node.js application. It uses the `dotenv` package to load environment variables from the`.env` file.
- Based on the value of `API_ENDPOINT_BASE`, the application routes requests either to the WireMock server (`http://localhost:8080`) or the AccuWeather API. In this setup, it uses the WireMock server.
- The code ensures that the `ACCUWEATHER_API_KEY` is required only if the application is not using WireMock, enhancing efficiency and avoiding errors.
```javascript
require("dotenv").config();
const express = require("express");
const axios = require("axios");
const router = express.Router();
const API_ENDPOINT_BASE = process.env.API_ENDPOINT_BASE;
const API_KEY = process.env.ACCUWEATHER_API_KEY;
console.log('API_ENDPOINT_BASE:', API_ENDPOINT_BASE); // Log after it's defined
console.log('ACCUWEATHER_API_KEY is set:', !!API_KEY); // Log boolean instead of actual key
if (!API_ENDPOINT_BASE) {
throw new Error("API_ENDPOINT_BASE is not defined in environment variables");
}
// Only check for API key if not using WireMock
if (API_ENDPOINT_BASE !== 'http://localhost:8080' && !API_KEY) {
throw new Error("ACCUWEATHER_API_KEY is not defined in environment variables");
}
// Function to fetch the location key for the city
async function fetchLocationKey(townName) {
const { data: locationData } = await
axios.get(`${API_ENDPOINT_BASE}/locations/v1/cities/search`, {
params: { q: townName, details: false, apikey: API_KEY },
});
return locationData[0]?.Key;
}
```
4. Start the Node server
Before you start the Node server, ensure that you have already installed the node packages listed in the package.json file by running `npm install`.
```console
npm install
npm run start
```
You should see the following output:
```plaintext
> express-api-starter@1.2.0 start
> node src/index.js
API_ENDPOINT_BASE: http://localhost:8080
..
Listening: http://localhost:5001
```
The output indicates that your Node application has successfully started.
Keep this terminal window open.
5. Test the Mocked API
Open a new terminal window and run the following command to test the mocked API:
```console
$ curl "http://localhost:5001/api/v1/getWeather?city=Bengaluru"
```
You should see the following output:
```plaintext
{"city":"Bengaluru","temperature":27.1,"conditions":"Mostly cloudy","forecasts":[{"date":"2024-09-02T07:00:00+05:30","temperature":83,"conditions":"Partly sunny w/ t-storms"},{"date":"2024-09-03T07:00:00+05:30","temperature":83,"conditions":"Thunderstorms"},{"date":"2024-09-04T07:00:00+05:30","temperature":83,"conditions":"Intermittent clouds"},{"date":"2024-09-05T07:00:00+05:30","temperature":82,"conditions":"Dreary"},{"date":"2024-09-06T07:00:00+05:30","temperature":82,"conditions":"Dreary"}]}%
```
This indicates that your Node.js application is now successfully routing requests to the WireMock container and receiving the mocked responses
You might have noticed that youre trying to use `http://localhost:5001` as the URL instead of port `8080`. This is because your Node.js application is running on port `5001`, and it's routing requests to the WireMock container that's listening on port `8080`.
> [!TIP]
> Before you proceed to the next step, ensure that you stop the node application service.
## Use a Live API in production to fetch real-time weather data from AccuWeather
To enhance your Node.js application with real-time weather data, you can seamlessly integrate the AccuWeather API. This section of the guide will walk you through the steps involved in setting up a non-containerized Node.js application and fetching weather information directly from the AccuWeather API.
1. Create an AccuWeather API Key
Sign up for a free AccuWeather developer account at[https://developer.accuweather.com/](https://developer.accuweather.com/). Within your account, create a new app by selecting `MY APPS` on the top navigation menu to get your unique API key.
![Diagram showing the AccuWeather Dashboard](images/wiremock-accuweatherapi.webp)
[AccuWeather API](https://developer.accuweather.com/) is a web API that provides real-time weather data and forecasts. Developers can use this API to integrate weather information into their applications, websites, or other projects.
2. Change directory to `accuweather-api`
```console
$ cd accuweather-api
```
3. Set your AccuWeather API key using the `.env` file:
> [!TIP]
> To prevent conflicts, ensure that any existing environment variables named `API_ENDPOINT_BASE` or `ACCUWEATHER_API_KEY` are removed before modifying the `.env` file.
Run the following command on your terminal:
```console
unset API_ENDPOINT_BASE
unset ACCUWEATHER_API_KEY
```
Its time to set the environment variables in the `.env` file:
```plaintext
ACCUWEATHER_API_KEY=XXXXXX
API_ENDPOINT_BASE=http://dataservice.accuweather.com
```
Make sure to populate `ACCUWEATHER_API_KEY` with the correct value.
4. Install the dependencies
Run the following command to install the required packages:
```console
$ npm install
```
This will install all the packages listed in your `package.json` file. These packages are essential for the project to function correctly.
If you encounter any warnings related to deprecated packages, you can ignore them for now for this demonstration.
5. Assuming that you dont have a pre-existing Node server running on your system, go ahead and start the Node server by running the following command:
```console
$ npm run start
```
You should see the following output:
```plaintext
> express-api-starter@1.2.0 start
> node src/index.js
API_ENDPOINT_BASE: http://dataservice.accuweather.com
ACCUWEATHER_API_KEY is set: true
Listening: http://localhost:5001
```
Keep this terminal window open.
6. Run the curl command to send a GET request to the server URL.
In the new terminal window, enter the following command:
```console
$ curl "http://localhost:5000/api/v1/getWeather?city=Bengaluru"
```
By running the command, you're essentially telling your local server to provide you with weather data for a city named `Bengaluru`. The request is specifically targeting the `/api/v1/getWeather` endpoint, and you're providing the query parameter `city=Bengaluru`. Once you execute the command, the server processes this request, fetches the data and returns it as a response, which `curl` will display in your terminal.
When fetching data from the external AccuWeather API, you're interacting with live data that reflects the latest weather conditions.
## Recap
This guide has walked you through setting up WireMock using Docker. Youve learned how to create stubs to simulate API endpoints, allowing you to develop and test your application without relying on external services. By using WireMock, you can create reliable and consistent test environments, reproduce edge cases, and speed up your development workflow.