FAQ & Troubleshooting
Common questions, issues, and solutions when working with Azu.
Frequently Asked Questions
General Questions
Q: What makes Azu different from other web frameworks?
A: Azu emphasizes compile-time type safety and contract-first development. Unlike traditional frameworks that validate at runtime, Azu catches errors during compilation, resulting in more reliable applications with zero runtime overhead for type checking.
Q: Can I use Azu for production applications?
A: Yes! Azu is built for production use with performance optimizations, comprehensive error handling, and scalability features. Many applications are successfully running Azu in production environments.
Q: How does Azu compare to other Crystal web frameworks?
A: Azu focuses on type-safe contracts and real-time features, while frameworks like Kemal prioritize simplicity. Azu provides more structure and compile-time guarantees at the cost of some flexibility.
Q: Do I need to learn Crystal to use Azu?
A: Yes, basic Crystal knowledge is required. However, Crystal's syntax is similar to Ruby, making it approachable for developers from many backgrounds.
Technical Questions
Q: How do I handle database connections in Azu?
A: Azu doesn't include a built-in ORM. You can use any Crystal database library like crystal-db, granite, or jennifer.cr:
require "pg"
require "azu"
struct UserEndpoint
include Azu::Endpoint(UserRequest, UserResponse)
get "/users/:id"
def call : UserResponse
DB.open("postgres://localhost/mydb") do |db|
user = db.query_one("SELECT * FROM users WHERE id = $1",
params["id"], as: User)
UserResponse.new(user)
end
end
endQ: Can I use Azu with existing Crystal libraries?
A: Absolutely! Azu is designed to work with the Crystal ecosystem. You can use any Crystal shard or library within your Azu applications.
Q: How do I handle authentication?
A: Implement authentication using middleware:
class AuthenticationHandler
include HTTP::Handler
def call(context)
token = context.request.headers["Authorization"]?
unless token && valid_token?(token)
context.response.status = HTTP::Status::UNAUTHORIZED
context.response.print "Authentication required"
return
end
context.set("current_user", get_user_from_token(token))
call_next(context)
end
end
# Add to middleware stack
MyApp.start [
AuthenticationHandler.new,
# ... other handlers
]Q: How do I deploy Azu applications?
A: Compile your application and deploy the binary:
# Build for production
crystal build --release --no-debug src/my_app.cr
# Deploy binary to server
scp my_app user@server:/opt/myapp/Common Issues
Compilation Issues
Problem: "can't infer type" errors
# ❌ This causes type inference issues
def create_user(request)
# Crystal can't infer the request type
end
# ✅ Use explicit types
def create_user(request : CreateUserRequest) : UserResponse
# Clear type information
endProblem: Template compilation errors
Error: can't find template "users/show.html"Solution: Check template paths in configuration:
configure do
templates.path = ["templates", "views"] # Add all template directories
template_hot_reload = env.development? # Enable hot reload for development
endRuntime Issues
Problem: WebSocket connections not working
Symptoms:
WebSocket connection fails
No error messages in logs
Client can't connect
Solutions:
Check WebSocket route registration:
class MyChannel < Azu::Channel
ws "/websocket" # Make sure this matches client URL
def on_connect
# Implementation
end
endVerify middleware order:
MyApp.start [
Azu::Handler::Logger.new,
# Don't put static handler before WebSocket routes
# WebSocket handlers should come early in the stack
]Check client-side connection:
// Make sure URL matches server route
const ws = new WebSocket("ws://localhost:4000/websocket");Problem: Request validation not working
Symptoms:
Validation rules ignored
Invalid data passes through
Solutions:
Ensure validation is called:
def call : UserResponse
# Always validate before processing
unless create_user_request.valid?
raise Azu::Response::ValidationError.new(
create_user_request.errors.group_by(&.field).transform_values(&.map(&.message))
)
end
# Process validated request
UserResponse.new(create_user(create_user_request))
endCheck validation rules syntax:
struct UserRequest
include Azu::Request
getter name : String
getter email : String
# ✅ Correct validation syntax
validate name, presence: true, length: {min: 2}
validate email, presence: true, format: /@/
def initialize(@name = "", @email = "")
end
endProblem: File uploads not working
Symptoms:
File uploads fail silently
Uploaded files are empty
Memory issues with large files
Solutions:
Configure upload limits:
configure do
upload.max_file_size = 50.megabytes
upload.temp_dir = "/tmp/uploads"
endHandle multipart data correctly:
struct FileUploadRequest
include Azu::Request
getter file : Azu::Params::Multipart::File?
getter description : String
def initialize(@file = nil, @description = "")
end
end
def call : FileUploadResponse
if file = file_upload_request.file
# Validate file
raise error("File too large") if file.size > 10.megabytes
# Save file
final_path = save_uploaded_file(file)
file.cleanup # Important: clean up temp file
FileUploadResponse.new(path: final_path)
else
raise error("File is required")
end
endPerformance Issues
Problem: Slow response times
Diagnosis:
Enable request logging:
MyApp.start [
Azu::Handler::Logger.new, # Add this first
# ... other handlers
]Check for blocking operations:
def call : UserResponse
# ❌ Blocking database call
users = database.query("SELECT * FROM users") # Blocks fiber
# ✅ Use async operations when possible
users = database.async_query("SELECT * FROM users")
UserResponse.new(users)
endProblem: Memory leaks
Common causes:
Not cleaning up file uploads
Keeping references to WebSocket connections
Large object creation in loops
Solutions:
Clean up resources:
def handle_file_upload(file)
process_file(file)
ensure
file.cleanup if file # Always cleanup
endManage WebSocket connections:
class MyChannel < Azu::Channel
CONNECTIONS = Set(HTTP::WebSocket).new
def on_connect
CONNECTIONS << socket.not_nil!
end
def on_close(code, message)
CONNECTIONS.delete(socket) # Remove on disconnect
end
endDevelopment Issues
Problem: Hot reload not working
Solutions:
Enable in configuration:
configure do
template_hot_reload = env.development? # Make sure this is true
endCheck file permissions and paths:
# Make sure template files are readable
chmod -R 644 templates/Problem: CORS issues in development
Symptoms:
Browser blocks requests from frontend
CORS errors in console
Solution:
MyApp.start [
Azu::Handler::CORS.new(
allowed_origins: ["http://localhost:3000"], # Add your frontend URL
allowed_methods: %w(GET POST PUT PATCH DELETE OPTIONS),
allowed_headers: %w(Accept Content-Type Authorization)
),
# ... other handlers
]Debugging Tips
Enable Debug Logging
configure do
log.level = Log::Severity::DEBUG # See all log messages
endInspect Request Data
def call : UserResponse
Log.debug { "Request data: #{create_user_request.inspect}" }
Log.debug { "Params: #{params.to_hash}" }
Log.debug { "Headers: #{context.request.headers}" }
# ... endpoint logic
endUse Crystal's Built-in Debugging
# Add pp for pretty printing
require "pp"
def call : UserResponse
pp create_user_request # Pretty print request object
pp params.to_hash # Pretty print parameters
# ... endpoint logic
endTest Individual Components
# Test request contracts in isolation
user_request = CreateUserRequest.new(name: "test", email: "test@example.com")
puts user_request.valid?
puts user_request.errors.map(&.message)
# Test response objects
user = User.new(name: "test")
response = UserResponse.new(user)
puts response.renderPerformance Troubleshooting
Profile Your Application
require "benchmark"
def call : UserResponse
time = Benchmark.measure do
# Your endpoint logic here
end
Log.info { "Endpoint took #{time.total_seconds}s" }
# ... return response
endMonitor Memory Usage
# Check memory usage during runtime
ps aux | grep my_app
# Use Crystal's built-in memory tracking
crystal run --stats src/my_app.crDatabase Query Optimization
# Log slow queries
def call : UserResponse
start_time = Time.monotonic
users = database.query("SELECT * FROM users WHERE active = true")
duration = Time.monotonic - start_time
if duration > 100.milliseconds
Log.warn { "Slow query detected: #{duration.total_milliseconds}ms" }
end
UserResponse.new(users)
endGetting Help
Community Resources
GitHub Issues: azutoolkit/azu/issues
Crystal Community: Crystal Language Forum
Documentation: Official Azu Docs
Reporting Issues
When reporting issues, include:
Crystal version:
crystal versionAzu version: Check
shard.ymlMinimal reproduction case
Error messages and stack traces
Environment details (OS, deployment method)
Example Issue Report
**Crystal Version**: 1.10.1
**Azu Version**: 0.5.2
**OS**: macOS 13.0
**Issue**: WebSocket connection fails with "Connection refused"
**Reproduction**:
```crystal
class TestChannel < Azu::Channel
ws "/test"
def on_connect
puts "Connected"
end
endError: Connection refused when trying to connect to ws://localhost:4000/test
Expected: WebSocket connection should succeed
---
**Still need help?** Check the [Contributing Guide](contributing.md) for information on getting support from the community.Last updated
Was this helpful?
