rails-param-validation 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.gitlab-ci.yml +34 -0
  4. data/Gemfile +8 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +63 -0
  7. data/Rakefile +6 -0
  8. data/bin/.keep +0 -0
  9. data/docs/_config.yml +3 -0
  10. data/docs/annotations.md +62 -0
  11. data/docs/getting-started.md +32 -0
  12. data/docs/image/error-screenshot.png +0 -0
  13. data/docs/index.md +61 -0
  14. data/docs/main-idea.md +72 -0
  15. data/docs/openapi.md +39 -0
  16. data/docs/type-definition.md +178 -0
  17. data/lib/rails-param-validation/errors/missing_parameter_annotation.rb +9 -0
  18. data/lib/rails-param-validation/errors/no_matching_factory.rb +9 -0
  19. data/lib/rails-param-validation/errors/param_validation_failed_error.rb +12 -0
  20. data/lib/rails-param-validation/errors/type_not_found.rb +9 -0
  21. data/lib/rails-param-validation/rails/action_definition.rb +66 -0
  22. data/lib/rails-param-validation/rails/annotation_manager.rb +40 -0
  23. data/lib/rails-param-validation/rails/config.rb +48 -0
  24. data/lib/rails-param-validation/rails/extensions/annotation_extension.rb +95 -0
  25. data/lib/rails-param-validation/rails/extensions/custom_type_extension.rb +13 -0
  26. data/lib/rails-param-validation/rails/extensions/error.template.html.erb +86 -0
  27. data/lib/rails-param-validation/rails/extensions/validation_extension.rb +105 -0
  28. data/lib/rails-param-validation/rails/helper.rb +9 -0
  29. data/lib/rails-param-validation/rails/openapi/openapi.rb +128 -0
  30. data/lib/rails-param-validation/rails/openapi/routing_helper.rb +40 -0
  31. data/lib/rails-param-validation/rails/rails.rb +31 -0
  32. data/lib/rails-param-validation/rails/tasks/openapi.rake +32 -0
  33. data/lib/rails-param-validation/types/types.rb +100 -0
  34. data/lib/rails-param-validation/validator.rb +51 -0
  35. data/lib/rails-param-validation/validator_factory.rb +37 -0
  36. data/lib/rails-param-validation/validators/alternatives.rb +42 -0
  37. data/lib/rails-param-validation/validators/array.rb +49 -0
  38. data/lib/rails-param-validation/validators/boolean.rb +38 -0
  39. data/lib/rails-param-validation/validators/constant.rb +38 -0
  40. data/lib/rails-param-validation/validators/custom_type.rb +28 -0
  41. data/lib/rails-param-validation/validators/date.rb +39 -0
  42. data/lib/rails-param-validation/validators/datetime.rb +39 -0
  43. data/lib/rails-param-validation/validators/float.rb +39 -0
  44. data/lib/rails-param-validation/validators/hash.rb +52 -0
  45. data/lib/rails-param-validation/validators/integer.rb +39 -0
  46. data/lib/rails-param-validation/validators/object.rb +63 -0
  47. data/lib/rails-param-validation/validators/optional.rb +44 -0
  48. data/lib/rails-param-validation/validators/regex.rb +37 -0
  49. data/lib/rails-param-validation/validators/string.rb +31 -0
  50. data/lib/rails-param-validation/validators/uuid.rb +39 -0
  51. data/lib/rails-param-validation/version.rb +3 -0
  52. data/lib/rails-param-validation.rb +42 -0
  53. data/rails-param-validation.gemspec +33 -0
  54. metadata +100 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 78a64263517a4c6d2d0c0e649cc7a3e4708f4ed1abb96beffb8a52b2acc2f8a0
