Simulation "Hello, World!"

Overview

This is an example demonstrating how easy it is to model and run API simulations with API Simulator.

To be able to run the example you would need API Simulator installed and that is as simple as downloading the distro and unpacking it - see the installation document.

Along with other examples, this example is included in the distro download.

"Hello, World!" Stub

  1. Let’s create the following directory structure:

    hello-world-sim (1)
    └─ simlets (2)
       └─ hello-world (3)
    1 hello-world-sim is the name of the simulation.
    2 All simlets for the simulation reside under the simlets directory.
    3 hello-world is the directory where we will create the configuration for the "Hello, World!" simlet.
  2. Place in the hello-world directory a file called simlet.yaml with the following content while making sure the indentation is preserved:

    hello-world/simlet.yaml
    response:
      from: stub
      body: "Hello, World!"

    Notice that the simlet configuration doesn’t have anything about the request.

    The configuration uses the API Simulator’s YAML-based Domain-Specific Language (DSL). You don’t have to learn all of YAML - the DSL only uses few simple concepts: name/value pairs, maps, and lists.

  3. Start API Simulator for the hello-world-sim simulation (replace /path/to/ appropriately):

    apisimulator start "/path/to/hello-world-sim"
  4. Point your browser to http://localhost:6090/ or use curl:

    curl localhost:6090

    In both cases API Simulator replies with

    Hello, World!

Because this is how we configured the "Hello, World!" simlet and because the simulation doesn’t have any other simlets yet, API Simulator will actually reply with same response to any request. For example, try in the browser http://localhost:6090/greetings or http://localhost:6090/greetings/Luke, and these using curl:

curl localhost:6090/greetings
Hello, World!

curl -X POST localhost:6090/greetings
Hello, World!

curl -X GET localhost:6090/greetings/Luke
Hello, World!

curl localhost:6090/hi
Hello, World!

The same Hello, World! response comes back every time.

Execute this command to stop API Simulator (replace /path/to/ appropriately):

apisimulator stop "/path/to/hello-world-sim"

Dynamic Simlets

Replying with the same static Hello, World! response every time may be OK for some use cases but often times we need more than that. How about an API simlet where we pass in a name and API Simulator greets us using that name?

Name from Path Variable

This simlet will handle requests where the name comes from a path variable.

  1. Let’s extend the current setup and add another directory under simlets called greetings and create in it a file named simlet.yaml having the following content (again, make sure the indentation is preserved):

    greetings/simlet.yaml
    request:
    - method: GET
    
    - where: uriPathPattern
      matches: /greetings/{name}
    
    
    Name:
      is: parameter
      from: uriPathPattern
      pattern: /greetings/{name}
    
    
    response:
      from: template
      body: "Greetings, ${ Name }!"

    This is what you should have:

    hello-world-sim
    └─ simlets
       ├─ greetings
       │  └─ simlet.yaml
       └─ hello-world
          └─ simlet.yaml
  2. Start API Simulator for the hello-world-sim simulation (replace /path/to/ appropriately):

    apisimulator start "/path/to/hello-world-sim"
  3. Try in your browser to access http://localhost:6090/greetings/Luke and http://localhost:6090/greetings/Princess Leia, or with curl:

    curl -X GET localhost:6090/greetings/Luke
    Greetings, Luke!
    
    curl -X GET localhost:6090/greetings/Princess+Leia
    Greetings, Princess Leia!

We can now stop the API Simulator instance (replace /path/to/ appropriately):

apisimulator stop "/path/to/hello-world-sim"

The Explanation

Let’s take a look at each part of the simlet configuration:

greetings/simlet.yaml
request:
- method: GET  (1)

- where: uriPathPattern  (2)
  matches: /greetings/{name}


Name:  (3)
  is: parameter
  from: uriPathPattern
  pattern: /greetings/{name}


response:
  from: template  (4)
  body: "Greetings, ${ Name }!"  (5)
1 The greetings simlet matches requests that use the HTTP GET method.
2 In addition, requests' URI path must match the pattern /greetings/{name}. The pattern describes URI path that starts with /greetings/ and has one non-empty path segment {name}; how the segment is called isn’t important.
3 The simlet configuration defines a parameter - Name - which value comes from the URI path pattern /greetings/{name}, so it gets the value of whatever is in the {name} path segment after /greetings/.
4 The response is rendered from a template. By default, the template is an API Simulator Simula template.
5 The response body has a placeholder - ${ Name }. The placeholder is resolved (substituted, interpolated) using the value of the Name parameter.

