commit
54f25c5880
6 changed files with 30 additions and 68 deletions
|
@ -2,25 +2,6 @@ require "./spec_helper"
|
|||
|
||||
describe "Route" do
|
||||
describe "match?" do
|
||||
it "doesn't match because of route" do
|
||||
route = Route.new("GET", "/foo/bar") { "" }
|
||||
request = HTTP::Request.new("GET", "/world?message=coco")
|
||||
route.match?(request).should be_nil
|
||||
end
|
||||
|
||||
it "doesn't match because of method" do
|
||||
route = Route.new("GET", "/foo/bar") { "" }
|
||||
request = HTTP::Request.new("POST", "/foo/bar")
|
||||
route.match?(request).should be_nil
|
||||
end
|
||||
|
||||
it "matches" do
|
||||
route = Route.new("GET", "/foo/:one/path/:two") { "" }
|
||||
request = HTTP::Request.new("GET", "/foo/uno/path/dos")
|
||||
match = route.match?(request)
|
||||
match.should eq true
|
||||
end
|
||||
|
||||
it "matches the correct route" do
|
||||
kemal = Kemal::Handler.new
|
||||
kemal.add_route "GET", "/route1" do |env|
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
class Kemal::Context
|
||||
getter request
|
||||
getter response
|
||||
getter params
|
||||
getter route
|
||||
getter content_type
|
||||
|
||||
def initialize(@request, @params)
|
||||
def initialize(@request, @route)
|
||||
@response = Kemal::Response.new
|
||||
end
|
||||
|
||||
|
@ -22,6 +22,10 @@ class Kemal::Context
|
|||
@response.content_type
|
||||
end
|
||||
|
||||
def params
|
||||
Kemal::ParamParser.new(@route, @request).parse
|
||||
end
|
||||
|
||||
delegate headers, @request
|
||||
delegate status_code, :"status_code=", :"content_type=", @response
|
||||
end
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
require "http/server"
|
||||
require "uri"
|
||||
|
||||
# Kemal::Handler is the main handler which handles all the HTTP requests. Routing, parsing, rendering e.g
|
||||
# are done in this handler.
|
||||
|
@ -24,11 +23,11 @@ class Kemal::Handler < HTTP::Handler
|
|||
end
|
||||
|
||||
def process_request(request)
|
||||
url = request.path.not_nil!
|
||||
@routes.each do |route|
|
||||
match = route.match?(request)
|
||||
if match
|
||||
params = Kemal::ParamParser.new(route, request).parse
|
||||
context = Context.new(request, params)
|
||||
url.match(route.pattern as Regex) do |url_params|
|
||||
request.url_params = url_params
|
||||
context = Context.new(request, route)
|
||||
begin
|
||||
body = route.handler.call(context).to_s
|
||||
return HTTP::Response.new(context.status_code, body, context.response_headers)
|
||||
|
|
|
@ -11,17 +11,15 @@ class Kemal::ParamParser
|
|||
APPLICATION_JSON = "application/json"
|
||||
|
||||
def initialize(@route, @request)
|
||||
@route_components = route.components
|
||||
@request_components = request.path.not_nil!.split "/"
|
||||
@params = {} of String => AllParamTypes
|
||||
end
|
||||
|
||||
def parse
|
||||
parse_components
|
||||
parse_request
|
||||
end
|
||||
|
||||
def parse_request
|
||||
parse_url_params
|
||||
parse_query
|
||||
parse_body
|
||||
parse_json
|
||||
|
@ -37,6 +35,18 @@ class Kemal::ParamParser
|
|||
parse_part(@request.query)
|
||||
end
|
||||
|
||||
# Ditto: This needs memoization without the huge AllParamTypes union :|
|
||||
def parse_url_params
|
||||
if @request.url_params
|
||||
url_params = @request.url_params.not_nil!
|
||||
name_table = url_params.regex.name_table
|
||||
url_params.size.times do |i|
|
||||
name = (name_table.fetch(i + 1) { i + 1 }) as String
|
||||
@params[name] = url_params[i + 1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Parses JSON request body if Content-Type is `application/json`.
|
||||
# If request body is a JSON Hash then all the params are parsed and added into `params`.
|
||||
# If request body is a JSON Array it's added into `params` as `_json` and can be accessed
|
||||
|
@ -45,7 +55,6 @@ class Kemal::ParamParser
|
|||
return unless @request.body && @request.headers["Content-Type"]? == APPLICATION_JSON
|
||||
|
||||
body = @request.body as String
|
||||
|
||||
case json = JSON.parse(body).raw
|
||||
when Hash
|
||||
json.each do |k, v|
|
||||
|
@ -63,13 +72,4 @@ class Kemal::ParamParser
|
|||
end
|
||||
end
|
||||
|
||||
def parse_components
|
||||
@route_components.zip(@request_components) do |route_component, req_component|
|
||||
if route_component.starts_with? ':'
|
||||
@params[route_component[1..-1]] = req_component
|
||||
else
|
||||
return nil unless route_component == req_component
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# Opening HTTP::Request to add override_method property
|
||||
class HTTP::Request
|
||||
property override_method
|
||||
property url_params
|
||||
end
|
||||
|
|
|
@ -3,40 +3,17 @@
|
|||
# what action to be done if the route is matched.
|
||||
class Kemal::Route
|
||||
getter handler
|
||||
getter components
|
||||
getter pattern
|
||||
|
||||
def initialize(@method, path, &@handler : Kemal::Context -> _)
|
||||
@components = path.split "/"
|
||||
@pattern = pattern_to_regex path
|
||||
end
|
||||
|
||||
def match?(request)
|
||||
check_for_method_override!(request)
|
||||
return nil unless request.override_method == @method
|
||||
components = request.path.not_nil!.split "/"
|
||||
return nil unless components.size == @components.size
|
||||
@components.zip(components) do |route_component, req_component|
|
||||
unless route_component.starts_with? ':'
|
||||
return nil unless route_component == req_component
|
||||
end
|
||||
private def pattern_to_regex(pattern)
|
||||
pattern = pattern.gsub(/\:(?<param>\w+)/) do |_, match|
|
||||
"(?<#{match["param"]}>.*)"
|
||||
end
|
||||
true
|
||||
Regex.new "^#{pattern}/?$"
|
||||
end
|
||||
|
||||
# Checks if request params contain _method param to override request incoming method
|
||||
def check_for_method_override!(request)
|
||||
request.override_method = request.method
|
||||
if request.method == "POST"
|
||||
params = Kemal::ParamParser.new(self, request).parse_request
|
||||
if params.has_key?("_method") && self.override_method_valid?(params["_method"])
|
||||
request.override_method = params["_method"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Checks if method contained in _method param is valid one
|
||||
def override_method_valid?(override_method)
|
||||
return false unless override_method.is_a?(String)
|
||||
override_method = override_method.upcase
|
||||
return (override_method == "PUT" || override_method == "PATCH" || override_method == "DELETE")
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue