Simulating Disruptions

Overview

It is all good when APIs run and service requests as expected. In a perfect world, they will be consistently fast and always successful. As a matter of fact, though, APIs do fail in different ways causing unforeseen disruptions.

Is your application ready to deal with disruptions in APIs it depends on?

Simulating disruptions, creating chaos, injecting faults…​whatever you call it, API Simulator can help your application be ready for the real world.

For more realistic disruption simulations, API Simulator supports Request Sampling - methods to select a subset, sample of simlet requests and disrupt only their responses in some way. Disrupting every simlet response is also possible as is applying more than one disruption to a response.

Failure Status Codes

From API Simulator’s perspective, returning a response with status code 400 (Bad Request) or 503 (Service Unavailable) is no different from returning 200 (OK). Status codes make sense in the context of a given API and API Simulator allows you to return whichever you like. In other words, returning a status code that denotes failure is "business as usual" with API Simulator.

Simulating Latency

Latency is inevitable. API clients and API providers communicate over networks, which have limitations and inconsistencies in terms of speed and reliability. That causes network latency.

APIs may experience internal problems and slowdowns leading to delays in replying, especially under load. That causes response times to increase.

If not handled properly, variable network latency and unexpected slow API responses may negatively affect an application and even cause cascading failures within the application.

The Simulating Latency document explains the options API Simulator supports for adding latency in a simulation.

Rate Limiting

Many APIs impose rate limiting where only a predefined number of calls per second are allowed and calls beyond that rate limit window of 1 second are rejected.

Here is how to simulate such rate limiting with API Simulator:

simlet: response-for-rate-limited-request


request:
- uriPath: /api/some/path
- method: GET


responses:
- when:
    request:
    - where: callsPerSecond
      exceed: 100
  # then
  from: stub
  status: 429
  headers:
  - "Content-Type: application/json"
  - "X-RateLimit-Limit: 100"
  body: `
{
  "status": "error",
  "message": "Rate limit exceeded"
}
`

  # otherwise
- from: stub
  status: 200
  headers:
  - "Content-Type: application/json"
  body: `
{
  "status": "OK"
}
`

Upon detecting that a GET request to /api/some/path is the 101st or later call within the same second, API Simulator will return response with status code 429 (Too Many Requests), and the configured headers and body.

The general format is as follows:

request:
  #...

responses:
#...
- when:
    request:
    #- ...
    - where: callsPerSecond
      exceed: <max-calls-per-second>
  #...

Things to consider:

  • The rate limiting is per API Simulator instance.

  • The sampling is approximate. Sudden bursts of requests, for example, could lead to a few more requests being allowed (not matched right away) than the configured exceed threshold.

  • Using rate-limiting sampling in request matching - the top-level request element - has no effect.

Connection Disruption

API server overloads, network blips, proxy problems, and other reasons could lead to connections being unexpectedly closed, even in the middle of a response. That can wreak havoc in API clients from both stability and response handling perspectives.

API Simulator gives you several options to configure connection disruptions to test and prepare your application for such problems.

A connection disruption is configured at the response level for a simlet. For example, for a single response definition:

response:
  #...

  # Close the connection for 10% of the responses
  # regardless of how many bytes have been output
  connection:
    close: randomly
    for: 10%

  #...

…​and the same for a response in a list of possible responses:

responses:
- when:
    #...

- when:
    request:
    #- ...
  # then
  #...
  connection:
    close: randomly
    for: 10%
  #...

  # otherwise
- from: ...
  status: 200
  #...

The general syntax is as follows:

connection:
  close: always | randomly
  # Only when closing randomly:
  for: <fractional-number-between-0.0-and-100.0>%
  # Optionally, after outputting some bytes
  after: <positive-fractional-number> b | bytes| KB | KiB | MB | MiB | GiB | GB

This gives a few combinations:

  • Always close connections without returning anything.

  • Always close connections after returning certain number of bytes.

  • Randomly close connections for some percent of the responses.

  • Randomly close connections for some percent of the responses and only after returning certain number of bytes.

Notice that for randomly closing connections and when percent is not 100, some responses will be excluded from the sampling so the connection will not be closed and the full output will be sent to the client. In addition, when randomly closing connections after some threshold size is reached, it could happen that the number of bytes output is above the threshold but the response is not selected right away and even the full output could be sent to the client.

API Simulator supports both decimal and binary units of data for the size of the output after which a connection is to be closed:

Decimal (base 10, metric)

Binary (base 2)

Value

Symbol

Name

Value

Symbol

Name

1000

KB

kilobyte

210 bytes = 1024

KiB

kibibyte

10002

MB

megabyte

10242

MiB

mebibyte

10003

GB

gigabyte

10243

GiB

gibibyte

Things to consider for HTTP/2 connections:

  • The size threshold is approximate. That is because HTTP/2 is a binary protocol that uses frames and the frames header bytes are part of the "counting".

  • SETTINGS frames exchanged when establishing HTTP/2 connection are not subject to connection disruption by size or closing the connection right away - connection disruption is defined at the response level for a simlet so there is no connection disruption until it is known which response a simlet will return.

  • When computing the size of output headers for HTTP/2 for disruption, it is the size of the HTTP/2 HEADERS frame in which the headers are compressed, not the size of the original header names and values.


We would love to hear your feedback! Shoot us an email to [feedback at APISimulator.com] about anything that is on your mind.

Happy API Simulating!