Shaping Responses
Grape provides several ways to control the HTTP response, including setting status codes, headers, cookies, and the response body itself.
HTTP Status Codes
By default, Grape returns a 201 Created
for POST
requests, 204 No Content
for DELETE
requests with no body, and 200 OK
for all others. You can override this using the status
method.
post '/resources' do
status 202 # Accepted
# ...
end
get '/resources' do
if stale?(resource)
status 200
else
status 304 # Not Modified
end
end
You can also use Rack's standard status code symbols:
status :accepted # Equivalent to status 202
status :not_found # Equivalent to status 404
Headers
You can set response headers using the header
method.
get '/resources' do
header 'X-Rate-Limit-Remaining', '4999'
# ...
end
Cookies
Grape provides a simple hash-like interface for managing cookies.
get '/remember' do
cookies[:remember_token] = {
value: 'a-secret-token',
expires: Time.now + 3600,
path: '/',
httponly: true
}
'You are remembered!'
end
delete '/forget' do
cookies.delete(:remember_token, path: '/')
'You are forgotten.'
end
Redirecting
You can perform redirects using the redirect
helper.
get '/old-path' do
# Temporary redirect (302)
redirect '/new-path'
end
get '/ancient-path' do
# Permanent redirect (301)
redirect '/new-path', permanent: true
end
Body Content
By default, the return value of an endpoint block becomes the response body. You can override this with the body
method.
get '/custom-body' do
body 'This is the explicit body.'
'This will be ignored.'
end
To send a response with no body, use body false
. This will also set the status to 204 No Content
.
delete '/resource/:id' do
# ... delete resource ...
body false
end
Sending Files and Streaming
-
sendfile
: To efficiently serve a static file from disk, usesendfile
. This leverages the web server's capabilities (like Nginx'sX-Accel-Redirect
) via theRack::Sendfile
middleware.get '/download' do sendfile '/path/to/large-file.zip' end
-
stream
: For streaming dynamic content or file chunks, use thestream
method. This is useful for large responses that you don't want to load into memory all at once.get '/stream-file' do # Stream a file in chunks stream '/path/to/large-file.csv' end get '/stream-dynamic' do # Stream from an object that responds to `each` stream MyCustomStreamer.new end