Today it’s not unusual to see organizations having implemented mocking in their daily workflow, as mock APIs allow developers to speed up their development and not rely on external services. For those reasons and others, many engineers are looking to learn more about the mocked APIs and how they can best be implemented into their organization.
Imagine you have an application with five different dependencies. If you want to test that application, you have to make sure that all those five dependencies are running in some capacity. It can be a sandbox API, but you still need them to be running. Imagine that those dependencies also have dependencies, then they also need to be running. Using a mocked API instead, you don’t need to rely on any dependencies. You can just use your own simple static API.
In this article you’ll learn a bit about what it means to mock an API in general, before going deeper into what it means to mock an API in Kubernetes. Lastly, you’ll be introduced to two different ways of mocking APIs inside Kubernetes.
What Does it Mean to Mock APIs?
Before looking into how mock APIs work inside of Kubernetes, it’s important to first understand what it means to mock an API in general. Mocking APIs is usually a practice used when performing tests. While mock APIs can be used in integration tests, it’s most commonly used in unit testing. They’re used when you want to test your own application, and not rely on the uptime of any other dependency.
Using the regular dependencies of an application, like an API or a database, you need that API or database to be up as well. Carrying that train of thought, you also need the dependency of the dependency to be up and running. Using mocked APIs removes this need.
With a mock API, you create a service that only returns a static response. A mocked API has no logic aside from returning the static data you’ve defined when you created the mock. Now, you’ve removed the need for dependencies to be up, and instead you will know for absolutely sure that you get the proper returned data when calling the API during testing. (Speedscale can actually dynamically vary the mocked responses based on inbound parameters).
This is of course only possible in the cases where you know for sure what data your dependencies are returning. If you are starting to use a new API in your application and you’re yet to figure out what parameters you need to send in the API request, you will have to use the actual API. But, once that is configured then you can start using mocked services.
Mock APIs are generally most useful in cases like CI/CD, where you can create pipelines that are running completely independently of any other services. This makes for quicker and more efficient pipelines. You can also implement continuous load testing using mocks, as you don’t risk putting load on dependencies. If you’re familiar with contract testing you’ll also know that mocks aren’t just useful, they’re needed. Mocks are useful in many different scenarios, and it’s worth knowing what it takes to run them.
Isolation Testing vs Mocking at the Edge
When you are developing an application you can generally split your dependencies up into two categories: close to the service, or at the edge. Dependencies close to the service are dependencies that live either alongside the service in the same Pod or Namespace. Testing an application with these dependencies can be referred to as isolation testing, as you are testing an isolated part of your infrastructure, like a single Deployment or Namespace. These are easier to mock, as there’s very little you need to consider in terms of cross-infrastructure.
On the other hand, dependencies at the edge are ones like external endpoints, cloud services, and third-party APIs. These can be more troublesome to mock, as you need to consider the regular communication between these services. While it’s not impossible to place mocks of these dependencies close to the service, it’s a good practice to place it somewhere close to where the original dependency is running. In terms of Kubernetes, that would be outside of the cluster.
This is all to say, that while mocks can make development a lot easier, there can still be some challenges you need to take into account when getting started.
Mock APIs Inside Kubernetes
While there are many principles to know about mocking in general, and while many of them can easily be implemented in Kubernetes, there are still a few things you need to consider when running mocks in Kubernetes specifically. Here are some of the things to think about when running mock APIs in Kubernetes.
East-West Networking vs North-South Networking in Kubernetes
In traditional server administration there’s a concept of east-west networking as well as north-south networking. East-west networking means that all your servers reside on the same layer, on the same network. It’s server-to-server communication, and all your communication stays inside your own local network. East-west is most likely calling another service inside the same cluster.
North-south networking is the opposite, where you have requests going from your app to the client or vice versa. In other words, requests leave your own local network and go onto the public network. North typically refers to traffic coming through the ingress, whereas South traffic is leaving the Kubernetes cluster, addressed to a fully-qualified domain name (e.g. api.stripe.com). This separation is useful to know about, as it can determine how you design your infrastructure.
When using Kubernetes, you will be using east-west networking as your Pods are going to be communicating with each other. However, you’ll also be using north-south networking when your applications need to request something from an API that’s outside of your cluster. This isn’t an issue in a normal production environment, simply something to be aware of when designing your infrastructure.
But, when you start working with mocks, you need to consider whether you need to implement the exact same type of networking. You may have north-south networking in some places where you are using third-party APIs, but can the mocked APIs be moved into the cluster so you’re instead fully using east-west networking? It’s often a good idea to keep the same type of networking in both production and testing, but making the small change of doing entirely east-west networking in testing can bring with it some benefits, like needing less strict ingress and egress rules.
Retaining the Environment of the Mocked Service
Kubernetes is a very complex tool, and there are many ways you can configure your applications to be run. In the previous section it was mentioned that you need to consider what type of networking you’re using when you start to mock services outside of your cluster. However, there are also considerations to be made about mocks created of services that are running inside your cluster.
You need to consider whether you need the mock to also replicate the environment of the service it’s mocking. Are you relying on Kubernetes functionality that you need to verify along with your Mock, like specific networking policies or hostname resolution? In most cases this won’t be an issue, but it’s something important to keep in mind when you start to create mocks. When you are making HTTP requests, you always have a lot of headers and other metadata. By not mocking an API completely, you may end up having requests where the metadata doesn’t resemble production.
Spinning up Mocks
As long as you have a tool that’s capable of creating the mocks you need, it’s fairly easy to start using them. You just need to get your mock deployed as a service, and then you can start using it like your regular APIs. However, when you are using Kubernetes you should consider whether there are ways to optimize the creation of your mocks. Kubernetes heavily relies on the concept of manifests. Services defined as yaml files. At the same time, Kubernetes is built to be a very dynamic environment.
It’s likely that you are using some form of command line tool to execute your unit tests, which is when you need to have mocked APIs. Here you can integrate a step in your command, where it automatically applies a Kubernetes manifest and spins up your mocked API. You can even integrate a step where it automatically removes the mocked API again.
It’s very popular to integrate GitOps into your workflow. For the uninformed, GitOps is the practice of interacting with your infrastructure and CI/CD entirely using Git. This can be done in a few ways, for example by leaving a comment in a Pull Request or including specific tags in your commits.
An incredibly popular scenario is using Git to trigger a test of your application before it gets deployed. In this case, you need to automatically spin up an instance of your application, as well as all the dependencies. This becomes troublesome when using GitOps, as one of the principles of GitOps is to empower the deployment of applications hundreds or thousands of times per day. This leads to a lot of requests to external dependencies, which can easily result in rate-limiting. In some cases it can even be impossible because of strictly configured networking rules.
Using mocked APIs in your GitOps solution will give you a more streamlined, efficient, and cost-effective solution.
Mocking an API in Kubernetes
Now that you know a bit more about the considerations you need to have when developing applications in Kubernetes, it’s time to learn about how these mocks can be created. It was touched on in the earlier section on spinning up mocks, but here is a more detailed explanation.
Deploying Separate Services
If you want to deploy your mocked APIs as separate service that you can then call, you need to deploy them as separate Pods or Deployments. With this approach, you need to first create a container image that your mock container can be based upon. Then, you need to define a Kubernetes manifest file for your mock, in which you will have to define at least a Service and a Pod. From here, you can configure your application to use the service as the mock endpoint.
The other approach to using mocked APIs inside Kubernetes is to use sidecars. This is arguably the solution that takes the most advantage of Kubernetes capabilities. A sidecar isn’t just a container that lives inside the same Pod as your application, it can also integrate deeply with your application container.
A tool like Speedscale can intercept all incoming and outgoing requests, and thereby record everything your application is doing. With all requests recorded, it’s easy to replay requests again at a later time. With sidecars, you don’t have to make a separate manifest file or Deployment. In the case of Speedscale, it’s as simple as adding a few annotations to your application, and then your requests will be mocked automatically.
Using a sidecar has the major advantage of being able to mock requests perfectly. Firstly, you don’t even need to change the URL of your API calls, as the sidecar will just intercept the request. Secondly, the request response will match the original response exactly, with all the metadata.
By now you know more about what it means to mock an API, and where it can be useful. You also know what you should think about when you start to mock APIs inside Kubernetes, like giving thought to network implementations, how much of the environment you want to replicate, and what approach you want to use when creating your mocks.
If you’re looking to mainly use mocked APIs in Kubernetes, check out Speedscale. It’s a platform that has a focus on providing service mocking in Kubernetes, allowing you to run mocks just by adding annotations.