API Simulation Configuration

Overview

If you have not already, make sure to read the Basic Concepts page to get you started.

Then go over the sections below to get an understanding of how to model and configure API simulations and their simlets. Find more in depth documentation on the pages that follow.

DSL for Simulation Modeling

Modeling API simulations via configuration for the Standalone API Simulator is now easier than ever with API Simulator’s unique Domain Specific Language (DSL). The expressive DSL allows us to define simlets using simple and easy to understand constructs.

The DSL is based on YAML. Don’t worry if YAML is something new to you - the DSL makes use of only a small subset of the whole YAML language. Few simple constructs, actually: name/value pairs, lists, and maps. Much like JSON but less verbose and easier to use for configurations. In no time you will be reading and writing simlets.

Here is a small example demonstrating a possible configuration for matching HTTP requests that have "GET" method and particular URI path:

request:
- method: GET
- uriPath: "/api/v2/categories"

About YAML

YAML (YAML Ain’t Markup Language), per the description on its web site, is a "…​human friendly data serialization standard for all programming languages". It has gained wide acceptance as the language of choice for configuration.

YAML uses indentation-based scoping. In general, an element must be indented further than its parent element, and elements at the same level have the same indentation.

Indentation is very important in YAML. The right indentation leads to a well-formed YAML document and proper interpretation of the configuration.

YAML and JSON

JSON is a subset of YAML 1.2 - a JSON document is also a YAML document.

API Simulator can load simlet configuration in JSON as well. However, the JSON-based DSL will not be documented at this time. While both YAML and JSON can be used for human-friendly representation of data structures, arguably perhaps, YAML is more suitable for configuration and JSON for messaging.

API Simulation Names

Each API Simulation has a name. A simulation name must be a valid subdomain name:

  • Starts with an a through z letter.

  • Then contains letters a through z, digits 0 through 9, and hyphen -, where hyphen is not the last character.

  • Has maximum length of 63.

  • Is case-insensitive.

These rules are currently not enforced; however, following them will assure backward compatibility in the future.

API Simlet Names

Each API simlet has a name. The names follow the rules for valid subdomain name like in API Simulation Names.

Creating a New Simulation

To create a new API Simulation simply create a directory and name it after the name of the simulation. See above for the rules to follow when naming it.

Next, model simulation’s simlets. API Simulator gives you a choice when it comes to organizing the simlets:

  • All-in-one configuration file.

  • Dedicated directory per simlet.

All-in-one Configuration

All simlets of a simulation can be defined in a single file named apisim.yaml and placed in the simulation’s directory:

api-simulation-name
└─ apisim.yaml

Inside apisim.yaml, simlet definitions are separated by three dashes --- on a line:

simlet: <simlet1-name>
<simlet1 definition>
---
simlet: <simlet2-name>
<simlet2 definition>
---
# ....
---
simlet: <simletN-name>
<simletN definition>

Each simlet requires a name followed by the simlet-specific configuration.

The all-in-one configuration file is suitable for small number of simlets with generally smaller response payloads. Otherwise, it becomes difficult to navigate up and down the single, potentially big file.

Directory per Simlet

Another option API Simulator supports is to have a directory per simlet, all under a directory called simlets:

api-simulation-name
└─ simlets

The configuration for each simlet is placed in a directory named after the simlet and under the simlets folder. There is always a file named simlet.yaml, which contains the simlet configuration. For example:

payments-simulation
└─ simlets
   ├─ create-payment
   │  └─ simlet.yaml
   ├─ get-payment
   │  └─ simlet.yaml
   ├─ list-payments
   │  ├─ simlet.yaml
   │  └─ large-payments-list.json
   └─ not-found
      └─ simlet.yaml

In the example above, create-payment, get-payment, list-payments, and not-found are directories for simlets with those names; each directory has a simlet.yaml file that contains the definition of that simlet. The list-payments directory also has another file that is external to simlet.yaml, presumably with the JSON body of the response.

If there is a simlet with some name in apisim.yaml and directory with that same name under simlets then the simlet from apisim.yaml will not get loaded - the one in simlets takes precedence.

Using External Files

Both options for organizing the simlets allow the HTTP response body for a simlet to be in an external file. Having a separate file helps with simlets that return binary content (e.g. images) and/or large responses.

External files are also supported for external scripts in scripting.

Aside from using absolute paths to external files, API Simulator supports the following global variables that can be used to represent relative paths to files:

  • ${sim.path} - resolves to the simulation directory.

  • ${simlets.path} - points to the simlets directory for the simulation.

Here is an example:

simlet: get-favicon

request:
- method: GET
- uriPath: /favicon.ico

response:
  from: stub
  headers:
  - "Content-Type: image/png"
  body:
    type: binary
    file: "${sim.path}/favicon-16x16.png"

In the example above, the favicon-16x16.png file is expected to be under the simulation directory as given by ${sim.path}.

Why do we have both ${sim.path} and ${simlets.path}? While technically ${sim.path} is currently the same as ${simlets.path}/.., that may change in the future.

Full-blown Directory Structure

Regardless which approach you choose for organizing the simlets, the following optional directory structure can help with simulations that are more complex:

api-simulation-name
├─ bin
├─ config
├─ lib
├─ logs
├─ scripts
└─ simlets

Here is a description of each directory:

Directory Description

bin

This optional directory can be a convenient place for custom scripts to start and stop the simulation. Such scripts could take care, for example, of setting all simulation-specific start and stop arguments.

config

Custom configuration, like for logging, can be placed in this directory. If the directory is missing, such configs can be placed directly under the simulation’s directory. Optional.

lib

API Simulator is extensible by custom code. Any compiled artifacts placed in this directory will be automatically added to the classpath. Optional.

logs

Log files will be created in this directory, if it exists. Otherwise, the log files will be created directly in the simulation’s directory. Optional.

scripts

If one or more of the simlets use scripting to enhance the API Simulator’s capabilities, files with the scripts can be placed in the "scripts" directory. Optional.

simlets

Contains configuration for each simlet that is part of the simulation. Optional when using all-in-one simlets configuration file.

On Request Mismatch

API Simulator matches incoming requests to determine the simlet which response to return. There are two options for when a request cannot be matched:

  • Use a default simlet.

  • Forward the unmatched request.

Default Simlet

To define a default, fallback simlet, create a simlet and give it any valid simlet name; then configure it as matching any request:

request: any

response:
  from: stub
  status: 400
  body: "What are you doing?"

The response can be anything, including a dynamic response from template.

If an API simulation does not define a default simlet and a request cannot be matched, API Simulator will use its built-in default simlet. It returns "404 Not Found" for HTTP status and "API Simulator couldn’t find a matching simlet for the request." for body.

Request Forwarding

For request forwarding to work, API Simulator must be called as a HTTP/S proxy for the calling API client. This way, requests will be sent to API Simulator and will contain the actual destination host. If a request matches a simlet, API Simulator will return the response; if a request does not match a simlet, the request will be forwarded unchanged to the actual destination, and the response relayed back. In essence, API Simulator will be a pass-through for unmatched requests.

This functionality is currently not exposed via the DSL. See the Command-line Arguments for how to configure API Simulator to forward unmatched requests.


We would love to hear your feedback! Shoot us a quick email to [feedback at APISimulator.com] to let us know what you think.

Happy API Simulating!