Skip to content

The easiest way to test your web services securely and privately using a Docker container.

License

Notifications You must be signed in to change notification settings

joakim-ribier/mockapic

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mockapic

Go Report Card Software License Go Reference codecov

Docker Pulls Docker Image Size

Mockapic [mokapik] is a Go HTTP server - The easiest way to test your web services securely and privately using a Docker container.

It's always complicated to test easly your application when it uses external API services, for many reasons:

  • the service may not be free
  • it is limited on the calls
  • API response is not safe, it may change
  • I don't want to expose my authentication data (API_KEY) in my tests
  • it's not possible to test my implementation on several behaviors
  • ...

It's for all these reasons that I created Mockapic (based on the awesome mocky.io idea). The main goal is to be able to better test your code on several behaviors when calling external API services.

Usage - How it works - APIs - Test - Docker - CI - Demo - Thanks - License

Usage

Use it as a service or directly with Docker.

As a service

# install the latest version
$ go install -v github.com/joakim-ribier/mockapic/cmd/httpserver@latest

# use the service
$ httpserver --port 3333 --home /home/{user}/app/mockapic

As a container

# pull the last version
$ docker pull joakimribier/mockapic:latest

# run the image
$ docker run -it --rm -p 3333:3333 -e MOCKAPIC_PORT=3333 joakimribier/mockapic

How it works

So, let's say I want to test my service which converts an EUR amount to USD. To convert the amount, my service needs to call an external API which returns the latest exchange rates data on the world.

To test my service, I want to mock the response of the external API to simulate several behaviors depends on the API result.

  1. I have to start Mockapic server (see the all parameters)
  2. I need to create several mocked requests based on the external API for different use case
  3. I have to configure my test to call the mocked url test instead of the external API

Parameters of the service

