thoughtworks/pacto — pull request #68 by maxlinc (2013-12-10 05:02:38+00:00)
Title: Use Middleware and Validators

Sorry about the big PR. That's what happens when no one will pair w/ me for a month, though :ghost:

This is basically a big refactor, mostly in preparation for request validation, better request/response header normalization, and experiments with alternative stub data providers. The only behavior I changed was dropping `response#validate` (which was not being used outside contract#validate in any tests or examples). I did spot lots of behavior I'd like to simplify, but that's for later ;)

I've been thinking for a while we may be able to clean up Pacto and make it more extensible by using a Middleware pattern. This PR is an attempt to do that using the [middleware gem](https://github.com/mitchellh/middleware). Middleware might look a little odd at first, and I was struggling a bit trying to figure out how to make it testable, but I think it helps a lot.

Immediate benefits:
- `response#validate` method, which was marked as a rubocop method length violation, is gone. `response_spec.rb` is greatly simplified.
- The logic that was in `response#validate` is split into three middlewares: ResponseStatusValidator, ResponseHeaderValidator, and ResponseBodyValidator. It's a lot easier to read the tests and understand what each one is doing.
- Choosing active validations based on `opts[:body_only]` is now more readable (it just changes the middleware chain).

Near-term benefits of validation middleware:
- This makes it much easier to add new validations. I did this mainly in preparation for a RequestBodyValidator.
- The middleware can easily be exposed, to let users customize which checks they want, add their own checks, or replace our implementation.

Other potential uses for middleware:
- Middleware can be used to normalize the request or response objects, eliminating the need for repeated calls to normalize_keys.
- Could eliminate the need for preprocessor, postprocessor, and callback configuration.
- Could be used to configure an alternate stub data provider (instead of json-generator)
- Could help when using Pacto as a server (i.e. embedding it as a reverse-proxy), by filtering connection specific info that shouldn't be forwarded by the proxy (i.e. the Connection or Transfer-Encoding headers)