Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implemented initial version of schema validation #195 #196

Merged
merged 5 commits into from
Oct 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ Camouflage is a service virtualization tool inspired by [namshi/mockserver](http

📁 Comes with a file explorer UI that allows modification of mock files hosted remotely. 📁

✅ Validation of requests and responses using your OpenApi schema's. ✅

# Getting Started

1. Camouflage is an NPM package, therefore to install Camouflage, you'd need to install NodeJS (>v14) first, if you haven't already done so.
Expand Down Expand Up @@ -111,6 +113,11 @@ cache:
ttl_seconds: 300
injection:
enable: false
validation:
enable: true
schemas:
- type: OpenApi
url: https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.json
origins:
- http://localhost:3000
- http://localhost:3001
Expand Down
5 changes: 5 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ origins:
- http://localhost:3000
- http://localhost:3001
- http://localhost:5000
validation:
enable: true
schemas:
- type: OpenApi
url: https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.json
# ext_helpers: "./custom_handlebar.json"
# ext_data_source:
# pg:
Expand Down
Binary file added docs/MockValidation.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,5 @@ Camouflage is a service virtualization tool inspired by [namshi/mockserver](http
🎊 Deployable on standalone VMs, Dockers and Kubernetes. 🎊

📁 Comes with a file explorer UI that allows modification of mock files hosted remotely. 📁

✅ Validation of requests and responses using your OpenApi schema's. ✅
181 changes: 181 additions & 0 deletions docs/validation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
When testing software using a mock server it's important that your mocks are correct/valid to avoid false assumptions.

Contract testing is a grest methodology for ensuring that two separate systems are compatible and can communicate with one other.​

What sets this form of testing apart from other approaches that aim to achieve the same thing, is that each system can be tested independently from the other and that the contract is generated by the code itself, meaning the contract is always kept up to date with reality.​

![Mock validation using Contract Testing](MockValidation.png)

## OpenApi schema validation

Camouflage server support OpenApi schema's for request and response validation. When enabled the configured schema's are loaded in memory and each request and response simply need to adhere to the rules in schema.

### Configuration Options

By default, validation is disabled. To specify any of these optional configurations, modify config.yml in following way.

```yaml
validation:
enable: true
schemas:
- type: OpenApi
url: https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.json
```

### Example

Now when you have a mock for the supported endpoint `/pets` requesting it would result in a proper response.

```
HTTP/1.1 200 OK
Content-Type: application/json

[
{ "id": 1, "name": "Rabbit" },
{ "id": 2, "name": "Dog" },
{ "id": 3, "name": "Cat" },
{ "id": 4, "name": "Bird" }
]
```

#### Request validation

Given this schema for `/pets` we see that the only support parameter is the integer `limit`

```json
{
"openapi": "3.0.0",
"paths": {
"/pets": {
"get": {
"summary": "List all pets",
"operationId": "listPets",
"parameters": [
{
"name": "limit",
"in": "query",
"description": "How many items to return at one time (max 100)",
"required": false,
"schema": {
"type": "integer",
"format": "int32"
}
}
]
...
}
}
}
```

Called with an unsupported paraemeter like `/pets?unsupported=1` will result in the following 400 error.

```json
[
{
"path": "page",
"errorCode": "type.openapi.requestValidation",
"message": "unknown query parameter 'unsupported'",
"location": "query"
}
]
```

Called with a wrong type like `/pets?limit=abc` will also result in the following 400 error.

```json
[
{
"path": "limit",
"errorCode": "type.openapi.requestValidation",
"message": "must be integer",
"location": "query"
}
]
```

#### Response validation

Given this schema for `/pets` we see that a pet has two required properties `id` and `name`.

```json
{
"openapi": "3.0.0",
"paths": {
"/pets": {
"get": {
"summary": "List all pets",
"operationId": "listPets",
...
"responses": {
"200": {
"description": "A paged array of pets",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Pets"
}
}
}
},
...
}
}
"components": {
"schemas": {
"Pet": {
"type": "object",
"required": [
"id",
"name"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
},
"tag": {
"type": "string"
}
}
},
"Pets": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Pet"
}
},
...
}
}
}
```

In case previously your backend api did only had a required property `id` your assumptions in the tests are false.

```
HTTP/1.1 200 OK
Content-Type: application/json

[
{ "id": 1, "name": "Rabbit" },
{ "id": 2, "name": "Dog" },
{ "id": 3, "name": "Cat" },
{ "id": 4 }
]
```

Responses with the following mock will be blocked with a 409 response helping you to avoid mistakes.

```json
[
{
"path": "3",
"errorCode": "required.openapi.responseValidation",
"message": "must have required property 'name'"
}
]
```
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ nav:
- tests.md
- back-up-and-restore.md
- openAPI-conversion.md
- validation.md
- configuring-cache.md
- using-with-docker.md
- using-with-kubernetes.md
Expand Down
9 changes: 9 additions & 0 deletions mocks/pets/GET.mock
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
HTTP/1.1 200 OK
Content-Type: application/json

[
{ "id": 1, "name": "Rabbit" },
{ "id": 2, "name": "Dog" },
{ "id": 3, "name": "Cat" },
{ "id": 4, "name": "Bird" }
]
Loading