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, use sendfile. This leverages the web server's capabilities (like Nginx's X-Accel-Redirect) via the Rack::Sendfile middleware.

    get '/download' do
      sendfile '/path/to/large-file.zip'
    end
  • stream: For streaming dynamic content or file chunks, use the stream 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