shard-kemal/spec/kemal_handler_spec.cr
Imran Latif d25a611fbd Implemented HTTP HEAD method.
First I tried implementing this solution in such a way that it
explicitly clears body and set `Content-Length` header to body's size.
But for some reason, if I call the URL from cURL then `Content-Length`
header was blank which defeats the very purpose of `HEAD` requests.

I then later anticipated that since `HEAD` would be by-default
implemented by `HTTP::Server` module, there is no need to explicit
clears body and setting `Content-Length` but the way we have written
our previous specs were returning body as well. We could have used some
TestServer kind of thing but if we go to that route we explicitly need
to test non-existent route which I thought would create some
inconsistency among specs.

Crystal has clearly written specs for HEAD requests to make sure body
is not read for them. See
https://github.com/manastech/crystal/commit/acd0b6afb5af438a30529c36b11b
e7954336f23f. I decided to write simple specs which are easy to
maintain in long-run.

We are adding identical HEAD route for every GET route which will make
HEAD requests available for all defined GET requests.

https://github.com/sdogruyol/kemal/issues/19

Added comment for code line which is adding HEAD routes for defined GET routes.
2015-12-04 19:35:14 +05:00

187 lines
5.3 KiB
Crystal

require "./spec_helper"
describe "Kemal::Handler" do
it "routes" do
kemal = Kemal::Handler.new
kemal.add_route "GET", "/" do
"hello"
end
request = HTTP::Request.new("GET", "/")
response = kemal.call(request)
response.body.should eq("hello")
end
it "routes request with query string" do
kemal = Kemal::Handler.new
kemal.add_route "GET", "/" do |env|
"hello #{env.params["message"]}"
end
request = HTTP::Request.new("GET", "/?message=world")
response = kemal.call(request)
response.body.should eq("hello world")
end
it "routes request with multiple query strings" do
kemal = Kemal::Handler.new
kemal.add_route "GET", "/" do |env|
"hello #{env.params["message"]} time #{env.params["time"]}"
end
request = HTTP::Request.new("GET", "/?message=world&time=now")
response = kemal.call(request)
response.body.should eq("hello world time now")
end
it "route parameter has more precedence than query string arguments" do
kemal = Kemal::Handler.new
kemal.add_route "GET", "/:message" do |env|
"hello #{env.params["message"]}"
end
request = HTTP::Request.new("GET", "/world?message=coco")
response = kemal.call(request)
response.body.should eq("hello world")
end
it "parses simple JSON body" do
kemal = Kemal::Handler.new
kemal.add_route "POST", "/" do |env|
name = env.params["name"]
age = env.params["age"]
"Hello #{name} Age #{age}"
end
json_payload = {"name": "Serdar", "age": 26}
request = HTTP::Request.new(
"POST",
"/",
body: json_payload.to_json,
headers: HTTP::Headers{"Content-Type": "application/json"},
)
response = kemal.call(request)
response.body.should eq("Hello Serdar Age 26")
end
it "parses JSON with string array" do
kemal = Kemal::Handler.new
kemal.add_route "POST", "/" do |env|
skills = env.params["skills"] as Array
"Skills #{skills.each.join(',')}"
end
json_payload = {"skills": ["ruby", "crystal"]}
request = HTTP::Request.new(
"POST",
"/",
body: json_payload.to_json,
headers: HTTP::Headers{"Content-Type": "application/json"},
)
response = kemal.call(request)
response.body.should eq("Skills ruby,crystal")
end
it "parses JSON with json object array" do
kemal = Kemal::Handler.new
kemal.add_route "POST", "/" do |env|
skills = env.params["skills"] as Array
skills_from_languages = skills.map do |skill|
skill = skill as Hash
skill["language"]
end
"Skills #{skills_from_languages.each.join(',')}"
end
json_payload = {"skills": [{"language": "ruby"}, {"language": "crystal"}]}
request = HTTP::Request.new(
"POST",
"/",
body: json_payload.to_json,
headers: HTTP::Headers{"Content-Type": "application/json"},
)
response = kemal.call(request)
response.body.should eq("Skills ruby,crystal")
end
it "renders 404 on not found" do
kemal = Kemal::Handler.new
request = HTTP::Request.new("GET", "/?message=world")
response = kemal.call(request)
response.status_code.should eq 404
end
it "renders 500 on exception" do
kemal = Kemal::Handler.new
kemal.add_route "GET", "/" do
raise "Exception"
end
request = HTTP::Request.new("GET", "/?message=world")
response = kemal.call(request)
response.status_code.should eq 500
response.body.includes?("Exception").should eq true
end
it "checks for _method param in POST request to simulate PUT" do
kemal = Kemal::Handler.new
kemal.add_route "PUT", "/", do |env|
"Hello World from PUT"
end
request = HTTP::Request.new(
"POST",
"/",
body: "_method=PUT",
headers: HTTP::Headers{"Content-Type": "application/x-www-form-urlencoded"}
)
response = kemal.call(request)
response.body.should eq("Hello World from PUT")
end
it "checks for _method param in POST request to simulate PATCH" do
kemal = Kemal::Handler.new
kemal.add_route "PATCH", "/", do |env|
"Hello World from PATCH"
end
request = HTTP::Request.new(
"POST",
"/",
body: "_method=PATCH",
headers: HTTP::Headers{"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}
)
response = kemal.call(request)
response.body.should eq("Hello World from PATCH")
end
it "checks for _method param in POST request to simulate DELETE" do
kemal = Kemal::Handler.new
kemal.add_route "DELETE", "/", do |env|
"Hello World from DELETE"
end
json_payload = {"_method": "DELETE"}
request = HTTP::Request.new(
"POST",
"/",
body: json_payload.to_json,
headers: HTTP::Headers{"Content-Type": "application/json"}
)
response = kemal.call(request)
response.body.should eq("Hello World from DELETE")
end
it "can process HTTP HEAD requests for defined GET routes" do
kemal = Kemal::Handler.new
kemal.add_route "GET", "/" do |env|
"Hello World from GET"
end
request = HTTP::Request.new("HEAD", "/")
response = kemal.call(request)
response.status_code.should eq(200)
end
it "can't process HTTP HEAD requests for undefined GET routes" do
kemal = Kemal::Handler.new
request = HTTP::Request.new("HEAD", "/")
response = kemal.call(request)
response.status_code.should eq(404)
end
end