Request contracts define the expected shape of incoming request data with validation.
struct MyRequest
include Azu::Request
getter field1 : String
getter field2 : Int32?
def initialize(@field1 = "", @field2 = nil)
end
endAdd validation rules to a field.
validate field_name, rule: value, ...Available Rules:
| Rule | Description | Example |
|---|---|---|
presence |
Field must not be empty | presence: true |
length |
String length constraints | length: {min: 2, max: 100} |
format |
Regex pattern match | format: /@/ |
numericality |
Numeric constraints | numericality: {greater_than: 0} |
inclusion |
Value in set | inclusion: {in: ["a", "b"]} |
exclusion |
Value not in set | exclusion: {in: ["admin"]} |
Validate field is not empty/nil.
validate name, presence: trueValidate string length.
validate name, length: {min: 2} # At least 2 chars
validate name, length: {max: 100} # At most 100 chars
validate name, length: {min: 2, max: 100} # Between 2 and 100
validate code, length: {is: 6} # Exactly 6 charsOptions:
min : Int32- Minimum lengthmax : Int32- Maximum lengthis : Int32- Exact length
Validate against regular expression.
validate email, format: /@/
validate phone, format: /^\d{10}$/
validate slug, format: /^[a-z0-9-]+$/Validate numeric values.
validate age, numericality: {greater_than: 0}
validate age, numericality: {greater_than_or_equal_to: 18}
validate age, numericality: {less_than: 150}
validate age, numericality: {less_than_or_equal_to: 120}
validate quantity, numericality: {equal_to: 1}Options:
greater_than : Numbergreater_than_or_equal_to : Numberless_than : Numberless_than_or_equal_to : Numberequal_to : Number
Validate value is in allowed set.
validate status, inclusion: {in: ["pending", "active", "archived"]}
validate role, inclusion: {in: Role.values.map(&.to_s)}Validate value is not in forbidden set.
validate username, exclusion: {in: ["admin", "root", "system"]}Check if request passes all validations.
request = MyRequest.new(name: "")
request.valid? # => falseReturns: Bool
Get validation errors.
request.errors # => Array(Error)
request.errors.each do |error|
puts "#{error.field}: #{error.message}"
endReturns: Array(Error)
Override to add custom validation logic.
def validate
super # Run standard validations
if custom_condition_fails
errors << Error.new(:field, "custom message")
end
endRepresents a validation error.
Error.new(field : Symbol, message : String)Properties:
field : Symbol- Field namemessage : String- Error message
Use for endpoints that don't accept body data.
struct GetUserEndpoint
include Azu::Endpoint(EmptyRequest, UserResponse)
get "/users/:id"
def call : UserResponse
# No request body to parse
end
endRequests are automatically parsed from:
- JSON body (
application/json) - Form data (
application/x-www-form-urlencoded) - Multipart form (
multipart/form-data)
Handle file uploads with HTTP::FormData::File:
struct UploadRequest
include Azu::Request
getter file : HTTP::FormData::File
getter description : String?
def initialize(@file, @description = nil)
end
endFile Properties:
filename : String?- Original filenamebody : IO- File contentheaders : HTTP::Headers- File headers
struct CreateUserRequest
include Azu::Request
getter name : String
getter email : String
getter password : String
getter age : Int32?
getter role : String
def initialize(
@name = "",
@email = "",
@password = "",
@age = nil,
@role = "user"
)
end
validate name, presence: true, length: {min: 2, max: 100}
validate email, presence: true, format: /@/
validate password, presence: true, length: {min: 8}
validate age, numericality: {greater_than: 0, less_than: 150}, allow_nil: true
validate role, inclusion: {in: ["user", "admin", "moderator"]}
def validate
super
if email_taken?(email)
errors << Error.new(:email, "is already taken")
end
end
private def email_taken?(email : String) : Bool
User.exists?(email: email)
end
end