---
title: Validating the FormKeep API
teaser: Validate your client-server contracts with `json_matchers`.
tags: web,testing,rails,ruby,json,formkeep
author: Sean Doyle
published_on: 2015-10-12
---

[FormKeep's][formkeep] administrative interface is an Ember application that
consumes a Rails-backed JSON API. We test our JSON endpoints with RSpec's
[request specs].

Ensuring that the client and server adhere to a common contract is important.
Without test coverage, the contract is implicit and often times brittle.
Implementation changes on the server that change JSON payloads in
unexpected ways pose problems for consumers.

To guard against unexpected changes, we created [json\_matchers] to validate the
format of our JSON endpoints, making our contract explicit. Under
the covers, `json_matchers` validates payloads against schemas conforming to the
[JSON Schema] specification. Schemas serve as a codification of the
client-server contract.

[formkeep]: https://formkeep.com/
[request specs]: https://www.relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec
[json\_matchers]: https://github.com/thoughtbot/json_matchers
[JSON Schema]: http://json-schema.org/

## Asserting responses adhere to a JSON Schema

In order to verify that `GET /api/forms` serves JSON in the format our client
expects, we'll assert that it successfully validates against a particular
JSON schema:

```rb
describe "GET /api/forms" do
  it "returns the user's forms" do
    user = create(:user)
    form = create(:form, user: user)

    create(:form)

    json_get "/api/forms", api_token: user.api_token

    expect(response).to be_successful
    expect(response).to match_response_schema("forms-many")
  end
end

def json_response
  JSON.parse(response.body)
end
```

Next, we'll create the `forms-many` schema, declared in
`spec/support/api/schemas/forms-many.json`:

```json
{
  "type": "object",
  "required": [
    "forms"
  ],
  "properties": {
    "forms": {
      "type": "array",
      "items": { "$ref": "form.json" }
    }
  }
}
```

Note the `"$ref": "form.json"`, key-value pair. It denotes a
[canonical dereferencing][$ref], which allows us to reference and reuse a
`form` schema that we declare separately in
`spec/support/api/schemas/form.json`:

```json
{
  "type": "object",
  "required": [
    "id",
    "name",
    "redirect_url",
    "webhook_url",
    "field_map",
    "sandboxed"
  ],
  "properties": {
    "id": { "type": "string" },
    "name": { "type": "string" },
    "redirect_url": { "type": "string" },
    "webhook_url": { "type": "string" },
    "field_map": { "type": ["object", "null"] },
    "sandboxed": { "type": "boolean" }
  }
}
```

These two schemas, combined with the `match_response_schema` matcher,
guarantee the format, structure, and value types of the API response. Schema
changes necessitate serializer code changes, and vice versa.

This is a good thing, as it helps guarantee that your client's expectations
match the server's behavior.

[$ref]: http://json-schema.org/latest/json-schema-core.html#rfc.section.7.2.3

## Next steps

* Read [Validating JSON Schemas with an RSpec Matcher][blog].
* Add [json\_matchers][install] to your project.
* [Help make json\_matchers great][contributing]!

[blog]: https://thoughtbot.com/blog/validating-json-schemas-with-an-rspec-matcher
[install]: https://github.com/thoughtbot/json_matchers#installation
[contributing]: https://github.com/thoughtbot/json_matchers/blob/master/CONTRIBUTING.md
