How to make mock API Response with Mitmproxy

5 min read
A diagram of API responses with Mitmproxy

I work at zen8labs as a mobile developer. The need to make mock A.P.I responses has become increasingly crucial for efficient testing and development workflows. While various tools offer powerful capabilities for intercepting and modifying HTTP traffic, they often come with an expensive price tag. This is where mitmproxy steps in as a cost-effective and feature-rich alternative.

Why Mitmproxy?

The limitations of other tools in Free License

ProxyMan, while being a powerful tool, faces limitations when it comes to mocking multiple requests simultaneously. This constraint can hinder developers who require the ability to mock various API responses concurrently.

On the other hand, Charles, despite its robust features, forces time restrictions in its free version. This limitation can be a roadblock for developers who need extended periods for testing and development without incurring additional costs.

Why Mitmproxy?

Choosing the right tool for intercepting and mocking A.P.I responses is essential, especially when budget constraints or functionality restrictions come into play. Mitmproxy stands out by offering a balance between powerful features and a cost-effective solution.

Key Advantages of Mitmproxy

  • Cost-Effective: Mitmproxy is an open source. Ensuring that developers can harness its capabilities without the financial burden associated with premium alternatives.
  • Multiple Request Mocking: Unlike some tools that limit the ability to mock multiple requests simultaneously. Mitmproxy excels in providing flexibility for diverse testing scenarios.
  • No Time Restrictions: Developers using mitmproxy won’t encounter time constraints in the free version. Allowing for extensive testing and development without interruptions.

Start using Mitmproxy

1. Installation

Begin by installing mitmproxy on your machine. Open your terminal or command prompt and run:

pip install mitmproxy

This will install mitmproxy along with its dependencies.

2. Start Mitmproxy

Once the installation is complete, you can start mitmproxy by running the following command:

mitmproxy

This will launch the mitmproxy interactive console, and you’ll start seeing captured requests and responses.

3. Configure Proxy Settings on Your MacBook

  • Open the “System Preferences” on your MacBook.
  • Go to “Network.”
  • Select your connected Wi-Fi network on the left.
  • Click on the “Advanced…” button.
  • Go to the “Proxies” tab.
  • Check the box next to “Web Proxy (HTTP)”.
  • In the “Web Proxy Server” field, enter the IP address of your MacBook and set the port to “8080”.
  • Check the box next to “Secure Web Proxy (HTTPS)”.
  • In the “Secure Web Proxy Server” field, enter the IP address of your MacBook and set the port to “8080”.
  • Click “OK” to save the changes.
  • After this step, you can see requests is showing in mitmproxy UI like this:

4. View https requests in iOS Simulator 

I have an iOS application using TMDP API which looks like this: 

Now, I want to view HTTP requests in mitmproxy. The next step is to install the certificate on the simulator: 

1. Open the Safari browser in the iOS Simulator
2. Visit the mitm.it page and download the certificate
3. Install and trust this certificate

Now, open the application to trigger an A.P.I call, and the requests will be displayed in mitmproxy: 

Modifying Responses based on JSON Configuration 

Mitmproxy provides a powerful A.P.I that allows you to create add-ons to intercept, analyze, and modify both requests and responses in real-time. This flexibility enables you to customize the behavior of mitmproxy to suit your specific testing or development needs. In this section, we’ll explore how to create a simple mitmproxy addon to modify requests and responses. 

1. Add-on Structure

Update the structure of the addon to read the JSON configuration file: 

import json 
from mitmproxy import http 
 
class ModifyAddon: 
    def __init__(self, config_path="modify_config.json"): 
        with open(config_path, "r") as config_file: 
            self.config = json.load(config_file) 
 
    def request(self, flow: http.HTTPFlow): 
        # Modify request logic goes here 
 
    def response(self, flow: http.HTTPFlow): 
        # Modify response logic goes here 

2. Modify Response Based on Configuration: 

Modify the response method to apply modifications based on the configuration: 

def response(self, flow: http.HTTPFlow): 
    for rule in self.config: 
        if ( 
            flow.request.method == rule["method"] and 
            flow.request.pretty_url == rule["url"] 
        ): 
            with open(rule["local_file"], "r") as local_file: 
                modified_content = local_file.read() 
            flow.response.content = modified_content.encode("utf-8") 

3. Example Configuration File (modify_config.json): 

Create a JSON configuration file specifying rules for response modifications: 

[ 
  { 
    "method": "GET", 
    "url": "https://api/example", 
    "local_file": "example.json" 
  }, 
  { 
    "method": "POST", 
    "url": "https://api/example", 
    "local_file": "example.json" 
  } 
] 

4. Verify the Response 

Let open my movie app and click to The Hunger Games: The Ballad of Songbirds & Snakes movie, this screen looks like that the left image.

Next, I created a configuration file like this: 

{ 
    "method": "GET", 
    "url": "https://api.themoviedb.org/3/movie/695721?append_to_response=videos,credits,reviews", 
    "local_file": "movie-detail.json" 
  }  

I have then modified the title of the movie in the movie-detail.json file and we can see the result in the right image.

You can see the detail source code here.

Conclusion

As we wrap up our journey through the intricacies of intercepting and modifying API responses, remember that effective testing and development require adaptability. The ability to simulate various scenarios empowers you to create robust and resilient applications.

Happy coding and may your A.P.I responses always be just what you need! If you’re interested in more information, have a look at our other blogs on the zen8labs website.

Quan Nguyen, Mobile Engineer 

Related posts

Normally when programming a mobile application, we often encounter apps crashing, which is when the current application cannot operate (force close). But there is another status that is less serious: Application Not Responding (ANR). Why is it less serious because your application can continue to be used normally after waiting? The question is how to minimize ANR errors? Let's find out below.
3 min read
This tutorial is to provide you with a deep understanding of the core components of RxSwift, focusing mainly on the implementation behind the scenes of RxSwift. After reading this post, it is hoped that you will have a clear understanding of what observables are, what subscriptions are, and how observables work.
7 min read
Communication between different software systems and services is essential in today's digital world. Developers constantly seek efficient and reliable ways to make these connections, and one technology that has gained significant traction in recent years is gRPC. In this article, we will explore what gRPC is, how it works, and why it has become a popular choice for building modern applications. 
3 min read