base on Rack middleware to validate content # Probity
Even Rails can't be trusted not to produce malformed xml sometimes. Add this Rack middleware to the stack while you run your tests and it will monitor the responses you send, infer the appropriate validations based on content type, and raise if they fail.
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'probity', git: '
[email protected]:mdsol/probity.git'
```
And then execute:
$ bundle
Or install it yourself as:
$ gem install probity
## Usage
Probity should only be included in your middleware stack when running in test/development mode. If you're using a conventional Rails app, for example, you could include it like so:
```ruby
# in config/environments/test.rb
config.middleware.use(Probity::ResponseValidatorMiddleware)
```
Now, run your test scripts! If your app produces malformed responses, Probity will turn a passing test into a failing one by raising a parsing error in your server. Depending on your particular test setup, this might manifest in different ways, but as long as your tests are at all meaningful they at least shouldn't pass.
## Configuration
By default, Probity will validate the `application/xml` and `application/json` content types, and **raise** if it sees anything else. If you're serving something other than those two, such as html, you'll probably want to do
```ruby
middleware.use(Probity::ResponseValidatorMiddleware, missing_validator: :warn)
#or
middleware.use(Probity::ResponseValidatorMiddleware, missing_validator: :ignore)
```
A blank body is not valid JSON or XML. If you would like to special-case this as an allowable response, use
```ruby
middleware.use(Probity::ResponseValidatorMiddleware, blank_body: :ignore)
```
You can add validators for your content types with code like this:
```ruby
Probity.validators['application/hal+json'] = Proc.new do |body|
raise unless Halidator.new(body).valid?
end
```
You can also override the default validators the same way:
```ruby
Probity.validators['application/xml'] = # Object that responds to .call(str)
```
## Validators
The XML validator uses [Nokogiri](http://www.nokogiri.org/) in Strict Mode, while the JSON validator uses Ruby's built-in `JSON.parse`. Pull requests are welcome for more content types.
## Contributing
1. Fork it ( https://github.com/[my-github-username]/probity/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request
", Assign "at most 3 tags" to the expected json: {"id":"8951","tags":[]} "only from the tags list I provide: [{"id":77,"name":"3d"},{"id":89,"name":"agent"},{"id":17,"name":"ai"},{"id":54,"name":"algorithm"},{"id":24,"name":"api"},{"id":44,"name":"authentication"},{"id":3,"name":"aws"},{"id":27,"name":"backend"},{"id":60,"name":"benchmark"},{"id":72,"name":"best-practices"},{"id":39,"name":"bitcoin"},{"id":37,"name":"blockchain"},{"id":1,"name":"blog"},{"id":45,"name":"bundler"},{"id":58,"name":"cache"},{"id":21,"name":"chat"},{"id":49,"name":"cicd"},{"id":4,"name":"cli"},{"id":64,"name":"cloud-native"},{"id":48,"name":"cms"},{"id":61,"name":"compiler"},{"id":68,"name":"containerization"},{"id":92,"name":"crm"},{"id":34,"name":"data"},{"id":47,"name":"database"},{"id":8,"name":"declarative-gui "},{"id":9,"name":"deploy-tool"},{"id":53,"name":"desktop-app"},{"id":6,"name":"dev-exp-lib"},{"id":59,"name":"dev-tool"},{"id":13,"name":"ecommerce"},{"id":26,"name":"editor"},{"id":66,"name":"emulator"},{"id":62,"name":"filesystem"},{"id":80,"name":"finance"},{"id":15,"name":"firmware"},{"id":73,"name":"for-fun"},{"id":2,"name":"framework"},{"id":11,"name":"frontend"},{"id":22,"name":"game"},{"id":81,"name":"game-engine "},{"id":23,"name":"graphql"},{"id":84,"name":"gui"},{"id":91,"name":"http"},{"id":5,"name":"http-client"},{"id":51,"name":"iac"},{"id":30,"name":"ide"},{"id":78,"name":"iot"},{"id":40,"name":"json"},{"id":83,"name":"julian"},{"id":38,"name":"k8s"},{"id":31,"name":"language"},{"id":10,"name":"learning-resource"},{"id":33,"name":"lib"},{"id":41,"name":"linter"},{"id":28,"name":"lms"},{"id":16,"name":"logging"},{"id":76,"name":"low-code"},{"id":90,"name":"message-queue"},{"id":42,"name":"mobile-app"},{"id":18,"name":"monitoring"},{"id":36,"name":"networking"},{"id":7,"name":"node-version"},{"id":55,"name":"nosql"},{"id":57,"name":"observability"},{"id":46,"name":"orm"},{"id":52,"name":"os"},{"id":14,"name":"parser"},{"id":74,"name":"react"},{"id":82,"name":"real-time"},{"id":56,"name":"robot"},{"id":65,"name":"runtime"},{"id":32,"name":"sdk"},{"id":71,"name":"search"},{"id":63,"name":"secrets"},{"id":25,"name":"security"},{"id":85,"name":"server"},{"id":86,"name":"serverless"},{"id":70,"name":"storage"},{"id":75,"name":"system-design"},{"id":79,"name":"terminal"},{"id":29,"name":"testing"},{"id":12,"name":"ui"},{"id":50,"name":"ux"},{"id":88,"name":"video"},{"id":20,"name":"web-app"},{"id":35,"name":"web-server"},{"id":43,"name":"webassembly"},{"id":69,"name":"workflow"},{"id":87,"name":"yaml"}]" returns me the "expected json"