Option Env Value Default Description
--home MOCKAPIC_HOME /usr/app/mockapic . Define the working directory
--port MOCKAPIC_PORT 3333 3333 Define a specific port
--req_max MOCKAPIC_REQ_MAX_LIMIT 100 -1 (unlimited) Define the total number of the mocked requests allowed
--ssl MOCKAPIC_SSL true false Enable SSL/TLS HTTP server (need to provide certificate files)
--cert MOCKAPIC_CERT /usr/app/mockapic . Define the certificate directory that contains (mockapic.crt and mockapic.key)
--crt MOCKAPIC_CRT_FILE_PATH /usr/app/mockapic/*.crt ./mockapic.crt Define the *crt file path
--key MOCKAPIC_KEY_FILE_PATH /usr/app/mockapic/*.key ./mockapic.key Define the *key file path
  1. Start Mockapic
$ docker run -it -p 3333:3333 -e MOCKAPIC_PORT=3333 mockapic &
    __  ___              __                  _
   /  |/  /____   _____ / /__ ____ _ ____   (_)_____
  / /|_/ // __ \ / ___// //_// __ '// __ \ / // ___/
 / /  / // /_/ // /__ / ,<  / /_/ // /_/ // // /__   _  _  _
/_/  /_/ \____/ \___//_/|_| \__,_// .___//_/ \___/  (_)(_)(_)
                                 /_/
                    https://github.com/joakim-ribier/mockapic

Server running on port http[:3333]....
  1. Create new mocked requests

The first one simulate a real response of the external API service which returns the exchange rates:

$ curl -X POST 'http://localhost:3333/v1/new?status=200&contentType=application%2Fjson&charset=UTF-8&domain=github.com%2Fjoakim-ribier&project=mockapic&path=/currencies' \
--data '{
  "timestamp":1725967696,
  "rates":{
    "EUR":1,
    "GBP":0.842772,
    "KZT":527.025041,
    "USD":1.103546
  }
}' | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   408  100    48  100   360  13892   101k --:--:-- --:--:-- --:--:--  132k
{
  "id": "c1403100-3aa0-484f-8e0f-f2c1db80f371",
  "_links": {
    "raw": "http://localhost:3333/v1/raw/c1403100-3aa0-484f-8e0f-f2c1db80f371",
    "self": "http://localhost:3333/v1/c1403100-3aa0-484f-8e0f-f2c1db80f371"
  }
}

And the second simulate an internal server error from the external API service:

$ curl -X POST 'http://localhost:3333/v1/new?status=500&contentType=application%2Fjson&charset=UTF-8&domain=github.com%2Fjoakim-ribier&project=mockapic' | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   408  100    48  100   360  13892   101k --:--:-- --:--:-- --:--:--  132k
{
  "id": "79090265-a1af-47ec-a177-88668582ce28",
  "_links": {
    "raw": "http://localhost:3333/v1/raw/79090265-a1af-47ec-a177-88668582ce28",
    "self": "http://localhost:3333/v1/79090265-a1af-47ec-a177-88668582ce28"
  }
}
  1. Use the id from the response to call the mocked URL or the path parameter
# {id} from the response
$ curl -GET 'http://localhost:3333/v1/c1403100-3aa0-484f-8e0f-f2c1db80f371' | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    89  100    89    0     0   1226      0 --:--:-- --:--:-- --:--:--  1236
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=UTF-8
< Domain: github.com/joakim-ribier
< Project: mockapic
{
  "timestamp": 1725967696,
  "rates": {
    "EUR": 1,
    "GBP": 0.842772,
    "KZT": 527.025041,
    "USD": 1.103546
  }
}

# {path} parameter from the url ~/?path=/currencies
$ curl -GET 'http://localhost:3333/v1/currencies' | jq
...

or

$ curl -v -GET 'http://localhost:3333/v1/79090265-a1af-47ec-a177-88668582ce28'
* Request completely sent off
< HTTP/1.1 500 Internal Server Error
< Content-Type: application/json; charset=UTF-8
< Domain: github.com/joakim-ribier
< Project: mockapic

For more examples, please find for a specific language the use case of how to use Mockapic in your implementation:

Predefined requests

If you don't want to create a new mocked requests every time, you can also version a mocked requests file and load it directly by the server on startup.

The file must be in {MOCKAPIC_HOME}/mockapic.json or directly mount to the right destination -v /home/{user}/app/mockapic/mockapic.json:/usr/app/mockapic/mockapic.json using as a Docker container.

See an example of mockapic.json file

SSL/Tls

Run the HTTP server in SSL/Tls (https) mode with certificate.

  • --ssl parameter or $MOCKAPIC_SSL environment must be true
  • --cert parameter or $MOCKAPIC_CERT environment must contain mockapic.crt and mockapic.key files
$ ./httpserver \
  --home /home/{user}/app/mockapic \
  --port 3333 \
  --ssl true \
  --cert /home/{user}/app/mockapic # by default --home directory

APIs

List APIs available

Method Endpoint Description Status code
GET / Get info 200 OK
GET /static/content-types Get allowed content types 200 OK
GET /static/charsets Get allowed charsets 200 OK
GET /static/status-codes Get allowed status codes 200 OK
ALL /v1/{idOrPath} Get a mocked request {status mocked}
GET /v1/raw/{id} Get a raw mocked request 200 OK
GET /v1/list Get the list of all mocked requests 200 OK
POST /v1/new Create a new mocked request 201 Created

Create New Mocked Request

$ curl -X POST '~/v1/new?status={status}&contentType={contentType}&charset={charset}&{header1}={header1}&{header2}={header2}&path={path}' \
--data 'Hello World' | jq
{
  "id": "{id}",
  "_links": {
    "path": "{host}/v1/{path}",
    "raw": "{host}/v1/raw/{id}",
    "self": "{host}/v1/{id}"
  }
}
Field Required Value
status [x] Code HTTP (200, 204, 404, ...)
contentType [x] Content Type (application/json, text/plain...)
charset [x] Charset: UTF-8, UTF-16 or ISO-8859-1
body Body returns by the request ([]bytes(text, json))
headers Header parameters (x-key: value)
path Path to call the request (/my-path)

Get Mocked Request

$ curl -X GET '~/v1/{id}?delay=100ms'
Field Required Value
{id} [x] Request identifier returned by the POST API
delay Parameter to the URL to delay the response - Maximum delay: 60s

Raw Mocked Request

$ curl -X GET '~/v1/raw/{id}'

{
  "id": "{id}",
  "createdAt": "1970-01-01 00:00:01",
  "status": {status},
  "contentType": "{contentType}",
  "charset": "UTF-8",
  "headers": {
    "domain": "github.com/joakim-ribier",
    "project": "mockapic"
  },
  "body": "{raw}",
  "body64": "{base64}"
}

List requests

$ curl -X GET '~/v1/list' | jq
[
  {
    "id": "{id}",
    "createdAt": "1970-01-01 00:00:01",
    "status": {status},
    "contentType": "{contentType}",
    "charset": "UTF-8",
    "headers": {
      "domain": "github.com/joakim-ribier",
      "project": "mockapic"
    },
    "_links": {
      "raw": "{host}/v1/raw/{id}",
      "self": "{host}/v1/{id}"
    }
  },
  {
    "id": "{id}",
    "createdAt": "1970-01-01 00:00:01",
    "status": {status},
    "contentType": "{contentType}",
    "charset": "UTF-8",
    "headers": {
      "domain": "github.com/joakim-ribier",
      "project": "mockapic"
    },
    "_links": {
      "raw": "{host}/v1/raw/{id}",
      "self": "{host}/v1/{id}"
    }
  },
  ...

Test

$ go test ./... -race -covermode=atomic -coverprofile=coverage.out
...
ok  	github.com/joakim-ribier/mockapic/internal	1.642s	coverage: 100.0% of statements
ok  	github.com/joakim-ribier/mockapic/internal/server	2.181s	coverage: 91.0% of statements

Docker

Pull and Run

# pull the last version
$ docker pull joakimribier/mockapic:latest

# run the docker image with parameters
$ docker run -it --rm \
    -p 3333:3333 -e MOCKAPIC_PORT=3333 \
    -e MOCKAPIC_REQ_MAX_LIMIT=100 -e MOCKAPIC_SSL=true \
    -v /home/{user}/app/mockapic:/usr/app/mockapic \
    -v /home/{user}/app/mockapic/mockapic.json:/usr/app/mockapic/mockapic.json \
    -v /home/{user}/app/mockapic/mockapic.crt:/usr/app/mockapic/mockapic.crt \
    -v /home/{user}/app/mockapic/mockapic.key:/usr/app/mockapic/mockapic.key \
    joakimribier/mockapic

Build

# `--platform linux/amd64` to build container for Github Action
$ docker build --platform linux/amd64 -t mockapic .

...
=> exporting to image
=> => exporting layers
=> => writing image sha256:0ffc9be6749b23b64cad0aa4b665ca26b9e53b649855a156b9325557620c57d1
=> => naming to docker.io/library/mockapic

$ docker run -it --rm -p 3333:3333 -e MOCKAPIC_PORT=3333 mockapic
...
Server running on port 3333....

Push

$ docker tag mockapic:latest joakimribier/mockapic:latest
$ docker login -u "{username}" docker.io
$ docker push joakimribier/mockapic:latest

CI

Github action workflows *.yml

Name Description
Build test and coverage (reusable) Build, execute tests and push coverage report
Build and push docker image to Docker Hub (reusable) Build a container image on a specific version
Build and test pull request Execute build_test_and_coverage_reusable.yml workflow on pull request (without coverage)
Build, test and push coverage Execute build_test_and_coverage_reusable.yml workflow on main branch (with coverage)
Pre-release (Bump the release version) Bump the release version on the {inputs}
Publish binaries and tag Docker image Make binaries and execute build-and-push-container_reusable.yml after a new release
Publish new container image tag Execute build-and-push-container_reusable.yml workflow on the {inputs}

Demo

Access to the demo version to try the service (limited to 100 mocked requests), feel free to use it https://mockapic-dev.

the server is not always operational so don't hesitate to try later

Thanks

License

This software is licensed under the MIT license, see License for more information.

About

The easiest way to test your web services securely and privately using a Docker container.

Topics

Resources

License

Stars

Watchers

Forks