# Introduction

## ![Rivet](/files/-LzJ3OCXPx7VcXdRTPhx)

Rapid, modern web service development, which typically involves layers of microservices, reaches a point where a single, non-backwards-compatible API change affects multiple teams. This in turn leads to cascading service failures and finger-pointing. **Rivet** defines a solution where each service tests itself against real clients to assert that no interfaces have broken any clients at each step of the way.

#### Vocabulary

Rivet uses *services* and *consumers* in describing these relationships.

* *Consumer* — A client that talks to an API service
* *Service* — An API service that consumers depend on for data

### The Problem

With these types of service relationships, trouble arises when you'd like to make a change to an API without breaking other consumers.

People use tools like API Blueprint, Swagger, or tests within the API's code itself to specify the requirements for an API. However, these tools and strategies do not account for the consuming applications that may break. You can change a response within the API's codebase and not know whether you've broken any given consumer.

### The Solution

By having the *consumers* define their requirements through contracts, you gain direct visibility into any *consumer*-breaking change to a *service*. For example, if you are forced to make a backwards-incompatible change (due to security, something upstream, or something simply out of your control), making the *service* aware of each client's requirements will tell you exactly what clients need to be updated to handle the change, whether or not you have versioned API mechanisms.

![](/files/-LzJ3OCZ-gT6YihQjCpK)

### Generic Metaphor

For example, take a factory that manufactures widgets:

Two customers come to have widgets made. The factory has a base widget *(with twist it, bop it, spin it)* that it modifies for different customers' needs, defined in a contract.

* **Customer 1:** widget with twist it, bop it, spin it
* **Customer 2:** widget with twist it, spin it
* **Factory:** Removes *bop it*, without checking the contracts in place for their customer orders
* **Customer 1:** Now mad that they don't have a *bop it* anymore
* **Customer 2:** Doesn't notice the change because it's not required

If the factory had checked the contracts that were in place, they would have known to add a *bop it* for Customer 1. In this scenario, the Factory is a *service*, and Customers are *consumers*. It's absurd to imagine a Factory not checking manufacturing contracts before delivering their widgets. In the same way, it's absurd to imagine that in software, a *service* doesn't check requirements before delivering a change.


# Consumer-Driven Contracts

## Consumer-Driven Contracts

We'd like to introduce a strategy for keeping your applications \[communication layer, APIs, etc..] in sync.

