DEV Community

Cover image for How to Mock a RESTful Microservice
Clivern
Clivern

Posted on

How to Mock a RESTful Microservice

👋 there!

Recently I created a simple API mocking service called Rhino. That was because sometimes i have to integrate with a RESTful web service which is not ready yet or requires a lot of effort to setup and fill with data or Need a backend for a single page application & backend not ready yet.

GitHub logo Clivern / Rhino

❄️ HTTP Mocking & Debugging Service.

Rhino Logo

Rhino

HTTP Mocking & Debugging Service

Rhino is an HTTP Mocking & Debugging Service. It enables easy mocking of any HTTP web service for testing and debugging purposes. Also it can simulate high latencies and failures to make sure your services have the capability to withstand and recover from failures. It supports cross-origin resource sharing (CORS) so it can be used as a backend for single page applications.

Documentation

Usage

Get the latest binary.

$ curl -sL https://github.com/Clivern/Rhino/releases/download/x.x.x/Rhino_x.x.x_OS_x86_64.tar.gz | tar xz
Enter fullscreen mode Exit fullscreen mode

Create the config file config.prod.json

{
    "app": {
        "mode": "prod or dev"
        "port": "8080",
        "domain": "http://127.0.0.1:8080",
        "tls": {
            "status": "off",
            "pemPath": "/cert/server.pem",
            "keyPath": "/cert/server.key"
        }
    },
    "mock": [
        {
            "path": "/api/v2/service1/mock/:id",
            "request": {
                "method": "get"
Enter fullscreen mode Exit fullscreen mode

Rhino enables easy mocking of any HTTP web service for testing and debugging purposes. Also it can simulate high latencies and failures to make sure your services have the capability to withstand and recover from failures. It supports cross-origin resource sharing (CORS) so it can be used as a backend for single page applications.

In order to run Rhino locally:

{
    "app": {
        "mode": "prod",
        "port": "8080",
        "domain": "http://127.0.0.1:8080",
        "tls": {
            "status": "off",
            "pemPath": "/cert/server.pem",
            "keyPath": "/cert/server.key"
        }
    },
    "mock": [
        {
            "path": "/api/v2/service1/item",
            "request": {
                "method": "get"
            },
            "response": {
                "statusCode": 200,
                "headers": [
                    {"key": "Content-Type", "value": "application/json"}
                ],
                "body": "{\"action\": \"list\"}"
            },
            "chaos": {
                "latency": "0s",
                "failRate": "0%"
            }
        },
        {
            "path": "/api/v2/service1/item",
            "request": {
                "method": "post"
            },
            "response": {
                "statusCode": 200,
                "headers": [
                    {"key": "Content-Type", "value": "application/json"}
                ],
                "body": "{\"action\": \"create\"}"
            },
            "chaos": {
                "latency": "0s",
                "failRate": "0%"
            }
        },
        {
            "path": "/api/v2/service1/item/:id",
            "request": {
                "method": "get"
            },
            "response": {
                "statusCode": 200,
                "headers": [
                    {"key": "Content-Type", "value": "application/json"}
                ],
                "body": "{\"id\": \":id\", \"action\": \"get one\"}"
            },
            "chaos": {
                "latency": "0s",
                "failRate": "0%"
            }
        },
        {
            "path": "/api/v2/service1/item/:id",
            "request": {
                "method": "put"
            },
            "response": {
                "statusCode": 200,
                "headers": [
                    {"key": "Content-Type", "value": "application/json"}
                ],
                "body": "{\"id\": \":id\", \"action\": \"update\"}"
            },
            "chaos": {
                "latency": "0s",
                "failRate": "0%"
            }
        },
        {
            "path": "/api/v2/service1/item/:id",
            "request": {
                "method": "delete"
            },
            "response": {
                "statusCode": 200,
                "headers": [
                    {"key": "Content-Type", "value": "application/json"}
                ],
                "body": "{\"id\": \":id\", \"action\": \"delete\"}"
            },
            "chaos": {
                "latency": "0s",
                "failRate": "0%"
            }
        }
    ],
    "debug": [
        {
            "path": "/api/debug",
            "chaos": {
                "latency": "0s",
                "failRate": "0%"
            }
        }
    ],
    "log": {
        "level": "info",
        "output": "stdout",
        "format": "json"
    }
}
Enter fullscreen mode Exit fullscreen mode
  • The run rhino with that config file
$ rhino serve -c config.json
Enter fullscreen mode Exit fullscreen mode
  • On a different terminal, let's call these mocked endpoints
➜  ~ curl -X POST "http://127.0.0.1:8080/api/v2/service1/item"
{"action": "create"}

➜  ~ curl -X GET "http://127.0.0.1:8080/api/v2/service1/item"
{"action": "list"}

➜  ~ curl -X GET "http://127.0.0.1:8080/api/v2/service1/item/1"
{"id": "1", "action": "get one"}

➜  ~ curl -X PUT "http://127.0.0.1:8080/api/v2/service1/item/1"
{"id": "1", "action": "update"}

➜  ~ curl -X DELETE "http://127.0.0.1:8080/api/v2/service1/item/1"
{"id": "1", "action": "delete"}

Enter fullscreen mode Exit fullscreen mode

To run rhino with docker and docker compose:

Just close the repository and use either the simple or the advanced setup.

# Simple setup
$ git clone https://github.com/Clivern/Rhino.git
$ cd Rhino/deployment/basic/docker-compose
$ docker-compose up -d

# In case you want to visualize incoming requests with grafana
$ git clone https://github.com/Clivern/Rhino.git
$ cd Rhino/deployment/advanced/docker-compose
$ docker-compose up -d
Enter fullscreen mode Exit fullscreen mode

Rhino supports a bunch of fake data flags that can be used in the endpoint definition

AnyOf: @fake(:anyof[A||B||C||D])
Latitude: @fake(:lat)
Longitude: @fake(:long)
CreditCardNumber: @fake(:cc_number)
CreditCardType: @fake(:cc_type)
Email: @fake(:email)
DomainName: @fake(:domain_name)
IPV4: @fake(:ipv4)
IPV6: @fake(:ipv6)
Password: @fake(:password)
PhoneNumber: @fake(:phone_number)
MacAddress: @fake(:mac_address)
URL: @fake(:url)
UserName: @fake(:username)
TollFreeNumber: @fake(:toll_free_number)
E164PhoneNumber: @fake(:e_164_phone_number)
TitleMale: @fake(:title_male)
TitleFemale: @fake(:title_female)
FirstName: @fake(:first_name)
FirstNameMale: @fake(:first_name_male)
FirstNameFemale: @fake(:first_name_female)
LastName: @fake(:last_name)
Name: @fake(:name)
UnixTime: @fake(:unix_time)
Date: @fake(:date)
Time: @fake(:time)
MonthName: @fake(:month_name)
Year: @fake(:year)
DayOfWeek: @fake(:day_of_week)
DayOfMonth: @fake(:day_of_month)
Timestamp: @fake(:timestamp)
Century: @fake(:century)
TimeZone: @fake(:timezone)
TimePeriod: @fake(:time_period)
Word: @fake(:word)
Sentence: @fake(:sentence)
Paragraph: @fake(:paragraph)
Currency: @fake(:currency)
Amount: @fake(:amount)
AmountWithCurrency: @fake(:amount_with_currency)
UUIDHypenated: @fake(:uuid_hyphenated)
UUID: @fake(:uuid_digit)
Enter fullscreen mode Exit fullscreen mode

Happy coding everyone! ❤️

Top comments (2)

Collapse
 
mafflerbach profile image
mafflerbach

Just a question. How to deal with big responses? Is it possible to us a file instead?

Collapse
 
clivern profile image
Clivern

Yes, you can use files content as response in case of big response. like the following

        {
            "path": "/api/v2/service2/mock/:id",
            "request": {
                "method": "get",
                "parameters": {
                    "var_param": ":var_param",
                    "fixed_param": 10
                }
            },
            "response": {
                "statusCode": 200,
                "headers": [
                    {"key": "Content-Type", "value": "application/json"}
                ],
                "body": "@json:@config_dir/route.response.json"
            },
            "chaos": {
                "latency": "0s",
                "failRate": "0%"
            }
        }
Enter fullscreen mode Exit fullscreen mode

check this example too github.com/Clivern/Rhino/tree/mast...