https://github.com/alitari/mockgo-server
Lightweight and scalable server for mocking http endpoints
https://github.com/alitari/mockgo-server
go golang golang-application http kubernetes mock-server
Last synced: 7 months ago
JSON representation
Lightweight and scalable server for mocking http endpoints
- Host: GitHub
- URL: https://github.com/alitari/mockgo-server
- Owner: alitari
- License: apache-2.0
- Created: 2022-07-22T07:10:36.000Z (over 3 years ago)
- Default Branch: master
- Last Pushed: 2023-05-21T09:41:25.000Z (over 2 years ago)
- Last Synced: 2024-11-18T02:44:27.410Z (over 1 year ago)
- Topics: go, golang, golang-application, http, kubernetes, mock-server
- Language: Go
- Homepage:
- Size: 888 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# mockgo-server

[](https://bestpractices.coreinfrastructure.org/projects/6619)
[](https://github.com/alitari/mockgo-server/actions?workflow=Workflow&branch=master)
[](https://goreportcard.com/report/github.com/alitari/mockgo-server/mockgo)
[](https://codecov.io/gh/alitari/mockgo-server)
[](https://pkg.go.dev/github.com/alitari/mockgo-server/mockgo)


*mockgo-server* is a lightweight http server which can be used to mock http endpoints. *mockgo-server* is designed for horizontal scaling and feels at home in cloud environments like [kubernetes](https://kubernetes.io/) and [knative](https://knative.dev/). The main features are:
- **Simplicity** : easy configuration with human readable yaml files with reasonable defaults
- **Scalability** : mockgo-server is designed for horizontal scaling. Therefore it can be used in environments with high http traffic ( e.g. for performance/load tests )
- **Flexibility** : sometimes requirements for mocking requests goes beyond static responses. With templating mechanism and state management it is possible to implement particular logic for building responses.
## TL;DR
See [Examples.md](./Examples.md).
## variants
*mockgo-server* is built with different variants which have their own use cases. The following table gives an overview:
| variant | can scale | persistence | use this when you ... |
|---------------------|-----------|-------------|-----------------------------------------------------------------------------------------------|
| `mockgo-standalone` | no | no | want a simple setup and you don't need to scale, usually this variant is the starting point |
| `mockgo-grpc` | yes | no | have to deal with high incoming traffic, but you don't need durability for states and results |
| `mockgo-redis` | yes | yes | have to deal with high incoming traffic and you want a durable storage for states and results or if you want to use mockgo as serverless deployment in knative |
## install on kubernetes
Kubernetes is the first class environment for *mockgo-server*. So, if you have kubernetes cluster available, you can start right away with [helm](https://helm.sh/) charts:
```bash
helm repo add mockgo-server https://alitari.github.io/mockgo-server/
helm upgrade mymock mockgo-server/mockgo-server --install
```
see [here](./deployments/helm/mockgo-server/README.md) for further helm configuration options.
## install on knative
If you have a [knative](https://knative.dev/) cluster available, you can start right away with [kn](https://knative.dev/docs/client/install-kn/)
```bash
cat < kn-mock.yaml
endpoints:
- request:
path: "/hello-kn"
response:
statusCode: 200
body: "Hello from knative"
EOF
kubectl create configmap mockgo-config --from-file=kn-mock.yaml
kn service create mockgo --image=alitari/mockgo-standalone:v1.3.0 --mount /mockdir=cm:mockgo-config --env MOCK_DIR=/mockdir --env MOCK_PORT=8080
MOCKGO_URL=$(kn service describe mockgo -o url)
curl -v $MOCKGO_URL/hello-kn
```
See [here](./knative.md) for a example with redis.
## install on local machine
Define the environment :
```bash
MOCKGO_RELEASE_VERSION="v1.3.0"
MOCKGO_VARIANT="standalone" # or "grpc"
MOCKGO_OS="linux" # or "windows"
MOCKGO_ARCH="amd64" # or "arm64"
MOCKGO_NAME=mockgo-${MOCKGO_VARIANT}-${MOCKGO_OS}-${MOCKGO_ARCH}
```
### option 1: download binary excutable
```bash
wget https://github.com/alitari/mockgo-server/releases/download/$MOCKGO_RELEASE_VERSION/$MOCKGO_NAME
chmod +x $MOCKGO_NAME
# MOCK_DIR is the path for looking for mockfiles, per default this are files with names matching "*-mock.*"
MOCK_DIR=$(pwd)/test/mocks ./$MOCKGO_NAME
```
### option 2: go install
```bash
go install github.com/alitari/mockgo-server/mockgo-$MOCKGO_VARIANT/starter/mockgo@latest
MOCK_DIR=$(pwd)/test/mocks mockgo
```
### option 3: run with docker
```bash
MOCK_DIR=$(pwd)/test/mocks
docker run -it -v $MOCK_DIR:/mocks -e MOCK_DIR=/mocks alitari/mockgo-$MOCKGO_VARIANT:$MOCKGO_RELEASE_VERSION
```
## mockfiles and endpoints
A mockgo-server configuration consist of one or multiple files in yaml format, the so called *mockfiles*.
Each *mockfile* contains one or multiple *endpoints*.
The *endpoint* defines criteria which qualify the endpoint to serve an incoming request. This process is called *matching*.
The second configuration part of an *endpoint* is the definition of the http response.
```yaml
endpoints:
- id: "id" # [OPTIONAL] unique string to identify endpoint
prio: 1 # [OPTIONAL] integer to define precedence of endpoints if more than one endpoint matches
request: # request defines the matching
host: "alexkrieg.com" # [OPTIONAL], match to http host
method: "POST" # [OPTIONAL], match to http method, default is "GET"
path: "/mypath" # [MANDATORY], match to http request path
query: # [OPTIONAL] for matching, every key value pair must be part of the http query parameters of the incoming request
firstQueryParam: value1
secondQueryParam: value2
headers: # [OPTIONAL] for matching, every key value pair must be part of the http header values of the incoming request
Content-Type: "application/json"
Myheader: myheaderValue
body: "^{.*}$" # [OPTIONAL] regular expression which match to the request body
response: # defines the response
statusCode: 204 # [OPTIONAL], http response code ( see RFC 7231), defaults to "200"
body: "hello" # [OPTIONAL], response body as string, templates can be used
bodyFilename: "response.json" # [OPTIONAL], refers to a file which contains the response body, templates can be used in the file
headers: | # [OPTIONAL],multiline string in form of key: value, templates can be used
Content-Type: "application/text"
```
## path matching
The form of a http request can be described as a sequence of *pathsegments* which are separated through a `/`. In order to achieve flexibility matching the path of an http request, there are 3 special symbols which can be used for the *pathsegment* defining the `request.path`:
1. `*` every *pathsegment* on this position matches
2. `{pathvariable}` every *pathsegment* on this position matches, the value of the *pathsegment* is available as template variable with name `pathvariable`
3. `**` one or more arbitrary *pathsegments* match on this position
### examples
| `request.path` | incoming request path | match |
|---------------------|-----------------------|--------------------------------------------------------------|
| `/foo/*` | `/bar` | ➖ |
| `/foo/*` | `/foo` | ➖ |
| `/foo/*` | `/foo/bar` | ✅ |
| `/foo/*` | `/foo/bar/foo` | ➖ |
| `/foo/*/bar` | `/foo/bar` | ➖ |
| `/foo/*/bar` | `/foo/bar/bar` | ✅ |
| `/foo/{foo}/bar` | `/foo/bar/bar` | ✅ `{{ RequestPathParams.foo }}` resolves to `bar` |
| `/foo/*/{bar}` | `/foo/bar/bar/foo` | ➖ |
| `/foo/*/{bar}` | `/foo/bar/bar` | ✅ `{{ RequestPathParams.bar }}` resolves to `bar` |
| `/foo/**` | `/foo/` | ➖ |
| `/foo/**` | `/foo/bar` | ✅ |
| `/foo/**` | `/foo/bar/1/2/3` | ✅ |
| `/foo/**/{bar}` | `/foo/bar/1` | ✅ matches but `{{ RequestPathParams.bar }}` does not resolve |
| `/foo/**/foo/{bar}` | `/foo/bar/foo` | ➖ |
| `/foo/**/foo/{bar}` | `/foo/bar/1/2/foo/3` | ✅ `{{ RequestPathParams.bar }}` resolves to `3` |
## creating dynamic responses with go templates
In order to implement program logic, you can use [*go templates*](https://blog.gopheracademy.com/advent-2017/using-go-templates/) for creating dynamic responses.
The templating mechanism is available for the `response.body` and `response.headers` attributes and provides following additional functions for:
- common template functionality through the [sprig library](https://masterminds.github.io/sprig/)
- access to the incoming request through the `Request` variables
- using the key-value store
### access attributes of the incoming request
| template variable | type |
|-----------------------|--------------------------|
| `RequestPathParams` | `map[string]string` |
| `RequestUrl` | `string` |
| `RequestPath` | `string` |
| `RequestHost` | `string` |
| `RequestBody` | `string` |
| `RequestBodyJSONData` | `map[string]interface{}` |
### access the key-value store
There are 2 parameters which identifies a value in the key-value store:
- `store` is a string which identifies the store
- `key` is a string which identifies the value in the store
| template function name | signature | description |
|------------------------|----------------------------------------------|-----------------------------------------------------------------------|
| `kvStoreGet` | `func(store, key string) interface{}` | get the value from store `store`, which is stored under the key `key` |
| `kvStorePut` | `func(store, key string, value interface{})` | store value `value` under the key `key` in the store `store` |
| `kvStoreRemove` | `func(store, key string)` | remove the value under the key `key` from store `store` |
## mockgo-server api
The *mockgo-server* holds multiple kinds of state:
- current configuration (mock endpoints, logging , etc.)
- storage of incoming requests
- key-value store
All states can be accessed through an [REST](https://en.wikipedia.org/wiki/Representational_state_transfer) api.
The api is secured with basic auth which can be configured with the environment variables `API_USERNAME` and `API_PASSWORD`.
In order to avoid conflicts with the mock endpoints, the api is exposed under the path prefix `/__`.
This can be changed with the environment variable `API_PATH_PREFIX`.
### configuration api
| method | path | description |
|---------|--------------|-----------------------------------------|
| `POST` | `/__/reload` | reload the mock files from the mock dir |
### matching api
The request storage has a limited capacity which can be configured with `MATCHES_CAPACITY`.
| method | path | description |
|----------|---------------------------------|------------------------------------------------------------------------------------------------------|
| `GET` | `/__/matches/{endpointId}` | returns all requests which matched to an endpoint |
| `GET` | `/__/matchesCount/{endpointId}` | returns the count of requests which matched to an endpoint, is not limited through capacity |
| `GET` | `/__/mismatches` | returns all requests which didn't match to an endpoint |
| `GET` | `/__/mismatchesCount` | returns the count of all requests which didn't match to an endpoint, is not limited through capacity |
| `DELETE` | `/__/matches/{endpointId}` | deletes storage of all requests which matched to an endpoint |
| `DELETE` | `/__/mismatches` | deletes storage of all requests which didn't match to an endpoint |
### key-value store api
Using the path `/__/kvstore/{store}/{key}` you can access the key-value store with the following methods:
- `PUT` stores the content of the request body under the key `key` in the store `store`
- `GET` returns the content which is stored under the key `key` in the store `store`
- `DELETE` removes the content which is stored under the key `key` in the store `store`
## prometheus metrics
The *mockgo-server* exposes besides of the standard go metrics the following application specific counters:
- `matches{"endpoint":""}`: Number of matches of an endpoint
- `mismatches`: Number of requests which did not match to on endpoint
## using config reload feature
For local development it is useful to have a way to reload the mock files without restarting the *mockgo-server*. This can be achieved by sending a `POST` request to the reload endpoint. This functionality can be combined with a file watcher to automatically reload the mock files when they change. The script `scripts/watchmocks.sh` implements this functionality.
```bash
# watch for changes in test/main and reload the mock files
./scripts/watchmocks.sh test/main
```
## contribute
Learn how to contribute [here](./contribute.md)