> Read more about [Consumer-Driven Contracts](https://thoughtworks.github.io/pacto/patterns/cdc/).

The primary actors involved are the consumer and the service:

* *Consumer* — defines and publishes a contract using&#x20;

  [JSON Schema](http://json-schema.org/)
* *Service* — imports and satisfies a contract

## How it works

The *consumer* maintains the contract for a given *service*.

1. The *consumer* creates a contract for an endpoint in a given *service.*
2. The *consumer* [publishes](/contracts/publishing) the contract to either an `npm registry` or git repository.
3. The *service* requires the contract, via `package.json`, at a very specific version, from the *consumer* from an npm package.
4. The *service* tests its API against the contract from the *consumer*.
5. If the contract tests fail, it means the contracts and the *consumer* application need to be updated to ensure that the *consumer* continues to work as expected.

![](/files/-LzJ3ON6HAI-O9dhH-pJ)

### The client consumes the API

> Your client is a *consumer* app that defines the contract for its *service* app: The API server.

Changes to server *(or service)* responses can potentially break the client *(or consumer)* without API developers knowing about the breaking changes. To prevent this, the *consumer* publishes a contract that it expects the API to satisfy. When the *service* runs tests, it verifies that its responses will satisfy the *consumer’s* needs. If the responses don’t satisfy the *consumer's* needs, we know that the *consumer* won’t work as expected after the changes are published. This visibility aids in preventing us from deploying breaking changes.


# Getting Started

Install Rivet using npm:

```
npm install --save-dev rivet
```

Or via yarn:

```
yarn add --dev rivet
```

Let's get started by creating a simple service API. First, create a file `route.js`

```javascript
module.exports = function (request, response) {
  const payload = {
    data: {
      userId: 1,
      id: 1,
      title: 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit',
      body: 'quia et suscipit suscipit recusandae consequuntur expedita et cum reprehenderit molestiae ut ut quas totam nostrum rerum est autem sunt rem eveniet architecto'
    }
  };

  response.status(200).json(payload);
};
```

Then, create a basic consumer contract file at `contracts/example.contract.js`

```javascript
module.exports = {
  title: 'Example',
  type: 'object',
  properties: {
    data: {
      type: 'object',
      properties: {
        userId: { type: 'integer' },
        id: { type: 'integer' },
        title: { type: 'string' },
        body: { type: 'string' }
      },
      required: ['userId', 'id', 'title', 'body'],
    }
  },
  required: ['data'],
};
```

## Writing Tests

### Consumer Test: Stubbing Data with a Contract

By using the contract to generate data for your contract tests, changes to the contract should expose any breaking-changes to the service API.

#### Install dependencies:

```
npm install nock axios jest --save-dev
```

#### Create a `consumer.test.js` file

```javascript
const { generateSync } = require('rivet');
const nock = require('nock');
const axios = require('axios');

describe('My Api', () => {
  it('satisfies the contract', (done) => {
    const stubbedData = generateSync('example.contract');

    nock('http://fakeser.ver')
    .get('/example')
    .reply(200, stubbedData);

    axios.get('http://fakeser.ver/example')
    .then((response) => {
      const payloadKeys = Object.keys(response.data);

      expect(payloadKeys)
      .toEqual(expect.arrayContaining([
        'userId',
        'id',
        'title',
        'body'
      ]));

      done();
    });
  });
});
```

### Service Test: Satisfying a Contract

Contracts can be used in any environment, given that they are JSON Schema files. The example here shows testing in a node environment, with jest, to validate that your api satisfies a consumer contract.

#### Install dependencies:

```
npm install jest jest-json-schema supertest express --save-dev
```

#### Create a `service.test.js` file

```javascript
const { matchers } = require('jest-json-schema');
const { load } = require('rivet');
const request = require('supertest');
const express = require('express');
const route = require('./route');

// add the jest-json-schema matchers to expect
expect.extend(matchers);

// setup the express app, with your new route
const app = express();
app.get('/example', route);

describe('My Api', () => {
  it('satisfies the contract', () => {
    // load the contract
    const schema = load('example.contract');

    request(app)
    .get('/example')
    .set('Accept', 'application/json')
    .expect(200)
    .then(response => {
      // Validate the response with the contract
      expect(response).toMatchSchema(schema);
    });
  });
});
```


# Contracts


# Configuration

If you don't want to use the Rivet default configuration, you can move your configuration into a separate file.

## File-based Configuring

### `package.json`

```javascript
{
  "rivet": {
    "contractsRoot": "contracts/"
  }
}
```

### Standalone file

Rivet accepts configuration files with the conventions.

* `.rivetrc`
* `.rivetrc.[js|json]`
* `.rivet.[js|json]`
* `rivetrc`
* `rivetrc.[js|json]`
* `rivet.[js|json]`

```javascript
module.exports = {
  contractsRoot: 'contracts/'
};
```

All configurations found will be merged into a single configuration object. That means if you have both a rivet configuration file, and rivet configuration defined in `package.json`, they will be merged. `package.json` is the last file read, and anything specified will overwrite other configurations.

> NOTE: Rivet configuration files are CommonJS modules. You can use any javascript here, as long as you export a configuration object.

## Configuration options

### `appRoot`

The root app path.

> Default: Root app directory with package.json

### `contractsRoot`

The root path to your contracts folder, relative to `appRoot`.

> Default: `contracts/"`

### `contractsPath`

Glob pattern used to find contract files, relative to `contractsRoot`.

> Default: `"**/*.contract.json"`

### `compiledContractsRoot`

The location where contracts are compiled, relative to `appRoot`.

> Default: `contracts/json`

### `aliases`

| alias:                                    | `require("mypath")`              | `require("mypath/endpoint.contract.js")`     |
| ----------------------------------------- | -------------------------------- | -------------------------------------------- |
| `{}`                                      | `"node_modules/mypath/index.js"` | `"node_modules/mypath/endpoint.contract.js"` |
| `{ mypath: "/absolute/path/to/file.js" }` | `"/absolute/path/to/file.js"`    | `error`                                      |
| `{ mypath: "/absolute/path" }`            | `"/absolute/path/index.js"`      | `"/absolute/path/endpoint.contract.js"`      |


# Helpers

## `load(contractPath)`

Loads a contract file referencing any [configured](/contracts/configuration) `aliases`.

## `generate(contractPath | schemaObject)` (async)

Generates mock data from a contract, asynchronously.

## `generateSync(contractPath | schemaObject)`

Generates mock data from a contract.


# Composability

With **Rivet** composability, you are able to reuse fundamental pieces of your contracts, such as data types, to make them much more maintainable. We do this by leveraging CommonJS modules and compiling your contracts to JSON.

## Composing with shared types

JSON Schema has a limited number of data types that it supports. For example, string, number, boolean. However, you can build custom data type validation using the `pattern` key in JSON schema.

### Custom Data Types

You can create custom data types to share between your contracts. If you need them on multiple applications, consider using an npm module.

**Custom** `animal` **data type:**

```javascript
// types/animal.js
module.exports = {
  id: 'types.animal',
  type: 'string',
  pattern: 'cat|dog'
};
```

**Usage:**

```javascript
// example.contract.js
const animal = require('./types/animal');

module.exports = {
  title: 'Example',
  type: 'object',
  properties: {
    pet: animal,
  },
  required: ['pet']
};
```

### Rivet default types

Rivet ships with a few [pre-defined data types](/contracts/composability#default-types).

```javascript
const { types } = require('rivet');

module.exports = {
  title: 'Example'
  type: 'object',
  properties: {
    email: types.email,
    phone: types.phone,
  },
  required: ['email', 'phone']
};
```

## Default Types

Below are the pre-defined types and their definitions.

### `email`

```javascript
{
  "id": "types.email",
  "type": "string",
  "format": "email",
  "pattern": "^(([^<>()\\\[\\]\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$"
}
```

> **Example Matches:**
>
> ```
> bob@sho.rt
> bob-villa@sho.rt
> bob@example.com
> bob.villa@example.com
> bob+villa@example.com
> ```

### `phone`

```javascript
{
  "id": "types.phone",
  "type": "string",
  "pattern": "^(?:(?:\\+?1\\s*(?:[.-]\\s*)?)?(?:\\(\\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\\s*\\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\\s*(?:[.-]\\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\\s*(?:[.-]\\s*)?([0-9]{4})(?:\\s*(?:#|x\\.?|ext\\.?|extension)\\s*(\\d+))?$"
}
```

> **Example Matches:**
>
> ```
> 12345678900
> +12345678900
> 2345678900
> (234) 567-8900
> (555)-555-5555
> 555-555-5555
> +1-555-532-3455
> ```

### `jwt`

```javascript
{
  "id": "types.jwt",
  "type": "string",
  "pattern": "^[A-Za-z0-9-_=]+\\.[A-Za-z0-9-_=]+\\.?[A-Za-z0-9-_.+/=]*$"
}
```

> **Example Matches:**
>
> ```
> ABC3EFGH.IJKLMN7PQRSTU.VWXYZ1234567890
> ```

### `uri`

```javascript
{
  "id": "types.uri",
  "type": "string",
  "pattern": "([A-Za-z][A-Za-z0-9+\\-.]*):(?:(//)(?:((?:[A-Za-z0-9\\-._~!$&'()*+,;=:]|%[0-9A-Fa-f]{2})*)@)?((?:\\[(?:(?:(?:(?:[0-9A-Fa-f]{1,4}:){6}|::(?:[0-9A-Fa-f]{1,4}:){5}|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}|(?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}|(?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:|(?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?::)(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))|(?:(?:[0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})?::)|[Vv][0-9A-Fa-f]+\\.[A-Za-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|(?:[A-Za-z0-9\\-._~!$&'()*+,;=]|%[0-9A-Fa-f]{2})*))(?::([0-9]*))?((?:/(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)|/((?:(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})+(?:/(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)?)|((?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})+(?:/(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)|)(?:\\?((?:[A-Za-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9A-Fa-f]{2})*))?(?:\\#((?:[A-Za-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9A-Fa-f]{2})*))?"
}
```

> **Example Matches:**
>
> ```
> http://foo.bar
> https://foo.bar
> http://foo.bar/baz
> https://foo.bar/baz
> http://foo.bar:3000
> http://foo.bar:3000/baz
> git://foo.bar/baz
> ssh://git@foo.bar/baz
> ssh://git@foo.bar/baz.git
> ```

### `uuid`

```javascript
{
  "id": "types.uuid",
  "type": "string",
  "format": "uuid",
  "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[34][0-9a-fA-F]{3}-[89ab][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
}
```

> **Example Matches:**
>
> ```
> efbf1234-1242-3fd1-8d9c-94d8c3a22ec7
> 14f114e8-449b-4bb8-b6b6-e0fe48b650e5
> 39b88796-8b6b-4f76-aacd-a530235f85b8
> 623bf773-a86f-4371-81c6-b4133cc67c73
> 69dab668-bcb6-40f9-90b2-0d3181da0987
> 9f20d246-bc75-4a8b-b423-9a238a7ea151
> 756be421-8985-4c0b-adc8-3c65c5807622
> ff984090-387d-4cc8-b9f9-1f4e348a9170
> 944595f4-8748-4ae7-bd4c-4de44e1cc2b3
> ff5d5b00-dc27-4ea7-a19f-8f934cee64f8
> 3fab55f4-a235-479c-8d79-60eba475390f
> 72308901-0849-4fb3-89a7-5e332672e785
> a8ab4e37-9786-46a3-955b-7c4fd5ed4f70
> ```


# Publishing

Because contracts live in your client applications, publishing and sharing contracts require maintaining a separate `package.json` specifically for your contracts. This lets you publish **only** your contracts to an npm registry.

## Private APIs

If you're working with a private API, it's recommended that you use either [private package](https://www.npmjs.com/features), or something else like [Gemfury](https://gemfury.com/) to keep your contracts private. If you're completely opposed to either of those options, you also have the option of using your github repo as your contract package.

## Distributing Contracts

The **Rivet** CLI helps manage your contracts with an npm registry. There are 4 CLI commands that you should be aware of. All of these commands are expected to be run from your consumer application root directory (along side your `package.json` that requires `rivet`)

### `rivet compile`

Compiles your javascript contract files into JSON Schema files, for distribution.

### `rivet watch`

Watches contracts for change to files, and compiles changes to JSON Schema files, for distribution.

### `rivet version <version|major|minor|patch>`

Bumps the contracts version, and writes the new version to the contracts' `package.json`. It will also create a version commit and tag.

### `rivet publish`

Publishes your contracts package to the registry.

> Note: Only use this, if you are using an npm registry to host your contracts.

## Importing Contracts


# CLI

```
* rivet init [name]                          - Scaffolds basic rivet configuration, files, and directories
* rivet link                                 - Link the package in the global node_modules
* rivet watch [src]                          - Watch and compile changes to contracts
* rivet compile [src]                        - Compile contracts from the [src] to JSON
* rivet publish                              - Publish the package with an optional version bump
* rivet config                               - Displays current configuration options
* rivet version <version|major|minor|patch>  - Bump the package version
```


