💎 Hash API Directive in TuskLang for Ruby

Ruby Documentation

Hash API Directive in TuskLang for Ruby

Welcome to the rebellious world of TuskLang's Hash API Directive! This is where we break free from the constraints of traditional API frameworks and embrace the power of declarative, configuration-driven API development. In Ruby, this means combining the elegance of TuskLang's hash directives with the expressiveness of Ruby's metaprogramming capabilities.

What is the Hash API Directive?

The Hash API Directive (#api) is TuskLang's way of saying "enough with the boilerplate!" It allows you to define complete API endpoints, routes, middleware, and behaviors using simple hash configurations. In Ruby, this translates to powerful, declarative API definitions that can be processed, validated, and executed with minimal ceremony.

Basic API Directive Syntax

Basic API endpoint definition

api_endpoint = { "#api" => { "method" => "GET", "path" => "/users/:id", "handler" => "UserController#show", "middleware" => ["auth", "rate_limit"], "validation" => { "id" => "integer|required" } } }

Ruby class to process the directive

class ApiDirectiveProcessor def initialize(config) @config = config @tusk_config = load_tusk_config end

def process_api_directive api_config = @config["#api"] return nil unless api_config

{ method: api_config["method"]&.upcase, path: api_config["path"], handler: parse_handler(api_config["handler"]), middleware: Array(api_config["middleware"]), validation: api_config["validation"] || {}, response_format: api_config["response_format"] || "json" } end

private

def parse_handler(handler_string) return nil unless handler_string controller, action = handler_string.split("#") { controller: controller, action: action } end

def load_tusk_config # Load TuskLang configuration TuskConfig.load("peanu.tsk") end end

Advanced API Configuration

Comprehensive API configuration with TuskLang features

advanced_api_config = { "#api" => { "method" => "POST", "path" => "/api/v1/users", "handler" => "Api::V1::UsersController#create", "middleware" => ["cors", "auth", "rate_limit:100,1m"], "validation" => { "user.email" => "email|required|unique:users", "user.password" => "string|min:8|max:128", "user.profile.name" => "string|required|max:100" }, "response_format" => "json", "status_codes" => { "201" => "User created successfully", "400" => "Validation failed", "409" => "Email already exists" }, "documentation" => { "summary" => "Create a new user account", "description" => "Creates a new user with email verification", "tags" => ["users", "authentication"] } } }

Ruby processor for advanced configurations

class AdvancedApiProcessor < ApiDirectiveProcessor def process_advanced_config base_config = process_api_directive api_config = @config["#api"] base_config.merge({ status_codes: api_config["status_codes"] || {}, documentation: api_config["documentation"] || {}, rate_limit: parse_rate_limit(api_config["middleware"]), validation_rules: build_validation_rules(api_config["validation"]) }) end

private

def parse_rate_limit(middleware) rate_limit_middleware = middleware.find { |m| m.start_with?("rate_limit:") } return nil unless rate_limit_middleware limits = rate_limit_middleware.split(":")[1] requests, period = limits.split(",") { requests: requests.to_i, period: parse_period(period) } end

def parse_period(period) case period when /(\d+)s/ then $1.to_i when /(\d+)m/ then $1.to_i * 60 when /(\d+)h/ then $1.to_i * 3600 else 60 # default to 1 minute end end

def build_validation_rules(validation_config) validation_config.transform_values do |rules| rules.split("|").map(&:strip) end end end

RESTful API Patterns

Complete RESTful API configuration

restful_api_config = { "#api" => { "base_path" => "/api/v1", "resources" => { "users" => { "index" => { "method" => "GET", "handler" => "UsersController#index", "middleware" => ["auth", "pagination"], "query_params" => ["page", "per_page", "search"] }, "show" => { "method" => "GET", "path" => "/:id", "handler" => "UsersController#show", "middleware" => ["auth"] }, "create" => { "method" => "POST", "handler" => "UsersController#create", "middleware" => ["auth", "validation"], "validation" => { "user.email" => "email|required|unique:users", "user.password" => "string|min:8" } }, "update" => { "method" => "PUT", "path" => "/:id", "handler" => "UsersController#update", "middleware" => ["auth", "ownership"] }, "destroy" => { "method" => "DELETE", "path" => "/:id", "handler" => "UsersController#destroy", "middleware" => ["auth", "admin"] } } } } }

Ruby RESTful API processor

class RestfulApiProcessor def initialize(config) @config = config["#api"] end

def generate_routes base_path = @config["base_path"] routes = []

@config["resources"].each do |resource_name, actions| actions.each do |action_name, action_config| route = build_route(base_path, resource_name, action_name, action_config) routes << route end end

routes end

private

def build_route(base_path, resource, action, config) path = config["path"] || resource_path(resource, action) full_path = "#{base_path}#{path}"

{ method: config["method"], path: full_path, handler: config["handler"], middleware: Array(config["middleware"]), validation: config["validation"] || {}, query_params: config["query_params"] || [] } end

def resource_path(resource, action) case action when "index" then "/#{resource}" when "create" then "/#{resource}" when "show" then "/#{resource}/:id" when "update" then "/#{resource}/:id" when "destroy" then "/#{resource}/:id" else "/#{resource}" end end end

API Versioning and Documentation

Versioned API with comprehensive documentation

versioned_api_config = { "#api" => { "version" => "v1", "base_url" => "https://api.example.com", "documentation" => { "title" => "Example API", "version" => "1.0.0", "description" => "A comprehensive API for managing resources", "contact" => { "name" => "API Support", "email" => "api@example.com" } }, "endpoints" => { "users" => { "GET /users" => { "summary" => "List all users", "parameters" => { "page" => { "type" => "integer", "default" => 1 }, "per_page" => { "type" => "integer", "default" => 20 } }, "responses" => { "200" => { "description" => "List of users" }, "401" => { "description" => "Unauthorized" } } }, "POST /users" => { "summary" => "Create a new user", "request_body" => { "required" => true, "content" => { "application/json" => { "schema" => { "type" => "object", "properties" => { "email" => { "type" => "string", "format" => "email" }, "password" => { "type" => "string", "minLength" => 8 } } } } } } } } } } }

Ruby API documentation generator

class ApiDocumentationGenerator def initialize(config) @config = config["#api"] end

def generate_openapi_spec { openapi: "3.0.0", info: build_info, servers: build_servers, paths: build_paths, components: build_components } end

private

def build_info doc = @config["documentation"] { title: doc["title"], version: doc["version"], description: doc["description"], contact: doc["contact"] } end

def build_servers [ { url: @config["base_url"], description: "Production server" } ] end

def build_paths paths = {} @config["endpoints"].each do |resource, endpoints| endpoints.each do |path_method, config| method, path = path_method.split(" ") paths[path] ||= {} paths[path][method.downcase] = build_operation(config) end end

paths end

def build_operation(config) { summary: config["summary"], parameters: build_parameters(config["parameters"]), requestBody: build_request_body(config["request_body"]), responses: build_responses(config["responses"]) } end

def build_parameters(parameters) return [] unless parameters

parameters.map do |name, spec| { name: name, in: "query", schema: { type: spec["type"] }, default: spec["default"] } end end

def build_request_body(request_body) return nil unless request_body

{ required: request_body["required"], content: request_body["content"] } end

def build_responses(responses) return {} unless responses

responses.transform_values do |response| { description: response["description"] } end end

def build_components { securitySchemes: { bearerAuth: { type: "http", scheme: "bearer", bearerFormat: "JWT" } } } end end

Error Handling and Validation

API error handling configuration

error_handling_config = { "#api" => { "error_handling" => { "global_middleware" => ["error_handler", "cors"], "error_responses" => { "400" => { "message" => "Bad Request", "details" => "validation_errors" }, "401" => { "message" => "Unauthorized", "details" => "authentication_required" }, "403" => { "message" => "Forbidden", "details" => "insufficient_permissions" }, "404" => { "message" => "Not Found", "details" => "resource_not_found" }, "422" => { "message" => "Unprocessable Entity", "details" => "validation_failed" }, "500" => { "message" => "Internal Server Error", "details" => "server_error" } }, "validation" => { "strict_mode" => true, "custom_validators" => { "unique_email" => "EmailValidator#unique", "strong_password" => "PasswordValidator#strong" } } } } }

Ruby error handling processor

class ApiErrorHandler def initialize(config) @config = config["#api"]["error_handling"] end

def handle_error(error, request) error_response = build_error_response(error) log_error(error, request) error_response end

private

def build_error_response(error) status_code = determine_status_code(error) error_config = @config["error_responses"][status_code.to_s]

{ status: status_code, error: { message: error_config["message"], details: error_config["details"], timestamp: Time.current.iso8601, request_id: SecureRandom.uuid } } end

def determine_status_code(error) case error when ActiveRecord::RecordNotFound then 404 when ActiveRecord::RecordInvalid then 422 when ActionController::ParameterMissing then 400 when ActionController::UnpermittedParameters then 400 when ActionController::InvalidAuthenticityToken then 401 else 500 end end

def log_error(error, request) Rails.logger.error({ error: error.class.name, message: error.message, backtrace: error.backtrace.first(5), request: { method: request.method, path: request.path, params: request.params.except(:controller, :action), user_agent: request.user_agent, ip: request.remote_ip } }) end end

Performance and Caching

API performance and caching configuration

performance_config = { "#api" => { "performance" => { "caching" => { "enabled" => true, "strategy" => "redis", "ttl" => 3600, "cache_keys" => { "users" => "users:list:{page}:{per_page}", "user" => "users:show:{id}", "user_posts" => "users:{id}:posts:{page}" } }, "rate_limiting" => { "enabled" => true, "limits" => { "default" => "1000/hour", "authenticated" => "5000/hour", "admin" => "10000/hour" } }, "compression" => { "enabled" => true, "algorithms" => ["gzip", "deflate"] }, "pagination" => { "default_per_page" => 20, "max_per_page" => 100, "page_param" => "page", "per_page_param" => "per_page" } } } }

Ruby performance processor

class ApiPerformanceProcessor def initialize(config) @config = config["#api"]["performance"] end

def apply_caching(response, cache_key) return response unless @config["caching"]["enabled"]

cache_config = @config["caching"] Rails.cache.fetch(cache_key, expires_in: cache_config["ttl"]) do response end end

def check_rate_limit(request, user) return true unless @config["rate_limiting"]["enabled"]

limits = @config["rate_limiting"]["limits"] limit_key = determine_limit_key(user) limit_config = limits[limit_key] || limits["default"]

RateLimiter.check(request.remote_ip, limit_config) end

def apply_compression(response) return response unless @config["compression"]["enabled"]

algorithms = @config["compression"]["algorithms"] # Apply compression based on accepted encoding response end

def paginate_results(results, params) pagination_config = @config["pagination"] per_page = [ params[pagination_config["per_page_param"]]&.to_i || pagination_config["default_per_page"], pagination_config["max_per_page"] ].min

page = params[pagination_config["page_param"]]&.to_i || 1

results.page(page).per(per_page) end

private

def determine_limit_key(user) return "admin" if user&.admin? return "authenticated" if user "default" end end

Testing and Validation

API testing configuration

testing_config = { "#api" => { "testing" => { "test_cases" => { "users" => { "GET /users" => { "valid_responses" => [200, 401], "test_data" => { "valid_user" => { "email" => "test@example.com", "password" => "password123" } } }, "POST /users" => { "valid_responses" => [201, 400, 422], "test_scenarios" => [ { "name" => "valid_user_creation", "data" => { "email" => "new@example.com", "password" => "password123" }, "expected_status" => 201 }, { "name" => "invalid_email", "data" => { "email" => "invalid-email", "password" => "password123" }, "expected_status" => 422 } ] } } }, "mock_data" => { "users" => [ { "id" => 1, "email" => "user1@example.com", "name" => "User One" }, { "id" => 2, "email" => "user2@example.com", "name" => "User Two" } ] } } } }

Ruby API testing framework

class ApiTestFramework def initialize(config) @config = config["#api"]["testing"] end

def run_tests results = {} @config["test_cases"].each do |resource, endpoints| results[resource] = {} endpoints.each do |endpoint, test_config| results[resource][endpoint] = run_endpoint_tests(endpoint, test_config) end end

results end

def run_endpoint_tests(endpoint, config) method, path = endpoint.split(" ") tests = []

# Run basic response tests config["valid_responses"].each do |status_code| test_result = test_response(method, path, status_code) tests << test_result end

# Run scenario tests config["test_scenarios"]&.each do |scenario| test_result = run_scenario_test(method, path, scenario) tests << test_result end

tests end

def test_response(method, path, expected_status) response = make_request(method, path) { scenario: "status_#{expected_status}", expected_status: expected_status, actual_status: response.status, passed: response.status == expected_status, response_body: response.body } end

def run_scenario_test(method, path, scenario) response = make_request(method, path, scenario["data"]) { scenario: scenario["name"], expected_status: scenario["expected_status"], actual_status: response.status, passed: response.status == scenario["expected_status"], response_body: response.body } end

private

def make_request(method, path, data = nil) # Implementation would use Rack::Test or similar # This is a simplified example case method.upcase when "GET" # GET request when "POST" # POST request with data end end end

Integration with Ruby Frameworks

Rails integration example

class TuskApiController < ApplicationController include TuskApiProcessor

def initialize @tusk_config = load_tusk_config @api_processor = ApiDirectiveProcessor.new(@tusk_config) end

def process_request api_config = @api_processor.process_api_directive # Apply middleware apply_middleware(api_config[:middleware]) # Validate request validate_request(api_config[:validation]) # Execute handler execute_handler(api_config[:handler]) end

private

def apply_middleware(middleware_list) middleware_list.each do |middleware| case middleware when "auth" authenticate_user! when /^rate_limit:(.+)$/ apply_rate_limit($1) when "cors" set_cors_headers end end end

def validate_request(validation_rules) validation_rules.each do |field, rules| validate_field(field, rules) end end

def execute_handler(handler_config) controller_class = handler_config[:controller].constantize controller = controller_class.new controller.send(handler_config[:action]) end

def load_tusk_config TuskConfig.load("peanu.tsk") end end

Sinatra integration example

class TuskSinatraApp < Sinatra::Base include TuskApiProcessor

configure do @tusk_config = TuskConfig.load("peanu.tsk") @api_processor = ApiDirectiveProcessor.new(@tusk_config) end

before do process_api_directive end

def process_api_directive api_config = @api_processor.process_api_directive return unless api_config

# Apply middleware apply_sinatra_middleware(api_config[:middleware]) # Set up validation setup_validation(api_config[:validation]) end

private

def apply_sinatra_middleware(middleware_list) middleware_list.each do |middleware| case middleware when "auth" authenticate_user when "cors" enable_cors end end end

def setup_validation(validation_rules) validation_rules.each do |field, rules| validate_field(field, rules) end end end

Best Practices and Patterns

Best practices for API directive usage

class ApiDirectiveBestPractices def self.validate_config(config) errors = [] # Check required fields unless config["#api"] errors << "Missing #api directive" return errors end

api_config = config["#api"] # Validate method unless %w[GET POST PUT DELETE PATCH].include?(api_config["method"]) errors << "Invalid HTTP method: #{api_config['method']}" end

# Validate path unless api_config["path"]&.start_with?("/") errors << "Path must start with /" end

# Validate handler format if api_config["handler"] && !api_config["handler"].include?("#") errors << "Handler must be in format 'Controller#action'" end

errors end

def self.optimize_config(config) api_config = config["#api"] # Set defaults api_config["response_format"] ||= "json" api_config["middleware"] ||= [] # Add common middleware unless api_config["middleware"].include?("cors") api_config["middleware"] << "cors" end

config end

def self.generate_documentation(config) api_config = config["#api"] { endpoint: "#{api_config['method']} #{api_config['path']}", handler: api_config['handler'], middleware: api_config['middleware'], validation: api_config['validation'], documentation: api_config['documentation'] } end end

Usage example

config = { "#api" => { "method" => "POST", "path" => "/api/users", "handler" => "UsersController#create", "validation" => { "email" => "email|required", "password" => "string|min:8" } } }

Validate and optimize

errors = ApiDirectiveBestPractices.validate_config(config) if errors.empty? optimized_config = ApiDirectiveBestPractices.optimize_config(config) documentation = ApiDirectiveBestPractices.generate_documentation(config) puts "Configuration is valid!" puts "Documentation: #{documentation}" else puts "Configuration errors: #{errors}" end

Conclusion

The Hash API Directive in TuskLang represents a paradigm shift in API development. By combining declarative configuration with Ruby's powerful metaprogramming capabilities, you can create sophisticated, maintainable APIs with minimal boilerplate code.

Key benefits: - Declarative Configuration: Define complete API behavior in simple hash structures - Ruby Integration: Leverage Ruby's object-oriented and functional programming features - Validation and Error Handling: Built-in support for comprehensive validation and error responses - Performance Optimization: Automatic caching, rate limiting, and compression - Testing Support: Integrated testing framework with mock data and scenarios - Documentation Generation: Automatic OpenAPI specification generation

Remember, TuskLang is about breaking free from conventions and embracing the power of declarative, configuration-driven development. The Hash API Directive is your gateway to building APIs that are as expressive as they are powerful!