4
+ data.tar.gz: dfd6039f8ce21dd31c7f96a93daf9c6b10a490107a4f96be6ceaa33f26e1a7fd
5
+ SHA512:
6
+ metadata.gz: c4862edac9546192dddce87b4d0e846443611db3426ad4b91eb5c3827ddbc72cc7e283dfef1f3ed624ee18fcce52db21a4aa04b5ef359dcf85ea5f707dba5caf
7
+ data.tar.gz: d0606f8d37a4f2bf9e822c410779be3efbefec1e81c505179d3ecc26780202c0961e6f412bd1d4503a354d5b6c8395dd14ba6027f35840783574ad1a75bd642a
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ coverage
2
+ .idea
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,34 @@
1
+ test:2.3:
2
+ image: ruby:2.3
3
+ script:
4
+ - bundle install && rake spec
5
+
6
+ test:2.4:
7
+ image: ruby:2.4
8
+ script:
9
+ - bundle install && rake spec
10
+
11
+ test:2.5:
12
+ image: ruby:2.5
13
+ script:
14
+ - bundle install && rake spec
15
+
16
+ test:2.6:
17
+ image: ruby:2.6
18
+ script:
19
+ - bundle install && rake spec
20
+
21
+ test:2.7:
22
+ image: ruby:2.7
23
+ script:
24
+ - bundle install && rake spec
25
+
26
+ test:jruby9.2:
27
+ image: jruby:9.2
28
+ script:
29
+ - bundle install && rake spec
30
+
31
+ test:jruby9.1:
32
+ image: jruby:9.1
33
+ script:
34
+ - bundle install && rake spec
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rails-param-validation.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+ gem "rspec", "~> 3.0"
8
+ gem "simplecov"
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Oskar Kirmis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # RailsParamValidation
2
+
3
+ [![pipeline status](https://git.iftrue.de/okirmis/rails-param-validation/badges/master/pipeline.svg)](https://git.iftrue.de/okirmis/rails-param-validation/commits/master)
4
+
5
+ This gem provides parameter validation for Rails using a declarative parameter definition and makes the automatic validation of complex parameters very easy. It also supports an export of the definition as an OpenAPI document.
6
+
7
+ * [Why this gem?](./docs/main-idea.md)
8
+ * [Getting started](./docs/getting-started.md)
9
+ * [Annotations](./docs/annotations.md)
10
+ * [How to specify types](./docs/type-definition.md)
11
+ * [OpenAPI Export](./docs/openapi.md)
12
+
13
+ ## Quick Example
14
+
15
+ Let's take a look at a very simple example: a controller with a sample action, which gets a list of floats, rounds them to the nearest integer and returns it in a json encoded form.
16
+
17
+ ```ruby
18
+ class ExampleController
19
+ desc "Show the functionality of this gem"
20
+
21
+ action "Round float values" do
22
+ # Expect a parameter with the name "values" which contains an array of floats
23
+ query_param :values, ArrayType(Float), "Values to round"
24
+ # Document the response of http status 200, which is an array of integers
25
+ response 200, :success, ArrayType(Integer), "Rounded values response"
26
+ end
27
+ def sample_action
28
+ render json: params[:values].map(&:round)
29
+ end
30
+
31
+ # We assume GET /round to be mapped to this action
32
+ end
33
+ ```
34
+
35
+ Sending a valid request, the parameters are validated and casted correctly and we get the response one would expect:
36
+
37
+ ```
38
+ $ curl -H "Accept: application/json" "http://localhost:3000/round?values[]=1.5&values[]=2.0&values[]=-0.777"
39
+ [2,2,-1]
40
+ ```
41
+
42
+ When a request with invalid parameters is sent, we get an error response which also describes the error.
43
+
44
+ ```
45
+ $ curl -H "Accept: application/json" "http://localhost:3000/round?values[]=1.5&values[]=2.0&values[]=XYZ"
46
+ {"status":"fail","errors":[{"path":"values/2","message":"Expected a float"}]}
47
+ ```
48
+
49
+ ## Installation
50
+
51
+ Add this line to your application's Gemfile:
52
+
53
+ ```ruby
54
+ gem 'rails-param-validation'
55
+ ```
56
+
57
+ And then execute:
58
+
59
+ $ bundle install
60
+
61
+ Or install it yourself as:
62
+
63
+ $ gem install rails-param-validator
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/.keep ADDED
File without changes
data/docs/_config.yml ADDED
@@ -0,0 +1,3 @@
1
+ theme: jekyll-theme-slate
2
+ title: Rails Parameter Validation
3
+ description: Declarative, easy-to-use parameter validations and OpenAPI export
@@ -0,0 +1,62 @@
1
+ # Annotations
2
+
3
+ ## Controller annotations
4
+
5
+ **desc**
6
+
7
+ Define a description for the controller that is later used in the OpenAPI export.
8
+
9
+ ## Action annotations
10
+
11
+ All of the following annotations have to be placed **above** the action definition and must be used within an `action` block like this:
12
+
13
+ ```ruby
14
+ action "Return a random number" do
15
+ query_param :min, Optional(Float, 0.0), 'Minimum value'
16
+ query_param :max, Optional(Float, 1.0), 'Maximum value'
17
+
18
+ response 200, { value: Float }, 'Random value response'
19
+ end
20
+ def random_value
21
+ render json: { value: Random.rand(params[:min]..params[:max]) }
22
+ end
23
+ ```
24
+
25
+ **query_param**
26
+
27
+ Parameter passed via query string, e.g. `http://localhost/my_action?parameter=value`. The first value is the parameter name (which must be a symbol), the second is the [type definition](./docs/type-definition.md). The last (optional) parameter to this call is the description.
28
+
29
+ **path_param**
30
+
31
+ Parameter passed as part of the actions route, e.g. `http://localhost/my_action/value` where the route definition is something like `get '/my_action/:parameter, to: 'my_controller#my_action'`. The first value is the parameter name (which must be a symbol), the second is the [type definition](./docs/type-definition.md). The last (optional) parameter to this call is the description.
32
+
33
+ **body_param**
34
+
35
+ Parameter as part of a JSON body in a POST/PUT/PATCH operation. The first value is the parameter name (which must be a symbol) as the JSON body must be a JSON object which has a key named like the parameter. The second parameter is the [type definition](./docs/type-definition.md). The last (optional) parameter to this call is the description.
36
+
37
+ Example body:
38
+
39
+ ```json
40
+ {
41
+ "min": 1.3,
42
+ "max": 3.7
43
+ }
44
+ ```
45
+
46
+ This body contains two parameters which have to be documented separately, e.g. like this:
47
+
48
+ ```ruby
49
+ action do
50
+ body_param :min, Optional(Float, 0.0), 'Minimum value'
51
+ body_param :max, Optional(Float, 1.0), 'Maximum value'
52
+ end
53
+ # ...
54
+ ```
55
+
56
+ **response**
57
+
58
+ The response annotation defines the possible responses the action can generate, where the first parameter is the HTTP status code, the second is the [type definition](./docs/type-definition.md). The last (optional) parameter to this call is the description.
59
+
60
+ **accept_all_params**
61
+
62
+ To disable parameter validation, an action can be annotated with the `accept_all_params` annotation.
@@ -0,0 +1,32 @@
1
+ # Getting started
2
+
3
+ To get started with this gem, first include it into your Rails application by adding it to your `Gemfile` ...
4
+
5
+ ```ruby
6
+ gem 'rails-param-validation'
7
+ ```
8
+
9
+ ... and running:
10
+ ```sh
11
+ $ bundle install
12
+ ```
13
+
14
+ Having included the gem, you can start using it right away, e.g. by annotating a controller class:
15
+
16
+ ```ruby
17
+ class ExampleController
18
+ desc "Show the functionality of this gem"
19
+
20
+ action "Round float values" do
21
+ # Expect a parameter with the name "values" which contains an array of floats
22
+ query_param :values, ArrayType(Float), "Values to round"
23
+ # Document the response of http status 200, which is an array of integers
24
+ response 200, ArrayType(Integer), "Rounded values response"
25
+ end
26
+ def sample_action
27
+ render json: params[:values].map(&:round)
28
+ end
29
+ end
30
+ ```
31
+
32
+ The parameters for `sample_action` will be automatically checked against our definition on every request.
Binary file
data/docs/index.md ADDED
@@ -0,0 +1,61 @@
1
+ [![pipeline status](https://git.iftrue.de/okirmis/rails-param-validation/badges/master/pipeline.svg)](https://git.iftrue.de/okirmis/rails-param-validation/commits/master)
2
+
3
+ This gem provides parameter validation for Rails using a declarative parameter definition and makes the automatic validation of complex parameters very easy. It also supports an export of the definition as an OpenAPI document.
4
+
5
+ * [Why this gem?](./main-idea.md)
6
+ * [Getting started](./getting-started.md)
7
+ * [Annotations](./annotations.md)
8
+ * [How to specify types](./type-definition.md)
9
+ * [OpenAPI Export](./openapi.md)
10
+
11
+ ## Quick Example
12
+
13
+ Let's take a look at a very simple example: a controller with a sample action, which gets a list of floats, rounds them to the nearest integer and returns it in a json encoded form.
14
+
15
+ ```ruby
16
+ class ExampleController
17
+ desc "Show the functionality of this gem"
18
+
19
+ action "Round float values" do
20
+ # Expect a parameter with the name "values" which contains an array of floats
21
+ query_param :values, ArrayType(Float), "Values to round"
22
+ # Document the response of http status 200, which is an array of integers
23
+ response 200, :success, ArrayType(Integer), "Rounded values response"
24
+ end
25
+ def sample_action
26
+ render json: params[:values].map(&:round)
27
+ end
28
+
29
+ # We assume GET /round to be mapped to this action
30
+ end
31
+ ```
32
+
33
+ Sending a valid request, the parameters are validated and casted correctly and we get the response one would expect:
34
+
35
+ ```
36
+ $ curl -H "Accept: application/json" "http://localhost:3000/round?values[]=1.5&values[]=2.0&values[]=-0.777"
37
+ [2,2,-1]
38
+ ```
39
+
40
+ When a request with invalid parameters is sent, we get an error response which also describes the error.
41
+
42
+ ```
43
+ $ curl -H "Accept: application/json" "http://localhost:3000/round?values[]=1.5&values[]=2.0&values[]=XYZ"
44
+ {"status":"fail","errors":[{"path":"values/2","message":"Expected a float"}]}
45
+ ```
46
+
47
+ ## Installation
48
+
49
+ Add this line to your application's Gemfile:
50
+
51
+ ```ruby
52
+ gem 'rails-param-validation'
53
+ ```
54
+
55
+ And then execute:
56
+
57
+ $ bundle install
58
+
59
+ Or install it yourself as:
60
+
61
+ $ gem install rails-param-validator
data/docs/main-idea.md ADDED
@@ -0,0 +1,72 @@
1
+ # What problem does this gem try to solve?
2
+
3
+ Let's say we expect a JSON body that contains an array of objects which contain - besides others - an array of timestamps (date-times), e.g.:
4
+
5
+ ```json
6
+ [
7
+ {
8
+ "type": "maxima",
9
+ "timestamps": [
10
+ "2020-03-01T16:49:50+01:00",
11
+ "2020-02-28T16:50:22+01:00"
12
+ ]
13
+ },
14
+ {
15
+ "type": "minima",
16
+ "timestamps": [
17
+ "2020-02-29T16:51:12+01:00"
18
+ ]
19
+ }
20
+ ]
21
+ ```
22
+
23
+ Validating such a request requires a lot of code, involving a lot of `is_a?` statements etc. This is both - annoying from a developer perspective and error prone.
24
+
25
+ # How does this gem solve this issue?
26
+
27
+ This gem introduces a simple way to annotate controller actions with declarative parameter type annotations. For the example shown above, it would look like this:
28
+
29
+ ```ruby
30
+ action do
31
+ body_param :data, ArrayType({ type: [:minima, :maxima], timestamps: ArrayType(DateTime) })
32
+ end
33
+ def sample_action
34
+ render json: { status: :ok }
35
+ end
36
+ ```
37
+
38
+ This will check the body parameter `:data` and will convert all string representing the timestamps automatically to `DateTime` objects. If the request does not match the definition, it will render either a JSON or HTML response which nicely describes what parameter does not match and why, e.g.:
39
+
40
+ ```sh
41
+ $ curl -X POST -d \
42
+ '{"data": [{"type": "maxima","timestamps": ["2020-03-01T16:49:50+01:00","2020-02-28T16:50:22+01:00"]},{"type": "minima","timestamps": ["2020-02-29T16:51:12+01:00"]}]}' \
43
+ -H "Content-Type: application/json" \
44
+ -H "Accept: application/json" \
45
+ http://localhost:3000/sample_action
46
+ ```
47
+
48
+ returns `{"status": "ok"}`. But if we send an invalid value, we get a different response:
49
+
50
+ ```sh
51
+ $ curl -X POST -d \
52
+ '{"data": [{"type": "maxima","timestamps": ["abc","2020-02-28T16:50:22+01:00"]},{"type": "minima","timestamps": ["2020-02-29T16:51:12+01:00"]}]}' \
53
+ -H "Content-Type: application/json" \
54
+ -H "Accept: application/json" \
55
+ http://localhost:3000/home
56
+ ```
57
+ the server will answer:
58
+ ```json
59
+ {
60
+ "errors": [
61
+ {
62
+ "message": "Expected a date-time",
63
+ "path": "data/0/timestamps/0"
64
+ }
65
+ ],
66
+ "status": "fail"
67
+ }
68
+ ```
69
+
70
+ If we do not request `application/json`, we get an HTML response which looks like this:
71
+
72
+ ![alt text](./image/error-screenshot.png)
data/docs/openapi.md ADDED
@@ -0,0 +1,39 @@
1
+ # OpenAPI Export
2
+
3
+ When annotating the controller actions with parameter and response types, you get an [OpenAPI](https://www.openapis.org/) 3.0 export for free.
4
+
5
+ ## Export task
6
+
7
+ When included in a Rails application, this gem automatically adds a rake task with the name `openapi:export`. It exports the OpenAPI definition in YAML format to the applications root directory (filename: `openapi.yaml`).
8
+
9
+ ```sh
10
+ $ rake openapi:export
11
+ Writing <your_apps_dir>/openapi.yaml... done.
12
+ ```
13
+
14
+ ## Configuration
15
+
16
+ An OpenAPI document contains some meta data about the API. By default, the following default values are assumed:
17
+
18
+ | Property | Default | Description |
19
+ |---|---|---|
20
+ | `info.version` | `1.0` | API version |
21
+ | `info.title` | Application module name | Name or title of the API |
22
+ | `info.description` | Application module name + `" application"` | The API's brief description |
23
+ | `info.url` | `http://localhost:3000` | The base URL of the API, all specified paths are relative to that |
24
+
25
+ These properties can be configured, e.g. in the `application.rb`, using:
26
+
27
+ ```ruby
28
+ # ...
29
+ module MyApp
30
+ class Application < Rails::Application
31
+ RailsParamValidation.openapi.title = "My App's API"
32
+ RailsParamValidation.openapi.description = 'This is an awesome API to interact with my App'
33
+ RailsParamValidation.openapi.version = '2.0'
34
+ RailsParamValidation.openapi.url = 'https://api.myapp.com'
35
+
36
+ # ...
37
+ end
38
+ end
39
+ ```
@@ -0,0 +1,178 @@
1
+ # Type definition
2
+
3
+ This gem provides declarative type checking. This part of the documentation will explain, how types are declared. Some types support inner types (e.g. arrays), so the definition can be nested.
4
+
5
+ * [Constants](#type-constant)
6
+ * [Alternatives](#type-alternatives)
7
+ * [String](#type-string)
8
+ * [Integer](#type-integer)
9
+ * [Float](#type-float)
10
+ * [Boolean](#type-boolean)
11
+ * [UUID (v4)](#type-uuid)
12
+ * [RegEx Pattern](#type-regex)
13
+ * [Date & DateTime](#type-date-time)
14
+ * [Optional Values](#type-optional)
15
+ * [Array](#type-array)
16
+ * [Object](#type-object)
17
+ * [Hash](#type-hash)
18
+
19
+ <a name="type-constant"></a>
20
+ ### Constants
21
+
22
+ Accepts exactly the defined value, if its string representation is identical. This is especially useful in combination with alternatives.
23
+
24
+ Example:
25
+ ```ruby
26
+ query_param :accept_terms, true, "The user's consent to the terms of service"
27
+ ```
28
+
29
+ This would accept the values `"true"` or `true` and reject all others.
30
+
31
+ <a name="type-alternatives"></a>
32
+ ### Alternatives
33
+
34
+ Accepts values that match at least one of the definitions.
35
+
36
+ Example:
37
+ ```ruby
38
+ query_param :gender, [:male, :female, :other], "User's gender"
39
+ query_param :date_or_timestamp, [DateTime, Integer], "Modification date"
40
+ ```
41
+
42
+ The first example will match any of the values `"male"`, `"female"`, `"other"`.
43
+
44
+ The second example will match any iso formatted date time string or a timestamp (e.g. seconds since 1970-01-01).
45
+
46
+ <a name="type-string"></a>
47
+ ### String
48
+
49
+ Accept any string or type which can be converted to a string, namely: `String`, `Symbol`, `Numeric`, `Boolean`. The value will be automatically converted to a string.
50
+
51
+ Example:
52
+ ```ruby
53
+ query_param :name, String, "The user's name"
54
+ ```
55
+
56
+ <a name="type-integer"></a>
57
+ ### Integer
58
+
59
+ Accepts an integer or a string which represents an integer. If a string is passed, which cannot be parsed to an integer, the value is rejected. If the string can be converted to an integer, this is done in any case, if the value is accepted, an integer is returned.
60
+
61
+ Example:
62
+ ```ruby
63
+ query_param :year_of_birth, Integer, "The year, the user was born"
64
+ ```
65
+
66
+ In this case, `params[:year_of_birth].is_a? Integer` returns `true`.
67
+
68
+
69
+ <a name="type-float"></a>
70
+ ### Float
71
+
72
+ Accepts an integer, float or a string which represents a float. If a string is passed, which cannot be parsed to a float, the value is rejected. If the string can be converted to a float, this is done in any case, if the value is accepted, a float is returned. Also integers are converted to floats.
73
+
74
+ Example:
75
+ ```ruby
76
+ query_param :radius, Float, "Search radius"
77
+ ```
78
+
79
+ In this case, `params[:radius].is_a? Float` returns `true`.
80
+
81
+
82
+ <a name="type-boolean"></a>
83
+ ### Boolean
84
+
85
+ Accepts a float or a string, which represents a boolean (either `"true"` or `"false"`).
86
+
87
+ Example:
88
+ ```ruby
89
+ query_param :radius, Float, "Search radius"
90
+ ```
91
+
92
+ In this case, `params[:radius].is_a? Float` returns `true`.
93
+
94
+
95
+ <a name="type-uuid"></a>
96
+ ### Uuid
97
+
98
+ Accepts a string or symbol in uuid v4 format. If the string does not match the correct format, it is rejected.
99
+
100
+ Example:
101
+ ```ruby
102
+ query_param :user_id, Uuid, "The user's ID"
103
+ ```
104
+
105
+
106
+ <a name="type-regex"></a>
107
+ ### Regex
108
+
109
+ Accepts a string or symbol, that matches a given `RegExp` pattern.
110
+
111
+ Example:
112
+ ```ruby
113
+ query_param :slug, /[a-z][a-z_0-9]+/, "Slug for the article as used in the URL"
114
+ ```
115
+
116
+ <a name="type-date-time"></a>
117
+ ### Date & DateTime
118
+
119
+ Accept strings that represent valid dates or datetimes, e.g. `"2020-02-28"` (for dates) or `"2020-02-28T12:13:14+01:00"`.
120
+
121
+ Example:
122
+ ```ruby
123
+ query_param :expiration_date, Date, "Date until the article will be available"
124
+ ```
125
+
126
+ <a name="type-optional"></a>
127
+ ### Optional Value
128
+
129
+ If a value is not passed, define a default value which is returned in this case. It can be used with any inner type. If the value is passed, it is validated. If it does not match, the value is rejected. If it is not specified at all, the default value is used.
130
+
131
+ Example:
132
+ ```ruby
133
+ query_param :public, Optional(Boolean, false), "Will the article be publicly available"
134
+ query_param :expiration_date, Optional(Date, -> { Date.today + 14.days }), "Date until the article will be available"
135
+ ```
136
+
137
+ In the first example, the constant is `false` is returned if no value is specified.
138
+
139
+ In the second example, the `Proc` is evaluated whenever no data is passed for the parameter.
140
+
141
+ <a name="type-array"></a>
142
+ ### Array
143
+
144
+ Accepts a list of values. Every value of the entry has to match the inner type.
145
+
146
+ Example:
147
+ ```ruby
148
+ body_param :tags, ArrayType(String), "Tags to assign to the article"
149
+ ```
150
+
151
+ This can be combined with any inner type.
152
+
153
+ <a name="type-object"></a>
154
+ ### Object
155
+
156
+ Accept an object with a defined list of keys. All properties have to match there definition.
157
+
158
+ Example:
159
+ ```ruby
160
+ body_param :article, {
161
+ title: String,
162
+ body: String,
163
+ expiration_date: Optional(Date, Date.today + 14.days),
164
+ tags: ArrayType(String)
165
+ }, "Article to store"
166
+ ```
167
+
168
+ <a name="type-hash"></a>
169
+ ### Hash
170
+
171
+ Accept an object with arbitrary keys. The values and the keys can be validated against a type definition.
172
+
173
+ Example:
174
+ ```ruby
175
+ body_param :settings, HashType(DateTime, /key_[a-z]/), "User settings"
176
+ ```
177
+
178
+ In this case, all keys have to start with `key_` and the rest may only consist of lower case letters. The values have to be date times.
@@ -0,0 +1,9 @@
1
+ module RailsParamValidation
2
+
3
+ class MissingParameterAnnotation < StandardError
4
+ def initialize
5
+ super "Missing parameter annotation for controller action"
6
+ end
7
+ end
8
+
9
+ end
@@ -0,0 +1,9 @@
1
+ module RailsParamValidation
2
+
3
+ class NoMatchingFactory < StandardError
4
+ def initialize(schema)
5
+ super "No matching factory found for schema: #{schema.inspect}"
6
+ end
7
+ end
8
+
9
+ end
@@ -0,0 +1,12 @@
1
+ module RailsParamValidation
2
+
3
+ class ParamValidationFailedError < StandardError
4
+ attr_reader :result
5
+
6
+ def initialize(result)
7
+ @result = result
8
+ super "Parameter validation has failed: #{result.error_messages.join ", "}"
9
+ end
10
+ end
11
+
12
+ end
@@ -0,0 +1,9 @@
1
+ module RailsParamValidation
2
+
3
+ class TypeNotFound < StandardError
4
+ def initialize(type)
5
+ super("The following type was not found: #{type}")
6
+ end
7
+ end
8
+
9
+ end