Skip to content

Commit

Permalink
Merge 8bc0807 into bc312ff
Browse files Browse the repository at this point in the history
  • Loading branch information
artem-zakharchenko committed Jul 2, 2019
2 parents bc312ff + 8bc0807 commit 6a4abd7
Show file tree
Hide file tree
Showing 32 changed files with 770 additions and 1,214 deletions.
223 changes: 212 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,225 @@
# Gavel.js — Validator of HTTP Transactions

[![npm version](https://badge.fury.io/js/gavel.svg)](https://badge.fury.io/js/gavel)
[![Build Status](https://travis-ci.org/apiaryio/gavel.js.svg?branch=master)](https://travis-ci.org/apiaryio/gavel.js)
[![Build status](https://ci.appveyor.com/api/projects/status/0cpnaoakhs8q58tn/branch/master?svg=true)](https://ci.appveyor.com/project/Apiary/gavel-js/branch/master)
[![Coverage Status](https://coveralls.io/repos/apiaryio/gavel.js/badge.svg?branch=master)](https://coveralls.io/r/apiaryio/gavel.js?branch=master)
[![Known Vulnerabilities](https://snyk.io/test/npm/gavel/badge.svg)](https://snyk.io/test/npm/gavel)

![Gavel.js - Validator of HTTP Transactions](https://raw.github.com/apiaryio/gavel/master/img/gavel.png?v=1)
<br />

<p align="center">
<img src="https://raw.githubusercontent.com/apiaryio/gavel/master/img/gavel.png?v=1" alt="Gavel logo" />
</p>

<h1 align="center">Gavel</h1>

Gavel detects important differences between actual and expected HTTP transactions (HTTP request and response pairs). Gavel also decides whether the actual HTTP transaction is valid or not.
Gavel is a library that validates a given HTTP transaction (request/response pair) and returns its verdict.

## Installation
## Install

```sh
$ npm install gavel
```bash
npm install gavel
```

## Documentation
## Usage

### CLI

```bash
# (Optional) Record HTTP messages
curl -s --trace - http://httpbin.org/ip | curl-trace-parser > expected
curl -s --trace - http://httpbin.org/ip | curl-trace-parser > actual

# Perform the validation
cat actual | gavel expected
```

> Example above uses [`curl-trace-parser`](https://github.com/apiaryio/curl-trace-parser).
### NodeJS

```js
const gavel = require('gavel');

// Define HTTP messages
const expected = {
statusCode: 200,
headers: {
'Content-Type': 'application/json'
}
};

const actual = {
statusCode: 404,
headers: {
'Content-Type': 'application/json'
}
};

// Perform the validation
const result = gavel.validate(expected, actual);
```

Executing the code above returns the next validation `result`:

```js
{
valid: false,
fields: {
statusCode: {
valid: false,
kind: 'text',
values: {
expected: 200,
actual: 404
},
errors: [
{
message: `Expected status code '200', but got '404'.`,
values: {
expected: 200,
actual: 404
}
}
]
},
headers: {
valid: true,
kind: 'json',
values: {
expected: {
'Content-Type': 'application/json'
},
actual: {
'Content-Type': 'application/json'
}
},
errors: []
}
}
}
```

### Usage with JSON Schema

You can describe the body expectations using [JSON Schema](https://json-schema.org/) by providing a valid schema to the `bodySchema` property of the expected HTTP message:

```js
const gavel = require('gavel');

const expected = {
bodySchema: {
type: 'object',
properties: {
fruits: {
type: 'array',
items: {
type: 'string'
}
}
}
}
};

const actual = {
body: JSON.stringify({
fruits: ['apple', 'banana', 2]
})
};

const result = gavel.validate(expected, actual);
```

The validation `result` against the given JSON Schema will look as follows:

```js
{
valid: false,
fields: {
body: {
valid: false,
kind: 'json',
values: {
actual: "{\"fruits\":[\"apple\",\"banana\",2]}"
},
errors: [
{
message: `At '/fruits/2' Invalid type: number (expected string)`,
location: {
pointer: '/fruits/2'
}
}
]
}
}
}
```

## Type definitions

### Input

> Gavel has no assumptions over the validity of a given HTTP message. It is the end user responsibility to operate on the valid data.
Both expected and actual HTTP messages inherit from a generic `HttpMessage` interface:

```ts
interface HttpMessage {
method?: string;
statusCode?: number;
headers?: Record<string> | string;
body?: string;
bodySchema?: Object | string; // string containing a valid JSON schema
}
```

Gavel will throw an exception when given invalid input data.

### Output

```ts
// Field kind describes the type of a field's values
// subjected to the end comparison.
enum FieldKind {
null // validation didn't happen (non-comparable data)
text // compared as text
json // compared as JSON
}

interface ValidationResult {
valid: boolean // validity of the actual message
fields: {
[fieldName: string]: {
valid: boolean // validity of a single field
kind: FieldKind
values: { // end compared values (coerced, normalized)
actual: any
expected: any
}
errors: FieldError[]
}
}
}

interface FieldError {
message: string
// Additional error information.
// Location is kind-specific.
location?: {
// JSON
pointer?: string
property?: string
}
values?: {
expected: any
actual: any
}
}
```

## API

- `validate(expected: HttpMessage, actual: HttpMessage): ValidationResult`

Gavel.js is a JavaScript implementation of the [Gavel behavior specification](https://www.relishapp.com/apiary/gavel/) ([repository](https://github.com/apiaryio/gavel-spec)):
## License

- [Gavel.js-specific documentation](https://www.relishapp.com/apiary/gavel/docs/javascript/)
- [CLI documentation](https://www.relishapp.com/apiary/gavel/docs/command-line-interface/)
MIT
2 changes: 1 addition & 1 deletion bin/gavel
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ process.stdin.on('end', function() {
const requestResult = gavel.validate(expectedRequest, realRequest);
const responseResult = gavel.validate(expectedResponse, realResponse);

if (requestResult.isValid && responseResult.isValid) {
if (requestResult.valid && responseResult.valid) {
process.exit(0);
} else {
process.exit(1);
Expand Down
6 changes: 3 additions & 3 deletions lib/units/isValid.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ function isValidField({ errors }) {

/**
* Returns a boolean indicating the given validation result as valid.
* @param {Object<string, any>} validationResult
* @param {Object<string, any>} fields
* @returns {boolean}
*/
function isValidResult(validationResult) {
return Object.values(validationResult.fields).every(isValidField);
function isValidResult(fields) {
return Object.values(fields).every(isValidField);
}

module.exports = {
Expand Down
Loading

0 comments on commit 6a4abd7

Please sign in to comment.