The Rack response object is no longer converted to an array by the formatter, enabling streaming. If your custom middleware is accessing @app_response
, update it to expect a Rack::Response
instance instead of an array.
For example,
class CacheBusterMiddleware < Grape::Middleware::Base
def after
@app_response[1]['Expires'] = Time.at(0).utc.to_s
@app_response
end
end
becomes
class CacheBusterMiddleware < Grape::Middleware::Base
def after
@app_response.headers['Expires'] = Time.at(0).utc.to_s
@app_response
end
end
See #1029 for more information.
Using present
with objects that responded to merge
would cause early evaluation of the represented object, with unexpected side-effects, such as missing parameters or environment within rendering code. Grape now only merges represented objects with a previously rendered body, usually when multiple present
calls are made in the same route.
See grape-with-roar#5 and #1023.
Parameters with nil
value will now pass regexp
validation. To disallow nil
value for an endpoint, add allow_blank: false
.
params do
requires :email, allow_blank: false, regexp: /.+@.+/
end
See #957 for more information.
Note: error_response
is being deprecated, not removed.
def error!(message, status = options[:default_status], headers = {}, backtrace = [])
headers = { 'Content-Type' => content_type }.merge(headers)
rack_response(format_message(message, backtrace), status, headers)
end
For example,
error_response({ message: { message: 'No such page.', id: 'missing_page' }, status: 404, headers: { 'Content-Type' => 'api/error' })
becomes
error!({ message: 'No such page.', id: 'missing_page' }, 404, { 'Content-Type' => 'api/error' })
error!
also supports just passing a message. error!('Server error.')
and format: :json
returns the following JSON response
{ 'error': 'Server error. }
with a status code of 500 and a Content Type of text/error.
Optionally, also replace Rack::Response.new
with error!.
The following are equivalent:
Rack::Response.new([ e.message ], 500, { "Content-type" => "text/error" }).finish
error!(e)
See #889 for more information.
Version 0.10.0 has introduced a change via #809 whereas routes no longer got file-type suffixes added if you declared a single API format
. This has been reverted, it's now again possible to call API with proper suffix when single format
is defined:
class API < Grape::API
format :json
get :hello do
{ hello: 'world' }
end
end
Will respond with JSON to /hello
and /hello.json
.
Will respond with 404 to /hello.xml
, /hello.txt
etc.
See the #1001 and #914 for more info.
Grape now supports, but doesn't require Rack 1.6.0. If you encounter an issue with parsing requests larger than 128KB, explictly require Rack 1.6.0 in your Gemfile.
gem 'rack', '~> 1.6.0'
See #559 for more information.
Key route_info is excluded from params.
See #879 for more information.
Callbacks defined in a version block are only called for the routes defined in that block. This was a regression introduced in Grape 0.10.0, and is fixed in this version.
See #901 for more information.
Groups of parameters now require their type to be set explicitly as Array or Hash. Not setting the type now results in MissingGroupTypeError, unsupported type will raise UnsupportedTypeError.
See #886 for more information.
Attributes with nil
values or with values that evaluate to false
are no longer considered missing and will be returned when include_missing
is set to false
.
See #864 for more information.
The following content-types have been removed:
- atom (application/atom+xml)
- rss (application/rss+xml)
- jsonapi (application/jsonapi)
This is because they have never been properly supported.
New block syntax:
Former:
desc "some descs",
detail: 'more details',
entity: API::Entities::Entity,
params: API::Entities::Status.documentation,
named: 'a name',
headers: [XAuthToken: {
description: 'Valdates your identity',
required: true
}
get nil, http_codes: [
[401, 'Unauthorized', API::Entities::BaseError],
[404, 'not found', API::Entities::Error]
] do
Now:
desc "some descs" do
detail 'more details'
params API::Entities::Status.documentation
success API::Entities::Entity
failure [
[401, 'Unauthorized', API::Entities::BaseError],
[404, 'not found', API::Entities::Error]
]
named 'a name'
headers [
XAuthToken: {
description: 'Valdates your identity',
required: true
},
XOptionalHeader: {
description: 'Not really needed',
required: false
}
]
end
A common hack to extend Grape with custom DSL methods was manipulating @last_description
.
module Grape
module Extensions
module SortExtension
def sort(value)
@last_description ||= {}
@last_description[:sort] ||= {}
@last_description[:sort].merge! value
value
end
end
Grape::API.extend self
end
end
You could access this value from within the API with route.route_sort
or, more generally, via env['api.endpoint'].options[:route_options][:sort]
.
This will no longer work, use the documented and supported route_setting
.
module Grape
module Extensions
module SortExtension
def sort(value)
route_setting :sort, sort: value
value
end
end
Grape::API.extend self
end
end
To retrieve this value at runtime from within an API, use env['api.endpoint'].route_setting(:sort)
and when introspecting a mounted API, use route.route_settings[:sort]
.
It used to be possible to fetch an API class variable from a helper function. For example:
@@static_variable = 42
helpers do
def get_static_variable
@@static_variable
end
end
get do
get_static_variable
end
This will no longer work. Use a class method instead of a helper.
@@static_variable = 42
def self.get_static_variable
@@static_variable
end
get do
get_static_variable
end
For more information see #836.
To implement a custom validator, you need to inherit from Grape::Validations::Base
instead of Grape::Validations::Validator
.
For more information see Custom Validators in the documentation.
In previous versions raising Grape::Exceptions::Validation
required a single param
.
raise Grape::Exceptions::Validation, param: :id, message_key: :presence
The param
argument has been deprecated and is now an array of params
, accepting multiple values.
raise Grape::Exceptions::Validation, params: [:id], message_key: :presence
Routes will no longer get file-type suffixes added if you declare a single API format
. For example,
class API < Grape::API
format :json
get :hello do
{ hello: 'world' }
end
end
Pre-0.10.0, this would respond with JSON to /hello
, /hello.json
, /hello.xml
, /hello.txt
, etc.
Now, this will only respond with JSON to /hello
, but will be a 404 when trying to access /hello.json
, /hello.xml
, /hello.txt
, etc.
If you declare further content_type
s, this behavior will be circumvented. For example, the following API will respond with JSON to /hello
, /hello.json
, /hello.xml
, /hello.txt
, etc.
class API < Grape::API
format :json
content_type :json, 'application/json'
get :hello do
{ hello: 'world' }
end
end
See the the updated API Formats documentation and #809 for more info.
Permitted and default parameter values are now only evaluated lazily for each request when declared as a proc. The following code would raise an error at startup time.
params do
optional :v, values: -> { [:x, :y] }, default: -> { :z } }
end
Remove the proc to get the previous behavior.
params do
optional :v, values: [:x, :y], default: :z }
end
See #801 for more information.
If version is used with a block, the callbacks defined within that version block are not scoped to that individual block. In other words, the callback would be inherited by all versions blocks that follow the first one e.g
class API < Grape::API
resource :foo do
version 'v1', :using => :path do
before do
@output ||= 'hello1'
end
get '/' do
@output += '-v1'
end
end
version 'v2', :using => :path do
before do
@output ||= 'hello2'
end
get '/:id' do
@output += '-v2'
end
end
end
end
when making a API call GET /foo/v2/1
, the API would set instance variable @output
to hello1-v2
See #898 for more information.
The following middleware classes have been removed:
Grape::Middleware::Auth::Basic
Grape::Middleware::Auth::Digest
Grape::Middleware::Auth::OAuth2
When you use theses classes directly like:
module API
class Root < Grape::API
class Protected < Grape::API
use Grape::Middleware::Auth::OAuth2,
token_class: 'AccessToken',
parameter: %w(access_token api_key)
you have to replace these classes.
As replacement can be used
Grape::Middleware::Auth::Basic
=>Rack::Auth::Basic
Grape::Middleware::Auth::Digest
=>Rack::Auth::Digest::MD5
Grape::Middleware::Auth::OAuth2
=> warden-oauth2 or rack-oauth2
If this is not possible you can extract the middleware files from grape v0.7.0 and host these files within your application
See #703 for more information.
Assume you have the following exception classes defined.
class ParentError < StandardError; end
class ChildError < ParentError; end
In Grape <= 0.6.1, the rescue_from
keyword only handled the exact exception being raised. The following code would rescue ParentError
, but not ChildError
.
rescue_from ParentError do |e|
# only rescue ParentError
end
This made it impossible to rescue an exception hieararchy, which is a more sensible default. In Grape 0.7.0 or newer, both ParentError
and ChildError
are rescued.
rescue_from ParentError do |e|
# rescue both ParentError and ChildError
end
To only rescue the base exception class, set rescue_subclasses: false
.
rescue_from ParentError, rescue_subclasses: false do |e|
# only rescue ParentError
end
See #544 for more information.
In Grape <= 0.6.1, the default status code returned from error!
was 403.
error! "You may not reticulate this spline!" # yields HTTP error 403
This was a bad default value, since 403 means "Forbidden". Change any call to error!
that does not specify a status code to specify one. The new default value is a more sensible default of 500, which is "Internal Server Error".
error! "You may not reticulate this spline!", 403 # yields HTTP error 403
You may also use default_error_status
to change the global default.
default_error_status 400
See #525 for more information.
In Grape <= 0.6.1, group
, optional
and requires
keywords with a block accepted either an Array
or a Hash
.
params do
requires :id, type: Integer
group :name do
requires :first_name
requires :last_name
end
end
This caused the ambiguity and unexpected errors described in #543.
In Grape 0.7.0, the group
, optional
and requires
keywords take an additional type
attribute which defaults to Array
. This means that without a type
attribute, these nested parameters will no longer accept a single hash, only an array (of hashes).
Whereas in 0.6.1 the API above accepted the following json, it no longer does in 0.7.0.
{
"id": 1,
"name": {
"first_name": "John",
"last_name" : "Doe"
}
}
The params
block should now read as follows.
params do
requires :id, type: Integer
requires :name, type: Hash do
requires :first_name
requires :last_name
end
end
See #545 for more information.
In Grape <= 0.5.0, only the first validation error was raised and processing aborted. Validation errors are now collected and a single Grape::Exceptions::ValidationErrors
exception is raised. You can access the collection of validation errors as .errors
.
rescue_from Grape::Exceptions::Validations do |e|
Rack::Response.new({
status: 422,
message: e.message,
errors: e.errors
}.to_json, 422)
end
For more information see #462.