class Router

Dispatches HTTP requests to handlers using exact path and method matches.

Request targets are parsed with Protocol::URL::Reference. Handlers receive the original request and the decoded query parameters.

Nested Classes and Modules

each

Definitions

def initialize

Initialize a router.

Signature

yields {|router| ...}

The router to configure.

Implementation

def initialize
	@routes = {}
	
	yield self if block_given?
end

def route(path, methods: nil, &handler)

Add a route.

When methods is omitted, the handler accepts every HTTP method. Otherwise, it may be a single method or an array of methods.

Signature

parameter path String

The absolute path to match.

parameter methods String | Symbol | Array(String | Symbol) | Nil

The accepted HTTP methods.

yields {|request, parameters| ...}

The route handler.

parameter request Protocol::HTTP::Request

The original request.

parameter parameters Hash

The decoded query parameters.

returns Router

The router.

Implementation

def route(path, methods: nil, &handler)
	raise ArgumentError, "A route handler is required!" unless handler
	
	path = route_path(path)
	methods = route_methods(methods)
	handlers = (@routes[path] ||= {})
	
	methods.each do |method|
		if handlers.key?(method)
			raise ArgumentError, "Route already defined for #{method || "any method"} #{path}!"
		end
		
		handlers[method] = handler
	end
	
	return self
end

def call(request)

Dispatch a request to a matching route.

Signature

parameter request Protocol::HTTP::Request

The request to dispatch.

returns Protocol::HTTP::Response | Nil

The handler or error response, or nil when no path matches.

Implementation

def call(request)
	reference = parse_reference(request.path)
	return Protocol::HTTP::Response[400] unless reference
	
	unless handlers = @routes[reference.path]
		return nil
	end
	
	unless handler = handlers[request.method] || handlers[ANY_METHOD]
		allowed_methods = handlers.keys.compact.sort.join(", ")
		return Protocol::HTTP::Response[405, [["allow", allowed_methods]]]
	end
	
	parameters = parse_query(reference)
	return Protocol::HTTP::Response[400] unless parameters
	
	return handler.call(request, parameters)
end