sinatra-param
sinatra-param copied to clipboard
Parameter Validation & Type Coercion for Sinatra
sinatra-param
Parameter Validation & Type Coercion for Sinatra
REST conventions take the guesswork out of designing and consuming web APIs. Simply GET, POST, PATCH, or DELETE resource endpoints, and you get what you'd expect.
However, when it comes to figuring out what parameters are expected... well, all bets are off.
This Sinatra extension takes a first step to solving this problem on the developer side
sinatra-param allows you to declare, validate, and transform endpoint parameters as you would in frameworks like ActiveModel or DataMapper.
Use
sinatra-paramin combination withRack::PostBodyContentTypeParserandRack::NestedParamsto automatically parameterize JSONPOSTbodies and nested parameters.
Install
You can install sinatra-param from the command line with the following:
$ gem install sinatra-param
Alternatively, you can specify sinatra-param as a dependency in your Gemfile and run $ bundle install:
gem "sinatra-param", require: "sinatra/param"
Example
require 'sinatra/base'
require 'sinatra/param'
require 'json'
class App < Sinatra::Base
helpers Sinatra::Param
before do
content_type :json
end
# GET /search?q=example
# GET /search?q=example&categories=news
# GET /search?q=example&sort=created_at&order=ASC
get '/search' do
param :q, String, required: true
param :categories, Array
param :sort, String, default: "title"
param :order, String, in: ["ASC", "DESC"], transform: :upcase, default: "ASC"
param :price, String, format: /[<\=>]\s*\$\d+/
one_of :q, :categories
{...}.to_json
end
end
Parameter Types
By declaring parameter types, incoming parameters will automatically be transformed into an object of that type. For instance, if a param is Boolean, values of '1', 'true', 't', 'yes', and 'y' will be automatically transformed into true.
StringIntegerFloatBoolean("1/0", "true/false", "t/f", "yes/no", "y/n")Array("1,2,3,4,5")Hash(key1:value1,key2:value2)Date,Time, &DateTime
Validations
Encapsulate business logic in a consistent way with validations. If a parameter does not satisfy a particular condition, a 400 error is returned with a message explaining the failure.
requiredblankisin,within,rangemin/maxmin_length/max_lengthformat
Custom Error Messages
Passing a message option allows you to customize the message
for any validation error that occurs.
param :spelling,
format: /\b(?![a-z]*cie)[a-z]*(?:cei|ie)[a-z]*/i,
message: "'i' before 'e', except after 'c'"
Defaults and Transformations
Passing a default option will provide a default value for a parameter if none is passed. A default can defined as either a default or as a Proc:
param :attribution, String, default: "©"
param :year, Integer, default: lambda { Time.now.year }
Use the transform option to take even more of the business logic of parameter I/O out of your code. Anything that responds to to_proc (including Proc and symbols) will do.
param :order, String, in: ["ASC", "DESC"], transform: :upcase, default: "ASC"
param :offset, Integer, min: 0, transform: lambda {|n| n - (n % 10)}
One Of
Using one_of, routes can specify two or more parameters to be mutually exclusive, and fail if more than one of those parameters is provided:
param :a, String
param :b, String
param :c, String
one_of :a, :b, :c
Any Of
Using any_of, a route can specify that at least one of two or more parameters are required, and fail if none of them are provided:
param :x, String
param :y, String
any_of :x, :y
All Or None Of
Using all_or_none_of, a router can specify that all or none of a set of parameters are required, and fail if some are provided:
param :x, String
param :y, String
all_or_none_of :x,:y
Exceptions
By default, when a parameter precondition fails, Sinatra::Param will halt 400 with an error message:
{
"message": "Parameter must be within [\"ASC\", \"DESC\"]",
"errors": {
"order": "Parameter must be within [\"ASC\", \"DESC\"]"
}
}
To change this, you can set :raise_sinatra_param_exceptions to true, and intercept Sinatra::Param::InvalidParameterError with a Sinatra error do...end block. (To make this work in development, set :show_exceptions to false and :raise_errors to true):
set :raise_sinatra_param_exceptions, true
error Sinatra::Param::InvalidParameterError do
{ error: "#{env['sinatra.error'].param} is invalid" }.to_json
end
Custom exception handling can also be enabled on an individual parameter basis, by passing the raise option:
param :order, String, in: ["ASC", "DESC"], raise: true
one_of :q, :categories, raise: true
Contact
Mattt (@mattt)
License
sinatra-param is released under an MIT license. See LICENSE for more information.