There is no HTTP status code configured explicitly so API Simulator will return by default 200 OK.

The response to a request that doesn’t match the greetings simlet is rendered and returned according to the definition of the hello-world simlet because the hello-world simlet matches any and all requests that are not matched by another simlet with concrete request-matching rules.

Name from Query Parameter

It is also very easy to extract the name for the greeting from a URI query parameter. Let’s model a simlet for that.

Add another directory under simlets called hi and create a file simlet.yaml in it with the following content:

hi/simlet.yaml
request:
- method: GET

- where: uriPath
  equals: /hi


Name:
  is: parameter
  from: uriQueryParameter
  named: name


response:
  from: template
  body: "Hi, ${ Name?.first() ?: 'Stranger' }!"

Start API Simulator for the simulation and try in your browser to access http://localhost:6090/hi?name=Luke and http://localhost:6090/hi?name=Princess Leia, or with curl:

curl -X GET localhost:6090/hi?name=Luke
Hi, Luke!

curl -X GET localhost:6090/hi?name=Princess+Leia
Hi, Princess Leia!

What if we don’t pass a value for the name parameter or don’t pass name parameter at all? If the HTTP method is GET and the URI is /hi, we would get Hi, Stranger!. Try in your browser http://localhost:6090/hi?name= and http://localhost:6090/hi, or with curl:

curl -X GET localhost:6090/hi?name=
Hi, Stranger!

curl -X GET localhost:6090/hi
Hi, Stranger!

Let’s see why is that and what is this ${ Name?.first() ?: 'Stranger' } expression in the placeholder.

The request matching rules check for HTTP method of GET and for the URI path to be equal to /hi - they don’t check anything about a query parameter named name. So, a GET /hi request will be matched regardless of what are the query parameters.

Then the configuration defines the Name parameter with values (potentially more than one) from URI query parameter named name. It could happen that the query parameter named name is missing in a request or has no value - then the Name parameter value will be null. That is why we don’t just output in the body the value of the Name parameter. We use the expression ${ Name?.first() ?: 'Stranger' } where ?. is the Safe Navigation operator and ?: is the Elvis operator. In essence, if Name is not null then the first() method will be called to return its first value; if the result is not null then that value will be output, or otherwise Stranger will be output.

It is to note that the Safe Navigation and Elvis operators make the expression succinct - brief and, yet, clearly expressed. We could have as well used a scriptlet with if…​else statements instead.

Stop API Simulator just like before.

Built-in Request Object

API Simulator has a built-in object - _request - that we can use in a Simula template to get any component of the request without the need to define a parameter. Here is an example - a simlet called howdy - that uses the _request object to get the first value of the name URI query parameter:

howdy/simlet.yaml
request:
- method: GET

- where: uriPath
  equals: /howdy


response:
  from: template
  body: "Howdy, ${ _request.queryParams.first('name') ?: 'Stranger' }!"

The _request object is documented here.

curl -X GET localhost:6090/howdy?name=Luke
Howdy, Luke!

curl -X GET localhost:6090/howdy?name=Princess+Leia
Howdy, Princess Leia!

curl -X GET localhost:6090/howdy?name=
Howdy, Stranger!

curl -X GET localhost:6090/howdy
Howdy, Stranger!

Stop API Simulator.

Random Greeting

Let’s have more fun! How about a simlet that replies with a random greeting to an informal "hey"? Here is the hey simlet:

hey/simlet.yaml
request:
- method: GET

- where: uriPath
  equals: /hey


Greeting:
  is: parameter
  from: list
  list: [ Hi, Hello, Hey, Howdy ]
  pick: 1


response:
  from: template
  body: ${ Greeting }

The response from the simlet will be the value of the Greeting parameter - one randomly picked value from the list upon each execution of the simlet.

In Conclusion

Using API Simulator’s YAML DSL, we modeled in no time an API simulation with simlets for static and dynamic responses. We started an API Simulator instance locally and exercised the functionality of the API simulation.

This only scratches the surface of what is possible with API Simulator. We invite you to learn more about API Simulator, download and install it, run the examples found in the distro…​ Why not even create API simulations to help your own testing and development?


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!