-
-
Notifications
You must be signed in to change notification settings - Fork 159
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Renderable#data method to be able to respond with IO and String…
… from an Action (#1220) * Added Renderable#data method to be able to respond with IO and String from an Action. * Refactored Lucky::DataResponse to accept data as a String
- Loading branch information
1 parent
bb92bb2
commit 29fa30c
Showing
3 changed files
with
180 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
require "../spec_helper" | ||
|
||
include ContextHelper | ||
|
||
describe Lucky::FileResponse do | ||
describe "#print" do | ||
describe "status_code" do | ||
it "uses the default status if none is set" do | ||
context = build_context | ||
print_data_response(context) | ||
|
||
context.response.status_code.should eq Lucky::TextResponse::DEFAULT_STATUS | ||
end | ||
|
||
it "uses the passed in status" do | ||
context = build_context | ||
print_data_response(context, status: 300) | ||
|
||
context.response.status_code.should eq 300 | ||
end | ||
|
||
it "uses the response status if it's set, and Lucky::TextResponse status is nil" do | ||
context = build_context | ||
context.response.status_code = 300 | ||
print_data_response(context) | ||
|
||
context.response.status_code.should eq 300 | ||
end | ||
end | ||
|
||
describe "content_length" do | ||
it "calculates from a bytesize of the data" do | ||
context = build_context | ||
data = "Lucky is awesome 🤟" | ||
print_data_response(context, data: data) | ||
|
||
context.response.headers["Content-Length"].should eq data.bytesize.to_s | ||
end | ||
end | ||
|
||
describe "content_type" do | ||
it "uses the default content_type when no extension is present" do | ||
context = build_context | ||
print_data_response(context) | ||
|
||
context.response.headers["Content-Type"].should eq "application/octet-stream" | ||
end | ||
|
||
it "uses the provided content_type" do | ||
context = build_context | ||
print_data_response(context, content_type: "text/plain") | ||
|
||
context.response.headers["Content-Type"].should eq "text/plain" | ||
end | ||
end | ||
|
||
describe "disposition" do | ||
it "is 'attachment' by default" do | ||
context = build_context | ||
print_data_response(context) | ||
|
||
context.response.headers["Content-Disposition"].should eq "attachment" | ||
end | ||
|
||
it "can be changed to 'inline'" do | ||
context = build_context | ||
print_data_response(context, disposition: "inline") | ||
|
||
context.response.headers["Content-Disposition"].should eq "inline" | ||
end | ||
|
||
it "can set the downloaded file's name" do | ||
context = build_context | ||
print_data_response(context, filename: "logo.png") | ||
|
||
context.response.headers["Content-Disposition"].should eq %(attachment; filename="logo.png") | ||
end | ||
end | ||
end | ||
end | ||
|
||
private def print_data_response(context : HTTP::Server::Context, | ||
data : String = "Lucky is awesome", | ||
content_type : String = "application/octet-stream", | ||
disposition : String = "attachment", | ||
filename : String? = nil, | ||
status : Int32? = nil) | ||
response = Lucky::DataResponse.new(context, | ||
data, | ||
content_type, | ||
disposition: disposition, | ||
filename: filename, | ||
status: status) | ||
response.print | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# Return a data for the request. | ||
# | ||
# `data` can be used to return contents of the IO as a file to the browser, or | ||
# render the contents of the IO inline to a web browser. Options for the | ||
# method: | ||
# | ||
# * `data` - first argument, _required_. The data that should be sent. | ||
# * `content_type` - defaults to "application/octet-stream". | ||
# * `disposition` - default "attachment" (downloads file), or "inline" | ||
# (renders file in browser). | ||
# * `filename` - default `nil`. When overridden and paired with | ||
# `disposition: "attachment"` this will download file with the provided | ||
# filename. | ||
# * status - `Int32` - the HTTP status code to | ||
# return with. | ||
# | ||
# Examples: | ||
# | ||
# ```crystal | ||
# class Reports::MyReport < ApiAction | ||
# get "/reports/my_report" do | ||
# result = CSV.build do |csv| | ||
# csv.row "one", "two" | ||
# csv.row "three" | ||
# end | ||
|
||
# data result, filename: "my_report.csv" | ||
# end | ||
# end | ||
# ``` | ||
class Lucky::DataResponse < Lucky::Response | ||
DEFAULT_STATUS = 200 | ||
|
||
getter context, data, content_type, filename, debug_message, headers | ||
|
||
def initialize(@context : HTTP::Server::Context, | ||
@data : String, | ||
@content_type : String = "application/octet-stream", | ||
@disposition : String = "attachment", | ||
@filename : String? = nil, | ||
@status : Int32? = nil, | ||
@debug_message : String? = nil) | ||
end | ||
|
||
def print | ||
set_response_headers | ||
context.response.print data | ||
end | ||
|
||
def status : Int | ||
@status || context.response.status_code || DEFAULT_STATUS | ||
end | ||
|
||
private def set_response_headers : Nil | ||
context.response.content_length = data.bytesize | ||
context.response.content_type = content_type | ||
context.response.status_code = status | ||
context.response.headers["Accept-Ranges"] = "bytes" | ||
context.response.headers["X-Content-Type-Options"] = "nosniff" | ||
context.response.headers["Content-Transfer-Encoding"] = "binary" | ||
context.response.headers["Content-Disposition"] = disposition | ||
end | ||
|
||
private def custom_filename? : Bool | ||
!!filename | ||
end | ||
|
||
def disposition : String | ||
if custom_filename? | ||
%(#{@disposition}; filename="#{filename}") | ||
else | ||
@disposition | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters