{"id":28092563,"url":"https://github.com/felipefava/request_params_validation","last_synced_at":"2025-09-08T14:43:27.185Z","repository":{"id":41871308,"uuid":"246167177","full_name":"felipefava/request_params_validation","owner":"felipefava","description":"Request parameters validations, type coercion and filtering for Rails params","archived":false,"fork":false,"pushed_at":"2022-04-25T14:34:33.000Z","size":109,"stargazers_count":21,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-24T23:03:43.919Z","etag":null,"topics":["coercion","documentation","filter","params","rails","requests","ruby","type-safety","validations"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/felipefava.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-09T23:56:24.000Z","updated_at":"2024-09-01T21:35:01.000Z","dependencies_parsed_at":"2022-08-11T19:50:35.557Z","dependency_job_id":null,"html_url":"https://github.com/felipefava/request_params_validation","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipefava%2Frequest_params_validation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipefava%2Frequest_params_validation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipefava%2Frequest_params_validation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipefava%2Frequest_params_validation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/felipefava","download_url":"https://codeload.github.com/felipefava/request_params_validation/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253948512,"owners_count":21988962,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["coercion","documentation","filter","params","rails","requests","ruby","type-safety","validations"],"created_at":"2025-05-13T13:20:15.250Z","updated_at":"2025-05-13T13:20:15.934Z","avatar_url":"https://github.com/felipefava.png","language":"Ruby","readme":"# RequestParamsValidation\n_Request parameters validations, type coercion and filtering for Rails params_\n\n[![Gem Version](https://badge.fury.io/rb/request_params_validation.svg)](https://badge.fury.io/rb/request_params_validation)\n[![CircleCI](https://circleci.com/gh/felipefava/request_params_validation.svg?style=shield\u0026circle-token=a404cb4fd87e219299caeb36e1685ab75d335b84)](https://circleci.com/gh/felipefava/request_params_validation)\n[![Codacy Quality Badge](https://api.codacy.com/project/badge/Grade/6ed6582228bd429a94dfabaa82071455)](https://www.codacy.com/manual/felipefava/request_params_validation?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=felipefava/request_params_validation\u0026amp;utm_campaign=Badge_Grade)\n\n## Introduction\nValidates the request params outside your controller logic in order to get a clean nice code, and\nalso working as code documentation for the operations. It ensure that all endpoints input data is\nright and well formed before it even hits your controller action.\n\nThis gem allows you to validate the presence, type, length, format, value and more, of your request\nparameters. It also coerces the params to the specified type and filter the hash to only those you\nexpect to receive.\n\nIt is designed to work for any expected params structure, from a simple hash to a complex one with\ndeeply nested data. It pretends to be a flexible library where you can change and customize\nseveral options.\n\nIt is intended for REST-like Ruby on Rails APIs.\n\n## Installation\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'request_params_validation'\n```\n\nAnd then execute `bundle install` from your shell.\n\nOr, if you want to install it manually, run:\n```ruby\ngem install request_params_validation\n```\n\n## Usage\nTo start using the gem without setting up any configuration is as simple as adding a\n`before_action` with the helper method `validate_params!` and define your expected request\nparameters for your resources actions.\n\nThe approach of this gem is to have, for each controller file, a definition file. This definitions\nfiles is where it should be all data related to the endpoints of your API. This works as code\ndocumentation and allows to keep controllers code clean, ensuring that `params` object will\nalways have the parameters you suppose to receive.\n\nThe default path for the definitions files is `app/definitions`, and their names should be the same\nas their respective controller's name, but ending with the suffix `_definition`. They should also\nrespect the folder structure of the controllers folder. Please see the following project structure\nto clarify the idea:\n\n```\n.\n├── app\n│   ├── controllers\n│   │   ├── commerces\n|   |   |   └── branches_controller.rb\n|   |   |\n|   |   ├── transactions_controller.rb\n│   │   └── users_controller.rb\n|   |\n│   ├── definitions\n│   │   ├── commerces\n|   |   |   └── branches_definition.rb\n|   |   |\n|   |   ├── transactions_definition.rb\n│   │   └── users_definition.rb\n│   └── ...\n|\n└── ...\n```\n\nThis gem comes with a set of configurable options allowing you to customize it to your needs.\nFor example, you can change the default helper method `validate_params!` for whatever name you\nwant. You can also change the default path folder for the definitions `app/definitions` and even\nthe suffix `_definition` of the file names. [Here](#configuration) you can see all\nglobals configuration options\n\n### Example\nAdd the `before_action` callback for all actions:\n\n```ruby\n# app/controllers/application_controller.rb\n\nclass ApplicationController \u003c ActionController::Base\n  before_action :validate_params!\nend\n```\n\nImagine we have the following resource and we want to define the params for the action `create`\nand `notify`:\n\n```ruby\n# app/controllers/users_controller.rb\n\nclass UsersController \u003c ApplicationController\n  def create\n    params # will have only the defined parameters\n  end\n\n  def notify\n    params # will have only the defined parameters\n  end\n\n  def another_action\n    params # will have whatever the user sends\n  end\nend\n```\n\nThen, we will need to create the definition for the `users` resource:\n\n```ruby\n# app/definitions/users_definition.rb\n\nRequestParamsValidation.define do\n  action :create do\n    request do\n      required :user, type: :hash do\n        required :first_name, type: :string\n        required :last_name, type: :string\n        required :emails, type: :array, elements: :email\n        required :birth_date,\n                 type: :datetime,\n                 validate: lambda { |value| value \u003c= 18.years.ago.to_date }\n      end\n    end\n  end\n\n  action :notify do\n    request do\n      required :user_id, type: :integer\n      required :message, type: :string, length: { min: 10, max: 250 }\n      optional :by, inclusion: %w(email text_msg push), default: :email\n    end\n  end\nend\n```\n\nThe above definition is just a silly example, but is good enough to explain some important things.\n\nThe first thing to say is, as we already mentioned, that each controller file matches with a\ndefinition file with the same name and path of it, as you can see in the first line of the example\nabove. Be aware that if the definition file doesn't exist for a controller, then the gem will not\nvalidate any param, unless you change this behavior with the global configuration option\n`config.on_definition_not_found`. [Here](#configuration) you can see all globals\nconfiguration options.\n\nAs you might notice, the method `RequestParamsValidation.define` allow you to define a\nresource/controller. Notice that the resource you are defining is given by the current\ndefinition file path/name. After defining the resource, you can continue defining the\nactions for that resource with the `action` method. Then, for each action you can define the\nrequest using the `request` method, and there is where you will define the params validations\nfor the current resource/action. You could think that the `request` step is not strictly\nnecessary, because we could just defined the params validations inside de action block. However,\nit will have more sense in the future, when more extra options be added.\n\nFor defining required parameters we use the `required` method, otherwise\nwe have the `optional` method. This two methods accept 2 arguments and a block. The first argument\nis the only one required, and is the name or key of the parameter. The second argument is an\noptions hash for specifing the extra validations, and the block is for defining nested params.\n\nIn the following section we will see all the options validations in-depth look.\n\n## Validations \u0026 Options\nNone of the below options are required, so they can be omitted if you don't need to use them.\n\n### Presence\nIf a parameter is required, then you should use the `required` method on the definition of the\nparam. Otherwise use the `optional` method. For default, required parameters don't accept blank\nvalues, if you would like to allow them for that parameter, you can use the option `allow_blank`\n\n```ruby\nrequest do\n  required :key_1\n  required :key_2, allow_blank: true\n  optional :key_3\nend\n```\n\n### Types\nThe `type` option specified the type of the parameter. The supported types are:\n\n1.  hash\n2.  array\n3.  string\n4.  integer\n5.  decimal\n6.  boolean\n7.  date\n8.  datetime\n9.  email\n\nSo if this option is present, the gem will validate that the value of the parameter matches with\nthe specified type. And if it does, it will convert the value to the right type. This means that\nif a parameter should be an `integer`, a valid string integer like `\"100\"` will be converter to\n`100`. The same applies to the other types.\n\nIf you want to add your own types, you can extend the supported types with the global\nconfiguration option `extend.types`. See [here](#configuration) all globals\nconfiguration options.\n\n```ruby\nrequest do\n  required :key_1, type: :boolean\n  required :key_2, type: :decimal\n  # ...\nend\n```\n\nLet's see each of the types now.\n\n#### Hash type\nWhen defining a hash parameter, you will need to pass a block for specifing the nested object.\nIf no block is passed, the gem will only check that the value of the parameter be a valid hash\nobject, without validating the content of it.\n\n```ruby\nrequest do\n  # Allows any keys and values for the hash\n  required :key_1, type: :hash\n\n  # Only allows the keys nested_key_1 and nested_key_2\n  required :key_2, type: :hash do\n    required :nested_key_1, type: :string\n    required :nested_key_2, type: :integer\n  end\nend\n```\n\n#### Array type\nIf you define an array parameter, the gem will only check the value to be a valid array, allowing\n the elements of the array to be anything. If you also want to validate the elements, you can use\n the option `elements`.\n\nThe value for this option can be a type or a hash. `elements: :integer` is equivalent to\n`elements: { type: :integer }`.\n\nThe second way is useful when you  want to validate other things of the elements than just the\ntype. The option `elements` accepts all validations options.\n\n```ruby\nrequest do\n  # Allows any value for the elements of the array\n  required :key_1, type: :array\n\n  # Only allows decimals with a value less than 1_000 for the elements of the array\n  required :key_2, type: :array, elements: { type: :decimal, value: { max: 1_000 } }\n\n  # Only allows objects with a required key 'nested_key' of type 'email' for the\n  # elements of the array\n  required :key_3, type: :array, elements: :hash do\n    required :nested_key, type: :email\n  end\nend\n```\n\n#### String type\nAny value is a valid string.\n\n#### Integer type\nAccepts only valid integers like `5` or `\"5\"`.\n\n#### Decimal type\nAccepts only valid decimals like `5` or `\"1.5\"` or `10.45`. With decimals parameters you can use\nthe option `precision`. Go [here](#precision) for more details about this option.\n\n#### Boolean type\nAccepts only valid boolean values. The default valid boolean values are:\n\n```ruby\n[true, false, 'true', 'false']\n```\n\nIf you need to add more values for the boolean type, for example  `['yes', 'no', 1, 0, 't', 'f']`,\nyou can extend the `true values` and the `false values` independently, with the global\nconfiguration options `extend.boolean_true_values` and `extend.boolean_false_values` respectively.\nSee [here](#configuration) all globals configuration options.\n\n#### Date type\nDate type accepts only valid dates. This means that values like `'04/10/1995'` are valids, and\nwill be converter to a Date object like  `Wed, 04 Oct 1995`.\n\nHowever, they are cases when you only want to accept a specific format for a date, like\n`\"%Y-%m-%e\"`. In this cases you have two options.\n\n1.  Use the global configuration option `format.date`, so all date types must have the specified\n    format through all the requests. See [here](#configuration) all globals configuration\n    options.\n\n2.  Specify the option `format: \"%Y-%m-%e\"` locally.\n\nYou can perfectly use both approaches, but the second one will locally override the first one on\nthat parameter validation.\n\nNotice that if no format is specified, the date will be validated using the ruby `Date.parse`\nmethod.\n\n```ruby\nrequest do\n  required :key_1, type: :date\n  required :key_2, type: :date, format: '%Y-%m-%e'\nend\n```\n\n#### Datetime type\nSame as `date` type but for `datetime`.\n\n#### Email type\nAccepts only valid emails like `john.doe@mail.com`. It's just a helper for a string type with\nan email regexp format.\n\n### Inclusion\nThe `inclusion` option is for validating that the param value is included in a given array.\n\nThe value for this option can be an enumerable or a hash. `inclusion: %w(asc desc)` is equivalent\nto `inclusion: { in: %w(asc desc) }`.\n\nBesides from the `in` option, you can also use the `message` option for passing a custom error\ndetail when the parameter is not valid.\n\n```ruby\nrequest do\n  required :key_1, type: :string, inclusion: %w(asc desc)\n  required :key_2,\n                  type: :string,\n                  inclusion: { in: %w(s m l), message: 'Value is not a valid size' }\nend\n```\n\n### Length\nThe `length` option is for validating the length of the param value.\n\nThe value for this option can be an integer or a hash. `length: 5` is equivalent\nto `length: { min: 5, max: 5 }`.\n\nBesides from the `min` and `max` options, you can also use the `message` option for passing a\ncustom error detail when the parameter is not valid.\n\n```ruby\nrequest do\n  required :key_1, type: :string, length: 10\n  required :key_2, type: :string, length: { min: 5, max: 12 }\n  required :key_3, type: :array, elements: :email, length: { max: 3 }\n  required :key_4, type: :string, length: { max: 25, message: '25 characters is the maximum allowed' }\nend\n```\n\n### Value Size\nThe `value` option is for validating the value size of numerics parameters.\n\nThe value for this option is a hash with the following options: `min`, `max` and `message`.\n\n```ruby\nrequest do\n  required :key_1, type: :integer, value: { min: 0 }\n  required :key_2, type: :integer, value: { max: 1_000_000, message: 'Value too big!' }\n  required :key_3, type: :decimal, value: { min: 0, max: 1 }\nend\n```\n\n### Format\nThe `format` option allows to validate the format of the value with a regular expression.\n\nThe value for this option is a `regexp`, `string` or a `hash`. The string value is only valid\nwhen the type is a `date` or a `datetime`. Otherwise, you should use a regexp. The options for\nthe hash are: `regexp`, `strptime` and `message`.\n\nSo, for `date` and `datetime` types, `format: '%u%F'` is equivalent to\n`format: { strptime: '%u%F' }`. For the other types, `format: /^5[1-5]\\d{14}$/` is\nequivalent to `format: { regexp: /^5[1-5]\\d{14}$/ }`.\n\n```ruby\nrequest do\n  required :key_1, type: :string, format: /^5[1-5]\\d{14}$/\n  required :key_2, type: :string, format: { regexp: /^1.*/,\n                                            message: 'Value should start with a 1' }\nend\n```\n\n### Custom Validation\nYou can add custom validations to the parameter with the option `validate`.\n\nThis option accepts a Proc as value or a hash. For example,\n`validate: lambda { |value| value \u003e Date.today }` is equivalent to\n`validate: { function: lambda { |value| value \u003e Date.today } }`. The hash value\nalso accepts the `message` option.\n\n```ruby\nrequest do\n  required :key_1, type: :date, validate: { function: lambda { |value| value \u003e= Date.today },\n                                            message: 'The date can not be in the past' }\nend\n```\n\n### Precision \u003ca name='precision'\u003e\u003c/a\u003e\nThe `precision` option are for `decimal` types. This option does not execute any validation\non the value of the parameter, but it will round the decimal when the value is converter to\nthe specified type.\n\nIf you want to set a precision value to all `decimal` parameters, you can use the global\nconfiguration option `format.decimal_precision`. Keep in mind that if you set the `precision`\noption on a parameter, it will locally override the global configuration. See [here](#configuration)\nfor all globals configuration options.\n\nThis option accepts an integer as value.\n\n```ruby\nrequest do\n  required :key_1, type: :decimal, precision: 2\nend\n```\n\n### Default Values\nWhen parameters are optional, with the `default` option you can set a default value when the parameter is not\npresent.\n\nThe value for the option `default` could be anything, including a proc.\n\n```ruby\nrequest do\n  optional :key_1, type: :string, default: 'Jane'\n  optional :key_2, type: :string, default: lambda { Date.today.strftime('%A') }\nend\n```\n\n### Transformations\nTransformations are functions that are called to the value of the parameter, after it has already\nbeen validated. The option for this is `transform`.\n\nThe `transform` option could be a symbol, or a proc. The proc will receive the value of the\nparameter as an argument, so keep in mind that the value will be already of the type\nspecified in the definition. So, `transform: :strip` is equivalent to\n`transform: lambda { |value| value.strip }`.\n\n```ruby\nrequest do\n  optional :key_1, type: :string, transform: :strip\n  optional :key_2,\n           type: :string,\n           format: /^\\d{3}-\\d{3}-\\d{3}$/,\n           transform: lambda { |value| value.gsub(/-/, '') }\nend\n```\n\n### Rename Parameters\nYou can rename parameters using the `as` option.\n\n```ruby\nrequest do\n  required :email_address, type: :email, as: :email\nend\n```\n\nThis means that in the request params you expect a valid email value in the key `email_address`,\nbut in your controller you will access with the key `email`.\n\n### Dependent Parameters\nIf you want to receive and validate a parameter only if another one is given, you can use\nthe `is_given` option.\n\n```ruby\nrequest do\n  optional :label, type: :string\n  required :description, type: :string, if_given: :label\n  #...\n  required :card_type, inclusion: %w(credit_card debit_card)\n  required :ccv, if_given: { card_type: lambda { |value| value == 'credit_card' } }\nend\n```\n\nOn the example above, the param `description` will be only validated if the param `label` is present.\nRequestParamsValidation will use the method `blank?` to check that. On the other hand, the param\n`ccv` will only be validated if the param `type_card` is equal to the string `credit_card`.\n\nNotice that if the global option `filter_params` is set to `true` (default behaviour), then the\ndependent parameters will be filtered from the `params object` if they haven't beeen validated.\nThis way we make sure to only receive those parameters that have been validated against our request\ndefinitions.\n\nBe aware that if you rename a param, then you should use the new name in the `if_given` option.\n\n---\n### NOTE\n\nRequestParamsValidation will start validating the presence of the parameters. Then, if the value is\nnot present and the parameter has a default value, it will assign that value and not execute any\nfurther validation. Otherwise, it will validate the type, convert it to the right type and then\ncontinue with the others validations. So, all others validations will be executed with the parameter\nvalue already converter to the specified type, so keep in mind that at defining the validations.\n\n## Errors \u0026 Messages\n\nFor default, when a required parameter failed the presence validation, the exception\n`RequestParamsValidation::MissingParameterError` will be raised. If it failed for any of the others\nvalidations, the raised exception will be `RequestParamsValidation::InvalidParameterValueError`\nwith a proper descriptive error message.\n\nThis two exceptions inherits from `RequestParamsValidation::RequestParamError`, so you\ncan rescue the exceptions like this:\n\n```ruby\n# app/controllers/application_controller.rb\n\nclass ApplicationController \u003c ActionController::Base\n  rescue_from RequestParamsValidation::RequestParamError do |exception|\n    # do whatever you want\n  end\nend\n```\n\nBoth exceptions has getters methods to access data related to the failure. For example, the\n`RequestParamsValidation::MissingParameterError` exception has two public methods `param_key`\nand `param_type` for getting the name and type of the parameter which failed. And the\n`RequestParamsValidation::InvalidParameterValueError` exception has the two mentioned methods,\nplus the methods `param_value` and `details`. `param_value` returns the value of the parameter,\nand `details` give more information about the reason of the failure.\n\n### Errors messages\nFor the exception `RequestParamsValidation::MissingParameterError`, the error message is the\nfollowing:\n\n```ruby\n\"The parameter '#{param_key}' is missing\"\n```\n\nAnd for `RequestParamsValidation::InvalidParameterValueError` the message is:\n\n```ruby\n\"The value for the parameter '#{param_key}' is invalid\"\n```\n\nOr, if `details` is present:\n\n```ruby\n\"The value for the parameter '#{param_key}' is invalid. #{details}\"\n```\n\nThe details is different depending on the reason of the failure, and whether the parameter is\nan element of an array or not. If you **have specified the `message` option in the parameter\ndefinition**, then the details will be that value, otherwise it will took a default value from\nthe table below:\n\n| Failure                   | Default Message                                                                                                                                                                                                                                                      |\n| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Missing parameter         | N/A                                                                                                                                                                                                                                                                  |\n| Invalid type              | - `Value should be a valid %{param_type}` \u003cbr\u003e - `All elements of the array should be a valid %{type}` \u003cbr\u003e If has `date` or `datetime` type with specified `format`: \u003cbr\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp; - ` with the format %{format}` is added to the message                 |\n| Invalid inclusion         | - `Value should be in %{include_in}` \u003cbr\u003e - `All elements values of the array should be in %{include_in}`                                                                                                                                                            |\n| Invalid length            | - `Length should be greater or equal than %{min}` \u003cbr\u003e - `Length should be less or equal than %{max}` \u003cbr\u003e - `Length should be equal to %{min/max}` \u003c/br\u003e - `Length should be between %{min} and %{max}` \u003cbr\u003e - `All elements of the array should have a length ...` |\n| Invalid value size        | - `Value should be greater or equal than %{min}` \u003cbr\u003e - `Value should be less or equal than %{max}` \u003cbr\u003e - `Value should be between %{min} and %{max}` \u003cbr\u003e - `All elements of the array should have a value ...`                                                    |\n| Invalid format            | - `Value format is invalid` \u003cbr\u003e - `An element of the array has an invalid format`                                                                                                                                                                                   |\n| Invalid custom validation | N/A                                                                                                                                                                                                                                                                  |                                               |\n\n### Custom Exceptions\nHowever, if the above is not enough for your app, and you need to fully customize the exceptions\nand the messages, you can setup your own exceptions classes for each type of failure. They are\nglobals configurations options that allow you to do that. See below to see them all.\n\n## Global Configurations \u003ca name='configuration'\u003e\u003c/a\u003e\nGlobal configurations help you to customize the gem to fulfill your needs. To change this\nconfiguration, you need to create an initializer and configure what you want to change:\n\n```ruby\n# config/initializers/request_params_validation.rb\n\nRequestParamsValidation.configure do |config|\n  #... here goes the configuration\nend\n```\n\nTo see a complete initializer file of the configuration with all the options and their description,\nplease see [here](./examples/initializer.rb).\n\n## Acknowledgments\nThis gem is strongly inspired in a Ruby framework named [Angus](https://github.com/moove-it/angus)\ndeveloped by [Moove It](https://moove-it.com/)\n\n## Contributing\n1.  Fork it\n2.  Create your feature branch (git checkout -b my-new-feature)\n3.  Commit your changes (git commit -am 'Add some feature')\n4.  Push to the branch (git push origin my-new-feature)\n5.  Create a Pull Request\n\n## License\nThis software is released under the MIT license. See the MIT-LICENSE file for more info.\n","funding_links":[],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffelipefava%2Frequest_params_validation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffelipefava%2Frequest_params_validation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffelipefava%2Frequest_params_validation/lists"}