

葡萄是Ruby的休息狀API框架。它旨在通過提供簡單的DSL來輕鬆開發靜止的API,在機架上運行或補充現有的Web應用程序框架,例如Rail和Sinatra。它具有內置的支持,包括多種格式,子域/前綴限制,內容談判,版本控制等等。
您正在閱讀下一個葡萄版本的文檔,應為2.3.0。當前穩定版本為2.2.0。
作為Tidelift訂閱的一部分可用。
葡萄的維護者正在與Tidelift合作提供商業支持和維護。節省時間,降低風險並改善代碼健康,同時支付葡萄的維護者。單擊此處以獲取更多詳細信息。
Ruby 2.7或需要更新。
葡萄作為寶石可用,以安裝運行:
bundle add grape
Grape API是通過將Grape::API子級創建的機架應用程序。下面是一個簡單的示例,顯示了在重新創建Twitter API的部分中葡萄的一些更常見的特徵。
module Twitter
class API < Grape :: API
version 'v1' , using : :header , vendor : 'twitter'
format :json
prefix :api
helpers do
def current_user
@current_user ||= User . authorize! ( env )
end
def authenticate!
error! ( '401 Unauthorized' , 401 ) unless current_user
end
end
resource :statuses do
desc 'Return a public timeline.'
get :public_timeline do
Status . limit ( 20 )
end
desc 'Return a personal timeline.'
get :home_timeline do
authenticate!
current_user . statuses . limit ( 20 )
end
desc 'Return a status.'
params do
requires :id , type : Integer , desc : 'Status ID.'
end
route_param :id do
get do
Status . find ( params [ :id ] )
end
end
desc 'Create a status.'
params do
requires :status , type : String , desc : 'Your status.'
end
post do
authenticate!
Status . create! ( {
user : current_user ,
text : params [ :status ]
} )
end
desc 'Update a status.'
params do
requires :id , type : String , desc : 'Status ID.'
requires :status , type : String , desc : 'Your status.'
end
put ':id' do
authenticate!
current_user . statuses . find ( params [ :id ] ) . update ( {
user : current_user ,
text : params [ :status ]
} )
end
desc 'Delete a status.'
params do
requires :id , type : String , desc : 'Status ID.'
end
delete ':id' do
authenticate!
current_user . statuses . find ( params [ :id ] ) . destroy
end
end
end
end 葡萄的棄用者將自動將其添加到您的應用程序的棄用器中,例如:grape ,以便將應用程序的配置應用於它。
默認情況下,葡萄會在第一個路線上編譯路由,可以使用compile!方法。
Twitter :: API . compile!可以將其添加到您的config.ru (如果使用radup), application.rb (如果使用導軌)或任何加載服務器的文件。
上面的示例創建了一個機架應用程序,該應用程序可以從rackup config.ru文件中運行:
run Twitter :: API(帶有預加載,您可以使用)
Twitter :: API . compile!
run Twitter :: API並會回應以下路線:
GET /api/statuses/public_timeline
GET /api/statuses/home_timeline
GET /api/statuses/:id
POST /api/statuses
PUT /api/statuses/:id
DELETE /api/statuses/:id
葡萄還將自動響應所有GET的頭部和選項,以及所有其他路線的選擇。
如果您想在Sinatra等另一個機架框架旁邊安裝葡萄,則可以使用Rack::Cascade輕鬆地進行:
# Example config.ru
require 'sinatra'
require 'grape'
class API < Grape :: API
get :hello do
{ hello : 'world' }
end
end
class Web < Sinatra :: Base
get '/' do
'Hello world.'
end
end
use Rack :: Session :: Cookie
run Rack :: Cascade . new [ Web , API ]請注意,使用Rack::Cascade重要的加載應用程序的順序很重要。如果您想從葡萄中引起自定義404錯誤(例如error!('Not Found',404) ),則必須是最後的應用程序。如果葡萄應用程序不是最後一個,並且返回404或405響應,則級聯將其用作信號來嘗試下一個應用程序。這可能會導致不良行為顯示錯誤的應用程序中錯誤的404頁。
將API文件放入app/api中。 Rails期望與Ruby模塊的名稱和與類名稱匹配的文件名匹配的子目錄。在我們的示例中, Twitter::API的文件名位置和目錄應為app/api/twitter/api.rb 。
修改config/routes :
mount Twitter :: API => '/' Rails的默認自動加載器是Zeitwerk 。默認情況下,它將api呈Api而不是API 。為了使我們的示例起作用,您需要在config/initializers/inflections.rb的底部取消分量,然後將API添加為縮寫:
ActiveSupport :: Inflector . inflections ( :en ) do | inflect |
inflect . acronym 'API'
end您可以將多個API實現安裝在另一個API實現中。這些不必是不同的版本,但可能是同一API的組成部分。
class Twitter :: API < Grape :: API
mount Twitter :: APIv1
mount Twitter :: APIv2
end您也可以安裝在路徑上,該路徑類似於安裝API本身內部的prefix 。
class Twitter :: API < Grape :: API
mount Twitter :: APIv1 => '/v1'
end可以在mount之前或之後進行宣言before/after/rescue_from 。無論如何,它們將被繼承。
class Twitter :: API < Grape :: API
before do
header 'X-Base-Header' , 'will be defined for all APIs that are mounted below'
end
rescue_from :all do
error! ( { "error" => "Internal Server Error" } , 500 )
end
mount Twitter :: Users
mount Twitter :: Search
after do
clean_cache!
end
rescue_from ZeroDivisionError do
error! ( { "error" => "Not found" } , 404 )
end
end 您可以將相同的端點安裝在兩個不同的位置。
class Voting :: API < Grape :: API
namespace 'votes' do
get do
# Your logic
end
post do
# Your logic
end
end
end
class Post :: API < Grape :: API
mount Voting :: API
end
class Comment :: API < Grape :: API
mount Voting :: API
end假設帖子和評論端點已安裝在/posts和/comments中,那麼您現在應該能夠get /posts/votes , post /posts/votes , get /comments/votes以及post /comments/votes 。
您可以配置可再生的端點,以根據安裝位置來更改它們的行為方式。
class Voting :: API < Grape :: API
namespace 'votes' do
desc "Vote for your #{ configuration [ :votable ] } "
get do
# Your logic
end
end
end
class Post :: API < Grape :: API
mount Voting :: API , with : { votable : 'posts' }
end
class Comment :: API < Grape :: API
mount Voting :: API , with : { votable : 'comments' }
end請注意,如果您將哈希作為mount的第一個參數,則需要明確地將()圍繞參數放置:
# good
mount ( { :: Some :: Api => '/some/api' } , with : { condition : true } )
# bad
mount :: Some :: Api => '/some/api' , with : { condition : true }您可以訪問類上的configuration (用作動態屬性),內部塊(如名稱空間)
如果您想在configuration上給出的邏輯,則可以使用given助手。
class ConditionalEndpoint :: API < Grape :: API
given configuration [ :some_setting ] do
get 'mount_this_endpoint_conditionally' do
configuration [ :configurable_response ]
end
end
end如果您希望每次安裝端點時運行一大堆邏輯(可以在其中訪問configuration哈希)
class ConditionalEndpoint :: API < Grape :: API
mounted do
YourLogger . info "This API was mounted at: #{ Time . now } "
get configuration [ :endpoint_name ] do
configuration [ :configurable_response ]
end
end
end可以通過使用mounted作為表達式來實現更複雜的結果,在該表達式中,在該表達式中,在該configuration中已經將配置評估為哈希。
class ExpressionEndpointAPI < Grape :: API
get ( mounted { configuration [ :route_name ] || 'default_name' } ) do
# some logic
end
end class BasicAPI < Grape :: API
desc 'Statuses index' do
params : ( configuration [ :entity ] || API :: Entities :: Status ) . documentation
end
params do
requires :all , using : ( configuration [ :entity ] || API :: Entities :: Status ) . documentation
end
get '/statuses' do
statuses = Status . all
type = current_user . admin? ? :full : :default
present statuses , with : ( configuration [ :entity ] || API :: Entities :: Status ) , type : type
end
end
class V1 < Grape :: API
version 'v1'
mount BasicAPI , with : { entity : mounted { configuration [ :entity ] || API :: Entities :: Status } }
end
class V2 < Grape :: API
version 'v2'
mount BasicAPI , with : { entity : mounted { configuration [ :entity ] || API :: Entities :: V2 :: Status } }
end 您可以選擇通過為每個提供的版本建立單獨的Grape::API類,然後將它們集成到主要Grape::API類中,從而提供API的各種版本。確保將較新的版本安裝在較舊版本之前。如果找不到特定版本,則默認版本控制方法將請求引導到後續機架中間件。
require 'v1'
require 'v2'
require 'v3'
class App < Grape :: API
mount V3
mount V2
mount V1
end要維護早期API版本的相同端點而不重寫它們,您可以在以前的API版本中指示多個版本。
class V1 < Grape :: API
version 'v1' , 'v2' , 'v3'
get '/foo' do
# your code for GET /foo
end
get '/other' do
# your code for GET /other
end
end
class V2 < Grape :: API
version 'v2' , 'v3'
get '/var' do
# your code for GET /var
end
end
class V3 < Grape :: API
version 'v3'
get '/foo' do
# your new code for GET /foo
end
end使用提供的示例,隨後的端點將在各種版本中訪問:
GET /v1/foo
GET /v1/other
GET /v2/foo # => Same behavior as v1
GET /v2/other # => Same behavior as v1
GET /v2/var # => New endpoint not available in v1
GET /v3/foo # => Different behavior to v1 and v2
GET /v3/other # => Same behavior as v1 and v2
GET /v3/var # => Same behavior as v2客戶可以在四種策略中達到您的API端點:: :path , :header , :accept_version_header和:param 。默認策略是:path 。
version 'v1' , using : :path使用此版本策略,客戶應在URL中傳遞所需版本。
curl http://localhost:9292/v1/statuses/public_timeline
version 'v1' , using : :header , vendor : 'twitter'當前,葡萄僅以以下格式支持版本的媒體類型:
vnd.vendor-and-or-resource-v1234+format
基本上, -和+之間的所有令牌都將被解釋為版本。
使用此版本策略,客戶應在HTTP Accept Head中傳遞所需版本。
curl -H Accept:application/vnd.twitter-v1+json http://localhost:9292/statuses/public_timeline
默認情況下,當不提供Accept標頭時,使用第一個匹配版本。這種行為類似於導軌中的路由。為了避免這種默認行為,可以使用:strict選項。當此選項設置為true時,當不提供正確的Accept標頭時,將返回406 Not Acceptable錯誤。
當提供無效的Accept標頭時,如果設置為:cascade false返回406 Not Acceptable錯誤。否則,如果沒有其他路由匹配,則架子將返回404 Not Found錯誤。
葡萄將評估接受標頭中包含的相對質量偏好,並在省略時默認為1.0。在下面的示例中
curl -H "Accept: text/xml;q=0.8, application/json;q=0.9" localhost:1234/resource
version 'v1' , using : :accept_version_header使用此版本策略,客戶應通過HTTP Accept-Version標頭傳遞所需版本。
curl -H "Accept-Version:v1" http://localhost:9292/statuses/public_timeline
默認情況下,當不提供Accept-Version標頭時,使用第一個匹配版本。這種行為類似於導軌中的路由。為了避免這種默認行為,可以使用:strict選項。當此選項設置為true時,當不提供正確的Accept標頭時,將返回406 Not Acceptable錯誤,並且:cascade選項設置為false 。否則,如果沒有其他路由匹配,則架子將返回404 Not Found錯誤。
version 'v1' , using : :param使用此版本策略,客戶端應在URL查詢字符串或請求主體中將所需版本作為請求參數傳遞。
curl http://localhost:9292/statuses/public_timeline?apiver=v1
查詢參數的默認名稱為“ apiver”,但可以使用:parameter選項指定。
version 'v1' , using : :param , parameter : 'v' curl http://localhost:9292/statuses/public_timeline?v=v1
您可以將描述添加到API方法和名稱空間。該描述將由葡萄吹牛使用來生成符合宣傳的文檔。
注意:描述塊僅用於文檔,不會影響API行為。
desc 'Returns your public timeline.' do
summary 'summary'
detail 'more details'
params API :: Entities :: Status . documentation
success API :: Entities :: Entity
failure [ [ 401 , 'Unauthorized' , 'Entities::Error' ] ]
default { code : 500 , message : 'InvalidRequest' , model : Entities :: Error }
named 'My named route'
headers XAuthToken : {
description : 'Validates your identity' ,
required : true
} ,
XOptionalHeader : {
description : 'Not really needed' ,
required : false
}
hidden false
deprecated false
is_array true
nickname 'nickname'
produces [ 'application/json' ]
consumes [ 'application/json' ]
tags [ 'tag1' , 'tag2' ]
end
get :public_timeline do
Status . limit ( 20 )
enddetail :更加增強的描述params :直接從Entity定義參數success :(前實體)用於提出此路線成功響應的Entity 。failure :(以前的HTTP_CODES)使用過的故障HTTP代碼和實體的定義。default :用於顯示此路線的默認響應的定義和Entity 。named :一個助手,可以給路由一個名字,並在文檔哈希中找到此名稱headers :用過的標題的定義使用Grape.configure在加載時設置全局設置。當前可配置的設置為:
Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder param_builder要更改設置值,請確保在加載時間在某個時刻運行以下代碼
Grape . configure do | config |
config . setting = value
end例如,對於param_builder ,以下代碼可以在初始化器中運行:
Grape . configure do | config |
config . param_builder = Grape :: Extensions :: Hashie :: Mash :: ParamBuilder
end您還可以配置一個API:
API . configure do | config |
config [ key ] = value
end它將在API內部提供configuration ,就好像它是安裝配置一樣。
請求參數可通過params哈希對象獲得。這包括GET , POST和PUT參數,以及您在路由字符串中指定的任何命名參數。
get :public_timeline do
Status . order ( params [ :sort_by ] )
end參數會自動從POST上的請求主體中填充,並PUT以進行表單輸入,JSON和XML內容類型。
請求:
curl -d '{"text": "140 characters"}' 'http://localhost:9292/statuses' -H Content-Type:application/json -v
葡萄端點:
post '/statuses' do
Status . create! ( text : params [ :text ] )
end多部分帖子和看台也得到了支持。
請求:
curl --form image_file='@image.jpg;type=image/jpg' http://localhost:9292/upload
葡萄端點:
post 'upload' do
# file in params[:image_file]
end在任何一個之間發生衝突的情況下:
GET , POST並PUT參數POST上並PUT路由字符串參數將具有優先級。
默認參數可作為ActiveSupport::HashWithIndifferentAccess提供。可以將其更改為例如Ruby Hash或Hashie::Mash的整個API。
class API < Grape :: API
include Grape :: Extensions :: Hashie :: Mash :: ParamBuilder
params do
optional :color , type : String
end
get do
params . color # instead of params[:color]
end該類也可以使用build_with在單個參數塊上覆蓋,如下所示。
params do
build_with Grape :: Extensions :: Hash :: ParamBuilder
optional :color , type : String
end或全球添加配置Grape.configure.param_builder 。
在上面的示例中, params["color"]將返回nil因為params是普通的Hash 。
可用的參數構建器Grape::Extensions::Hash::ParamBuilder , Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder and Grape and Grape::Extensions::Hashie::Mash::ParamBuilder 。
葡萄允許您僅訪問由您的params塊聲明的參數。它將:
考慮以下API端點:
format :json
post 'users/signup' do
{ 'declared_params' => declared ( params ) }
end如果您沒有指定任何參數, declared將返回一個空哈希。
要求
curl -X POST -H " Content-Type: application/json " localhost:9292/users/signup -d ' {"user": {"first_name":"first name", "last_name": "last name"}} '回覆
{
"declared_params" : {}
}
一旦添加了參數要求,葡萄將僅返迴聲明的參數。
format :json
params do
optional :user , type : Hash do
optional :first_name , type : String
optional :last_name , type : String
end
end
post 'users/signup' do
{ 'declared_params' => declared ( params ) }
end要求
curl -X POST -H " Content-Type: application/json " localhost:9292/users/signup -d ' {"user": {"first_name":"first name", "last_name": "last name", "random": "never shown"}} '回覆
{
"declared_params" : {
"user" : {
"first_name" : " first name " ,
"last_name" : " last name "
}
}
}將包括丟失為類型Hash或Array參數。
format :json
params do
optional :user , type : Hash do
optional :first_name , type : String
optional :last_name , type : String
end
optional :widgets , type : Array
end
post 'users/signup' do
{ 'declared_params' => declared ( params ) }
end要求
curl -X POST -H " Content-Type: application/json " localhost:9292/users/signup -d ' {} '回覆
{
"declared_params" : {
"user" : {
"first_name" : null ,
"last_name" : null
},
"widgets" : []
}
}返回的哈希是ActiveSupport::HashWithIndifferentAccess 。
#declared方法在過濾器before不可用,因為在參數脅迫之前對這些方法進行了評估。
默認情況下, declared(params)包括在所有父名稱空間中定義的參數。如果您只想從當前名稱空間中返回參數,則可以將include_parent_namespaces選項設置為false 。
format :json
namespace :parent do
params do
requires :parent_name , type : String
end
namespace ':parent_name' do
params do
requires :child_name , type : String
end
get ':child_name' do
{
'without_parent_namespaces' => declared ( params , include_parent_namespaces : false ) ,
'with_parent_namespaces' => declared ( params , include_parent_namespaces : true ) ,
}
end
end
end要求
curl -X GET -H " Content-Type: application/json " localhost:9292/parent/foo/bar回覆
{
"without_parent_namespaces" : {
"child_name" : " bar "
},
"with_parent_namespaces" : {
"parent_name" : " foo " ,
"child_name" : " bar "
},
}默認情況下, declared(params)包括具有nil值的參數。如果您只想返回未nil參數,則可以使用include_missing選項。默認情況下, include_missing設置為true 。考慮以下API:
format :json
params do
requires :user , type : Hash do
requires :first_name , type : String
optional :last_name , type : String
end
end
post 'users/signup' do
{ 'declared_params' => declared ( params , include_missing : false ) }
end要求
curl -X POST -H " Content-Type: application/json " localhost:9292/users/signup -d ' {"user": {"first_name":"first name", "random": "never shown"}} 'with include_missing:false
{
"declared_params" : {
"user" : {
"first_name" : " first name "
}
}
}with include_missing:true
{
"declared_params" : {
"user" : {
"first_name" : " first name " ,
"last_name" : null
}
}
}它也適用於嵌套的哈希:
format :json
params do
requires :user , type : Hash do
requires :first_name , type : String
optional :last_name , type : String
requires :address , type : Hash do
requires :city , type : String
optional :region , type : String
end
end
end
post 'users/signup' do
{ 'declared_params' => declared ( params , include_missing : false ) }
end要求
curl -X POST -H " Content-Type: application/json " localhost:9292/users/signup -d ' {"user": {"first_name":"first name", "random": "never shown", "address": { "city": "SF"}}} 'with include_missing:false
{
"declared_params" : {
"user" : {
"first_name" : " first name " ,
"address" : {
"city" : " SF "
}
}
}
}with include_missing:true
{
"declared_params" : {
"user" : {
"first_name" : " first name " ,
"last_name" : null ,
"address" : {
"city" : " Zurich " ,
"region" : null
}
}
}
}請注意,具有nil值的屬性不會丟失,並且當include_missing設置為false時也將返回:
要求
curl -X POST -H " Content-Type: application/json " localhost:9292/users/signup -d ' {"user": {"first_name":"first name", "last_name": null, "address": { "city": "SF"}}} 'with include_missing:false
{
"declared_params" : {
"user" : {
"first_name" : " first name " ,
"last_name" : null ,
"address" : { "city" : " SF " }
}
}
}默認情況下, declared(params)將不會評估given並返回所有參數。使用evaluate_given評估所有given塊,並僅返回given條件下滿足的參數。考慮以下API:
format :json
params do
optional :child_id , type : Integer
given :child_id do
requires :father_id , type : Integer
end
end
post 'child' do
{ 'declared_params' => declared ( params , evaluate_given : true ) }
end要求
curl -X POST -H " Content-Type: application/json " localhost:9292/child -d ' {"father_id": 1} '響應estairuate_given:false
{
"declared_params" : {
"child_id" : null ,
"father_id" : 1
}
}響應estairuate_given:true
{
"declared_params" : {
"child_id" : null
}
}它也適用於嵌套的哈希:
format :json
params do
requires :child , type : Hash do
optional :child_id , type : Integer
given :child_id do
requires :father_id , type : Integer
end
end
end
post 'child' do
{ 'declared_params' => declared ( params , evaluate_given : true ) }
end要求
curl -X POST -H " Content-Type: application/json " localhost:9292/child -d ' {"child": {"father_id": 1}} '響應estairuate_given:false
{
"declared_params" : {
"child" : {
"child_id" : null ,
"father_id" : 1
}
}
}響應estairuate_given:true
{
"declared_params" : {
"child" : {
"child_id" : null
}
}
}使用route_param比定義相同名稱的常規參數具有更高的優先級:
params do
requires :foo , type : String
end
route_param :foo do
get do
{ value : params [ :foo ] }
end
end要求
curl -X POST -H " Content-Type: application/json " localhost:9292/bar -d ' {"foo": "baz"} '回覆
{
"value" : " bar "
}您可以使用params塊為參數定義驗證和脅迫選項。
params do
requires :id , type : Integer
optional :text , type : String , regexp : / A [a-z]+ z /
group :media , type : Hash do
requires :url
end
optional :audio , type : Hash do
requires :format , type : Symbol , values : [ :mp3 , :wav , :aac , :ogg ] , default : :mp3
end
mutually_exclusive :media , :audio
end
put ':id' do
# params[:id] is an Integer
end指定類型後,將在強制後完成隱式驗證,以確保輸出類型是聲明的類型。
可選參數可以具有默認值。
params do
optional :color , type : String , default : 'blue'
optional :random_number , type : Integer , default : -> { Random . rand ( 1 .. 100 ) }
optional :non_random_number , type : Integer , default : Random . rand ( 1 .. 100 )
end熱切評估默認值。上圖:non_random_number將對每個params的端點進行評估。要使默認情況下,每個請求都會懶惰地使用lambda,例如:random_number 。
請注意,默認值將傳遞到指定的任何驗證選項。如果沒有明確提供:color以下示例將始終失敗。
params do
optional :color , type : String , default : 'blue' , values : [ 'red' , 'green' ]
end正確的實現是確保默認值通過所有驗證。
params do
optional :color , type : String , default : 'blue' , values : [ 'blue' , 'red' , 'green' ]
end您可以將一個參數的值用作其他參數的默認值。在這種情況下,如果未提供primary_color參數,則其值與color相同。如果他們兩個都沒有提供,則兩個都將具有blue價值。
params do
optional :color , type : String , default : 'blue'
optional :primary_color , type : String , default : -> ( params ) { params [ :color ] }
end以下都是有效類型,由葡萄支撐在開箱即用:
File )請注意,Ruby 2.4和更早版本之間的行為不同。在Ruby 2.4中,由數字組成的值轉換為整數,但在早期版本中,它將被視為fixnum。
params do
requires :integers , type : Hash do
requires :int , coerce : Integer
end
end
get '/int' do
params [ :integers ] [ :int ] . class
end
. ..
get '/int' integers : { int : '45' }
#=> Integer in ruby 2.4
#=> Fixnum in earlier ruby versions除了上面列出的默認類型類型外,只要提供明確的脅迫方法,任何類都可以用作類型。如果該類型實現了類級parse方法,則葡萄將自動使用它。此方法必須採用一個字符串參數並返回正確類型的實例,或返回Grape::Types::InvalidValue的實例,該實例可選地接受響應中要返回的消息。
class Color
attr_reader :value
def initialize ( color )
@value = color
end
def self . parse ( value )
return new ( value ) if %w[ blue red green ] . include? ( value )
Grape :: Types :: InvalidValue . new ( 'Unsupported color' )
end
end
params do
requires :color , type : Color , default : Color . new ( 'blue' )
requires :more_colors , type : Array [ Color ] # Collections work
optional :unique_colors , type : Set [ Color ] # Duplicates discarded
end
get '/stuff' do
# params[:color] is already a Color.
params [ :color ] . value
end另外,可以使用coerce_with提供自定義脅迫方法。可以按照優先順序給出任何類或對象,以實現parse或call方法。該方法必須接受單個字符串參數,並且返回值必須與給定type匹配。
params do
requires :passwd , type : String , coerce_with : Base64 . method ( :decode64 )
requires :loud_color , type : Color , coerce_with : -> ( c ) { Color . parse ( c . downcase ) }
requires :obj , type : Hash , coerce_with : JSON do
requires :words , type : Array [ String ] , coerce_with : -> ( val ) { val . split ( / s +/ ) }
optional :time , type : Time , coerce_with : Chronic
end
end請注意, nil值將調用自定義脅迫方法,而丟失的參數則不會。
使用lambda(也可以使用帶有parse方法的類)使用coerce_with的示例,它將解析一個字符串並返回整數數組,與Array[Integer] type匹配。
params do
requires :values , type : Array [ Integer ] , coerce_with : -> ( val ) { val . split ( / s +/ ) . map ( & :to_i ) }
end葡萄會斷言,強制值與給定type匹配,如果不這樣做,則會拒絕請求。為了覆蓋這種行為,自定義類型可以實現parsed?如果值通過類型驗證,則應接受單個參數並返回true方法。
class SecureUri
def self . parse ( value )
URI . parse value
end
def self . parsed? ( value )
value . is_a? URI :: HTTPS
end
end
params do
requires :secure_uri , type : SecureUri
end葡萄利用Rack::Request對多部分文件參數的內置支持。可以使用type: File :
params do
requires :avatar , type : File
end
post '/' do
params [ :avatar ] [ :filename ] # => 'avatar.png'
params [ :avatar ] [ :type ] # => 'image/png'
params [ :avatar ] [ :tempfile ] # => #<File>
endJSON類型使用特殊type: JSON聲明,葡萄支持以JSON形式的字符串給出的複雜參數。 JSON對象和對象的數組被平等地接受,在任何一種情況下,都將嵌套驗證規則應用於所有對象:
params do
requires :json , type : JSON do
requires :int , type : Integer , values : [ 1 , 2 , 3 ]
end
end
get '/' do
params [ :json ] . inspect
end
client . get ( '/' , json : '{"int":1}' ) # => "{:int=>1}"
client . get ( '/' , json : '[{"int":"1"}]' ) # => "[{:int=>1}]"
client . get ( '/' , json : '{"int":4}' ) # => HTTP 400
client . get ( '/' , json : '[{"int":4}]' ) # => HTTP 400另外type: Array[JSON] ,該數組將參數明確標記為對像數組。如果提供了一個對象,它將被包裝。
params do
requires :json , type : Array [ JSON ] do
requires :int , type : Integer
end
end
get '/' do
params [ :json ] . each { | obj | ... } # always works
end對於可能提供的JSON結構類型的更嚴格的控制,請使用type: Array, coerce_with: JSON或type: Hash, coerce_with: JSON 。
可以使用types選項而不是type來聲明變體類型參數:
params do
requires :status_code , types : [ Integer , String , Array [ Integer , String ] ]
end
get '/' do
params [ :status_code ] . inspect
end
client . get ( '/' , status_code : 'OK_GOOD' ) # => "OK_GOOD"
client . get ( '/' , status_code : 300 ) # => 300
client . get ( '/' , status_code : %w( 404 NOT FOUND ) ) # => [404, "NOT", "FOUND"]作為一種特殊情況,可以通過傳遞多個成員以上的成員來type的Set或Array來宣布變體式式收集:
params do
requires :status_codes , type : Array [ Integer , String ]
end
get '/' do
params [ :status_codes ] . inspect
end
client . get ( '/' , status_codes : %w( 1 two ) ) # => [1, "two"]參數可以使用group嵌套,也可以通過調用requires或optional塊。在上面的示例中,這意味著params[:media][:url]以及params[:id]和params[:audio][:format]僅在存在params[:audio]時才需要。使用塊, group , requires和optional可以接受其他選項type ,該選項類型可以是Array或Hash ,並且默認為Array 。根據值的不同,嵌套參數將被視為哈希的值或數組中的哈希值。
params do
optional :preferences , type : Array do
requires :key
requires :value
end
requires :name , type : Hash do
requires :first_name
requires :last_name
end
end假設您的某些參數僅在給出其他參數時才相關;葡萄使您可以通過參數塊中的given方法表達這種關係,例如:
params do
optional :shelf_id , type : Integer
given :shelf_id do
requires :bin_id , type : Integer
end
end在上面的示例中,葡萄會使用blank?檢查是否存在shelf_id參數。
given還使用自定義代碼的Proc 。下面,僅當category的值foo時,才需要參數description :
params do
optional :category
given category : -> ( val ) { val == 'foo' } do
requires :description
end
end您可以重命名參數:
params do
optional :category , as : :type
given type : -> ( val ) { val == 'foo' } do
requires :description
end
end注意: given參數應為重命名。在示例中,它應該是type ,而不是category 。
可以將參數選項分組。如果要為多個參數提取常見驗證或類型,則可能有用。在這些組中,各個參數可以擴展或選擇性地覆蓋共同的設置,從而使您可以在小組級別維護默認設置,同時在必要時仍在應用特定於參數的規則。
下面的示例顯示了參數共享共同選項時的典型情況。
params do
requires :first_name , type : String , regexp : /w+/ , desc : 'First name' , documentation : { in : 'body' }
optional :middle_name , type : String , regexp : /w+/ , desc : 'Middle name' , documentation : { in : 'body' , x : { nullable : true } }
requires :last_name , type : String , regexp : /w+/ , desc : 'Last name' , documentation : { in : 'body' }
end葡萄使您可以通過參數塊中的with呈現相同的邏輯,例如:
params do
with ( type : String , regexp : /w+/ , documentation : { in : 'body' } ) do
requires :first_name , desc : 'First name'
optional :middle_name , desc : 'Middle name' , documentation : { x : { nullable : true } }
requires :last_name , desc : 'Last name'
end
end您可以使用嵌套的“ with'塊將設置整體組織為層。每個層都可以使用,添加或更改其上方圖層的設置。這有助於保持複雜的參數組織和一致,同時仍允許進行特定的自定義。
params do
with ( documentation : { in : 'body' } ) do # Applies documentation to all nested parameters
with ( type : String , regexp : / w +/ ) do # Applies type and validation to names
requires :first_name , desc : 'First name'
requires :last_name , desc : 'Last name'
end
optional :age , type : Integer , desc : 'Age' , documentation : { x : { nullable : true } } # Specific settings for 'age'
end
end您可以使用as重命名參數,當重構現有API時,這很有用:
resource :users do
params do
requires :email_address , as : :email
requires :password
end
post do
User . create! ( declared ( params ) ) # User takes email and password
end
end呼叫declared(params)時將傳遞的值將as關鍵。
allow_blank參數可以定義為allow_blank ,以確保它們包含一個值。默認情況下,只requires驗證是否在請求中發送了一個參數,無論其值如何。使用allow_blank: false ,空值或空格值僅無效。
allow_blank可以與requires和optional 。如果需要參數,則必須包含一個值。如果是可選的,則可以不在請求中發送它,但是如果它發送,則必須具有一定的值,而不是一個空的字符串/只有空格。
params do
requires :username , allow_blank : false
optional :first_name , allow_blank : false
end values參數可以僅限於具有:values選項的特定值集。
params do
requires :status , type : Symbol , values : [ :not_started , :processing , :done ]
optional :numbers , type : Array [ Integer ] , default : 1 , values : [ 1 , 2 , 3 , 5 , 8 ]
end向:values選項提供一個範圍可確保該範圍內包含參數(或參數)(使用Range#include? )。
params do
requires :latitude , type : Float , values : - 90.0 ..+ 90.0
requires :longitude , type : Float , values : - 180.0 ..+ 180.0
optional :letters , type : Array [ String ] , values : 'a' .. 'z'
end請注意,無盡的範圍還用ActiveSupport> = 6.0支持,但它們要求提供類型。
params do
requires :minimum , type : Integer , values : 10 ..
optional :maximum , type : Integer , values : .. 10
end請注意,兩個範圍端點都必須是#kind_of?您的:type選項(如果您不提供:type選項,它將被猜測為等於範圍的第一個端點的類)。因此以下是無效的:
params do
requires :invalid1 , type : Float , values : 0 .. 10 # 0.kind_of?(Float) => false
optional :invalid2 , values : 0 .. 10.0 # 10.0.kind_of?(0.class) => false
end :values選項也可以與Proc一起提供,並通過每個請求懶惰地評估。如果PROC具有零(即不需要參數),則應返回列表或範圍,然後將其用於驗證參數。
例如,給定狀態模型,您可能需要通過先前在HashTag模型中定義的主題標籤來限制。
params do
requires :hashtag , type : String , values : -> { Hashtag . all . map ( & :tag ) }
end另外,可以使用具有ARITY ONE的PROC(即一個參數)來明確驗證每個參數值。在這種情況下,如果參數值有效,則預期PROC將返回真實值。如果PROC返回虛假值或升級標準詞,則該參數將被視為無效。
params do
requires :number , type : Integer , values : -> ( v ) { v . even? && v < 25 }
end儘管Procs在單個情況下方便,但在使用驗證不止一次的情況下,請考慮使用自定義驗證器。
請注意,允許_blank驗證器在使用時應用:values 。在下面的示例中,沒有以下內容:allow_blank不會阻止:state接收空白值是因為:allow_blank默認為true 。
params do
requires :state , type : Symbol , values : [ :active , :inactive ]
end except_values參數可以限制在具有:except_values操作的特定值集中。
except_values驗證器的行為與values驗證器相似,因為它接受數組,範圍或proc。但是,與values驗證器不同, except_values僅接受零零的procs。
params do
requires :browser , except_values : [ 'ie6' , 'ie7' , 'ie8' ]
requires :port , except_values : { value : 0 .. 1024 , message : 'is not allowed' }
requires :hashtag , except_values : -> { Hashtag . FORBIDDEN_LIST }
end same_as可以給出一個same_as選項,以確保參數值匹配。
params do
requires :password
requires :password_confirmation , same_as : :password
end length具有支持#length方法的類型的參數可以限制為具有:length選項的特定長度。
驗證器接受:min或:max或兩個選項或僅兩個選項:is驗證參數的值是否在給定限制範圍內。
params do
requires :code , type : String , length : { is : 2 }
requires :str , type : String , length : { min : 3 }
requires :list , type : [ Integer ] , length : { min : 3 , max : 5 }
requires :hash , type : Hash , length : { max : 5 }
end regexp參數可以限制以將特定的正則表達式與:regexp選項匹配。如果該值與正則表達式不匹配,則將返回錯誤。請注意,對於requires和optional參數都是正確的。
params do
requires :email , regexp : /.+@.+/
end如果參數是沒有值的,則驗證器將通過。為了確保參數包含一個值,請使用allow_blank: false 。
params do
requires :email , allow_blank : false , regexp : /.+@.+/
end mutually_exclusive參數可以定義為mutually_exclusive ,以確保其在請求中不同時存在。
params do
optional :beer
optional :wine
mutually_exclusive :beer , :wine
end可以定義多個集:
params do
optional :beer
optional :wine
mutually_exclusive :beer , :wine
optional :scotch
optional :aquavit
mutually_exclusive :scotch , :aquavit
end警告:切勿使用任何必需的參數定義互斥集。兩個相互排斥的參數將意味著參數永遠不會有效,從而使終點無用。帶有可選參數的必需參數互斥將意味著後者永遠不會有效。
exactly_one_of參數可以定義為“恰好_one_of”,以確保選擇一個參數。
params do
optional :beer
optional :wine
exactly_one_of :beer , :wine
end請注意,使用:default使用mutually_exclusive的默認值將導致多個參數始終具有默認值並引起Grape::Exceptions::Validation互斥異常。
at_least_one_of參數可以定義為“ at_least_one_of”,以確保至少選擇一個參數。
params do
optional :beer
optional :wine
optional :juice
at_least_one_of :beer , :wine , :juice
end all_or_none_of參數可以定義為“ all_or_none_of”,以確保選擇所有參數。
params do
optional :beer
optional :wine
optional :juice
all_or_none_of :beer , :wine , :juice
end mutually_exclusive , exactly_one_of , at_least_one_of , all_or_none_of所有這些方法都可以在任何嵌套級別使用。
params do
requires :food , type : Hash do
optional :meat
optional :fish
optional :rice
at_least_one_of :meat , :fish , :rice
end
group :drink , type : Hash do
optional :beer
optional :wine
optional :juice
exactly_one_of :beer , :wine , :juice
end
optional :dessert , type : Hash do
optional :cake
optional :icecream
mutually_exclusive :cake , :icecream
end
optional :recipe , type : Hash do
optional :oil
optional :meat
all_or_none_of :oil , :meat
end
end名稱空間允許參數定義,並應用於名稱空間中的每個方法。
namespace :statuses do
params do
requires :user_id , type : Integer , desc : 'A user ID.'
end
namespace ':user_id' do
desc "Retrieve a user's status."
params do
requires :status_id , type : Integer , desc : 'A status ID.'
end
get ':status_id' do
User . find ( params [ :user_id ] ) . statuses . find ( params [ :status_id ] )
end
end
end namespace方法具有許多別名,包括: group , resource , resources和segment 。使用最適合您的API的內容。
您可以使用route_param方便地將路由參數定義為命名空間。
namespace :statuses do
route_param :id do
desc 'Returns all replies for a status.'
get 'replies' do
Status . find ( params [ :id ] ) . replies
end
desc 'Returns a status.'
get do
Status . find ( params [ :id ] )
end
end
end您還可以通過傳遞到route_param的選項來定義路由參數類型。
namespace :arithmetic do
route_param :n , type : Integer do
desc 'Returns in power'
get 'power' do
params [ :n ] ** params [ :n ]
end
end
end class AlphaNumeric < Grape :: Validations :: Validators :: Base
def validate_param! ( attr_name , params )
unless params [ attr_name ] =~ / A [[:alnum:]]+ z /
raise Grape :: Exceptions :: Validation . new params : [ @scope . full_name ( attr_name ) ] , message : 'must consist of alpha-numeric characters'
end
end
end params do
requires :text , alpha_numeric : true
end您還可以創建使用參數的自定義類。
class Length < Grape :: Validations :: Validators :: Base
def validate_param! ( attr_name , params )
unless params [ attr_name ] . length <= @option
raise Grape :: Exceptions :: Validation . new params : [ @scope . full_name ( attr_name ) ] , message : "must be at the most #{ @option } characters long"
end
end
end params do
requires :text , length : 140
end您還可以創建使用請求來驗證屬性的自定義驗證。例如,如果您想擁有僅適用於管理員的參數,則可以執行以下操作。
class Admin < Grape :: Validations :: Validators :: Base
def validate ( request )
# return if the param we are checking was not in request
# @attrs is a list containing the attribute we are currently validating
# in our sample case this method once will get called with
# @attrs being [:admin_field] and once with @attrs being [:admin_false_field]
return unless request . params . key? ( @attrs . first )
# check if admin flag is set to true
return unless @option
# check if user is admin or not
# as an example get a token from request and check if it's admin or not
raise Grape :: Exceptions :: Validation . new params : @attrs , message : 'Can not set admin-only field.' unless request . headers [ 'X-Access-Token' ] == 'admin'
end
end並在您的端點定義中使用它為:
params do
optional :admin_field , type : String , admin : true
optional :non_admin_field , type : String
optional :admin_false_field , type : String , admin : false
end每個驗證都將擁有自己的驗證器實例,這意味著驗證器可以具有狀態。
收集了驗證和脅迫錯誤,並提出了Grape::Exceptions::ValidationErrors 。如果異常被殺死,它將以400個狀態和錯誤消息響應。驗證錯誤按參數名稱分組,可以通過Grape::Exceptions::ValidationErrors#errors訪問。
在下面的示例中,來自Grape::Exceptions::ValidationErrors是人類可讀的弦,例如“啤酒,葡萄酒相互排斥”。
params do
optional :beer
optional :wine
optional :juice
exactly_one_of :beer , :wine , :juice
end您可以挽救Grape::Exceptions::ValidationErrors ,並以自定義響應響應,或將響應轉換為將單個參數和相應錯誤消息分開的JSON API的良好的JSON。以下rescue_from示例產生[{"params":["beer","wine"],"messages":["are mutually exclusive"]}] 。
format :json
subject . rescue_from Grape :: Exceptions :: ValidationErrors do | e |
error! e , 400
end Grape::Exceptions::ValidationErrors#full_messages將驗證消息返回作為數組。 Grape::Exceptions::ValidationErrors#message將消息連接到一個字符串。
對於響應一系列驗證消息,您可以使用Grape::Exceptions::ValidationErrors#full_messages 。
format :json
subject . rescue_from Grape :: Exceptions :: ValidationErrors do | e |
error! ( { messages : e . full_messages } , 400 )
end葡萄返回默認情況下發現的所有驗證和強制錯誤。要跳過所有後續驗證檢查當發現特定參數無效時,請使用fail_fast: true 。
下面的示例將無法檢查是否存在:wine除非找到:beer 。
params do
required :beer , fail_fast : true
required :wine
end空參數的結果將是單個Grape::Exceptions::ValidationErrors錯誤。
同樣,如果以下示例中:blah為空白,則不會執行正則表達測試。
params do
required :blah , allow_blank : false , regexp : /blah/ , fail_fast : true
end葡萄支持與參數相關的錯誤消息的I18N,但是如果未提供默認場所的翻譯,則將退縮到英語。有關消息鍵,請參見En.yml。
如果您的應用程序僅執行可用的環境,並且:EN不包含在您的可用語言環境中,則葡萄不能返回英語,並且會返迴轉換鍵以獲取錯誤消息。為了避免這種行為,要么為您的默認場所提供翻譯,要么在可用的地區添加:en。
葡萄支持與參數相關和與強制相關的錯誤消息的自定義驗證消息。
presence , allow_blank , values , regexp params do
requires :name , values : { value : 1 .. 10 , message : 'not in range from 1 to 10' } , allow_blank : { value : false , message : 'cannot be blank' } , regexp : { value : /^[a-z]+$/ , message : 'format is invalid' } , message : 'is required'
end same_as params do
requires :password
requires :password_confirmation , same_as : { value : :password , message : 'not match' }
end length params do
requires :code , type : String , length : { is : 2 , message : 'code is expected to be exactly 2 characters long' }
requires :str , type : String , length : { min : 5 , message : 'str is expected to be atleast 5 characters long' }
requires :list , type : [ Integer ] , length : { min : 2 , max : 3 , message : 'list is expected to have between 2 and 3 elements' }
end all_or_none_of params do
optional :beer
optional :wine
optional :juice
all_or_none_of :beer , :wine , :juice , message : "all params are required or none is required"
end mutually_exclusive params do
optional :beer
optional :wine
optional :juice
mutually_exclusive :beer , :wine , :juice , message : "are mutually exclusive cannot pass both params"
end exactly_one_of params do
optional :beer
optional :wine
optional :juice
exactly_one_of :beer , :wine , :juice , message : { exactly_one : "are missing, exactly one parameter is required" , mutual_exclusion : "are mutually exclusive, exactly one parameter is required" }
end at_least_one_of params do
optional :beer
optional :wine
optional :juice
at_least_one_of :beer , :wine , :juice , message : "are missing, please specify at least one param"
end Coerce params do
requires :int , type : { value : Integer , message : "type cast is invalid" }
end With Lambdas params do
requires :name , values : { value : -> { ( 1 .. 10 ) . to_a } , message : 'not in range from 1 to 10' }
end Pass symbols for i18n translations如果您想要自定義驗證消息的I18N翻譯,則可以傳遞符號。
params do
requires :name , message : :name_required
end # en.yml
en :
grape :
errors :
format : ! '%{attributes} %{message}'
messages :
name_required : 'must be present' 您還可以覆蓋屬性名稱。
# en.yml
en :
grape :
errors :
format : ! '%{attributes} %{message}'
messages :
name_required : 'must be present'
attributes :
name : 'Oops! Name'會產生'哎呀!名稱必須在場'
您無法為默認值設置自定義消息選項,因為它需要Interpolation %{option1}: %{value1} is incompatible with %{option2}: %{value2} 。您可以通過更改en.yml內部的incompatible_option_values消息鍵來更改默認錯誤消息的默認錯誤消息
params do
requires :name , values : { value : -> { ( 1 .. 10 ) . to_a } , message : 'not in range from 1 to 10' } , default : 5
enddry-validation或dry-schema作為上述params DSL的替代方法,您可以使用模式或dry-validation合同來描述端點的參數。如果您已經在應用程序的其他某些部分中使用了上述內容,這可能特別有用。如果沒有,您需要在您的Gemfile中添加dry-validation或dry-schema 。
然後使用以前定義的合同或模式致電contract :
CreateOrdersSchema = Dry :: Schema . Params do
required ( :orders ) . array ( :hash ) do
required ( :name ) . filled ( :string )
optional ( :volume ) . maybe ( :integer , lt? : 9 )
end
end
# ...
contract CreateOrdersSchema或使用塊,使用架構定義語法:
contract do
required ( :orders ) . array ( :hash ) do
required ( :name ) . filled ( :string )
optional ( :volume ) . maybe ( :integer , lt? : 9 )
end
end後者將定義一個脅迫架構( Dry::Schema.Params )。使用以前的方法時,由您決定輸入是否需要脅迫。
params contract也可以在同一API中一起使用,例如描述端點嵌套名稱空間的不同部分。
請求標題可通過headers助手或env以其原始形式提供。
get do
error! ( 'Unauthorized' , 401 ) unless headers [ 'Secret-Password' ] == 'swordfish'
end get do
error! ( 'Unauthorized' , 401 ) unless env [ 'HTTP_SECRET_PASSWORD' ] == 'swordfish'
end 上面的示例可能已被要求如下:
curl -H " secret_PassWord: swordfish " ...標題名稱將為您標準化。
header輔助名稱中,將被脅迫為secret-password 。header輔助名稱中,將被強制為大寫的烤肉箱案件作為Secret-PassWord 。env集合中,它們出現在所有大寫,在蛇案中,並以HTTP_SECRET_PASSWORD為前綴'http_'根據RFC2616第4.2節中定義的HTTP標準,標題名稱將被歸一化,無論客戶端發送了什麼。
您可以在API中設置帶有header的響應標頭。
header 'X-Robots-Tag' , 'noindex'提出error! ,通過其他標題作為參數。在error!稱呼。
error! 'Unauthorized' , 401 , 'X-Error-Detail' => 'Invalid token.' 要定義路由,您可以將route方法或速記用於HTTP動詞。定義接受任何設置為:any路由的路由。用結腸表示的路徑的一部分將被解釋為路由參數。
route :get , 'status' do
end
# is the same as
get 'status' do
end
# is the same as
get :status do
end
# is NOT the same as
get ':status' do # this makes params[:status] available
end
# This will make both params[:status_id] and params[:id] available
get 'statuses/:status_id/reviews/:id' do
end要聲明一個名稱空間,該命名空間前綴在內部所有路由中,請使用namespace方法。 group , resource , resources和segment是此方法的別名。內部的任何端點都將共享其父上下文以及在命名空間上下文中完成的任何配置。
route_param方法是定義參數路由段的方便方法。如果定義類型,它將為此參數添加驗證。
route_param :id , type : Integer do
get 'status' do
end
end
# is the same as
namespace ':id' do
params do
requires :id , type : Integer
end
get 'status' do
end
end可選地,您可以使用名稱空間或端點上的正則表達式來定義命名路由參數的要求。僅當滿足所有要求時,該路線才會匹配。
get ':id' , requirements : { id : /[0-9]*/ } do
Status . find ( params [ :id ] )
end
namespace :outer , requirements : { id : /[0-9]*/ } do
get :id do
end
get ':id/edit' do
end
end 您可以通過給出一個塊或一個模塊數組來定義端點可以與helpers宏一起使用的輔助方法。
module StatusHelpers
def user_info ( user )
" #{ user } has statused #{ user . statuses } status(s)"
end
end
module HttpCodesHelpers
def unauthorized
401
end
end
class API < Grape :: API
# define helpers with a block
helpers do
def current_user
User . find ( params [ :user_id ] )
end
end
# or mix in an array of modules
helpers StatusHelpers , HttpCodesHelpers
before do
error! ( 'Access Denied' , unauthorized ) unless current_user
end
get 'info' do
# helpers available in your endpoint and filters
user_info ( current_user )
end
end您可以使用helpers定義可重複使用的params 。
class API < Grape :: API
helpers do
params :pagination do
optional :page , type : Integer
optional :per_page , type : Integer
end
end
desc 'Get collection'
params do
use :pagination # aliases: includes, use_scope
end
get do
Collection . page ( params [ :page ] ) . per ( params [ :per_page ] )
end
end您還可以使用共享幫助者定義可重複使用的params 。
module SharedParams
extend Grape :: API :: Helpers
params :period do
optional :start_date
optional :end_date
end
params :pagination do
optional :page , type : Integer
optional :per_page , type : Integer
end
end
class API < Grape :: API
helpers SharedParams
desc 'Get collection.'
params do
use :period , :pagination
end
get do
Collection
. from ( params [ :start_date ] )
. to ( params [ :end_date ] )
. page ( params [ :page ] )
. per ( params [ :per_page ] )
end
end幫助者支持可以幫助設置默認值的塊。以下API可以按asc或desc順序返回按id或created_at排序的集合。
module SharedParams
extend Grape :: API :: Helpers
params :order do | options |
optional :order_by , type : Symbol , values : options [ :order_by ] , default : options [ :default_order_by ]
optional :order , type : Symbol , values : %i( asc desc ) , default : options [ :default_order ]
end
end
class API < Grape :: API
helpers SharedParams
desc 'Get a sorted collection.'
params do
use :order , order_by : %i( id created_at ) , default_order_by : :created_at , default_order : :asc
end
get do
Collection . send ( params [ :order ] , params [ :order_by ] )
end
end 如果您需要在端點內生成路徑的方法,請參閱葡萄圈螺旋槳寶石。
您可以使用documentation哈希附加附加文檔到params 。
params do
optional :first_name , type : String , documentation : { example : 'Jim' }
requires :last_name , type : String , documentation : { example : 'Smith' }
end如果不需要文檔(例如,它是內部API),則可以禁用文檔。
class API < Grape :: API
do_not_document!
# endpoints...
end在這種情況下,葡萄不會創建與文檔有關的對象,這些對象永遠保留在RAM中。
您可以簡單地使用cookies方法設置,獲取和刪除cookie。
class API < Grape :: API
get 'status_count' do
cookies [ :status_count ] ||= 0
cookies [ :status_count ] += 1
{ status_count : cookies [ :status_count ] }
end
delete 'status_count' do
{ status_count : cookies . delete ( :status_count ) }
end
end使用基於哈希的語法設置多個值。
cookies [ :status_count ] = {
value : 0 ,
expires : Time . tomorrow ,
domain : '.twitter.com' ,
path : '/'
}
cookies [ :status_count ] [ :value ] += 1刪除帶delete cookie。
cookies . delete :status_count指定可選路徑。
cookies . delete :status_count , path : '/' 默認情況下,葡萄返回了POST - 要求的201, DELETE要求的204,不返回任何內容,以及所有其他請求的200個狀態代碼。您可以使用status查詢並設置實際的HTTP狀態代碼
post do
status 202
if status == 200
# do some thing
end
end您還可以使用機架util提供的狀態代碼符號之一
post do
status :no_content
end 您可以暫時重定向到新的URL(302)或永久性(301)。
redirect '/statuses' redirect '/statuses' , permanent : true 您可以識別與給定路徑匹配的端點。
此API返回一個Grape::Endpoint的實例。
class API < Grape :: API
get '/statuses' do
end
end
API . recognize_path '/statuses'由於版本2.1.0 ,因此recognize_path方法考慮了參數類型,以確定哪個端點應與給定路徑匹配。
class Books < Grape :: API
resource :books do
route_param :id , type : Integer do
# GET /books/:id
get do
#...
end
end
resource :share do
# POST /books/share
post do
# ....
end
end
end
end
API . recognize_path '/books/1' # => /books/:id
API . recognize_path '/books/share' # => /books/share
API . recognize_path '/books/other' # => nil 當您添加資源的GET路由時,還將自動添加HEAD方法的路由。您可以使用do_not_route_head! 。
class API < Grape :: API
do_not_route_head!
get '/example' do
# only responds to GET
end
end當您添加資源的路由時,還將添加OPTIONS方法的路由。對選項請求的響應將包括一個“允許”標頭列表所支持的方法。如果資源具有回調before和after ,它們將被執行,但是沒有其他回調將運行。
class API < Grape :: API
get '/rt_count' do
{ rt_count : current_user . rt_count }
end
params do
requires :value , type : Integer , desc : 'Value to add to the rt count.'
end
put '/rt_count' do
current_user . rt_count += params [ :value ] . to_i
{ rt_count : current_user . rt_count }
end
end curl -v -X OPTIONS http://localhost:3000/rt_count
> OPTIONS /rt_count HTTP/1.1
>
< HTTP/1.1 204 No Content
< Allow: OPTIONS, GET, PUT您可以使用do_not_route_options! 。
如果使用不支持的HTTP方法提出資源請求,則將返回HTTP 405(不允許的方法)響應。如果資源在回調before已被執行,但不會運行其他回調。
curl -X DELETE -v http://localhost:3000/rt_count/
> DELETE /rt_count/ HTTP/1.1
> Host: localhost:3000
>
< HTTP/1.1 405 Method Not Allowed
< Allow: OPTIONS, GET, PUT您可以通過error! 。
error! 'Access Denied' , 401任何響應#to_s的內容都可以作為error! 。
error! :not_found , 404您還可以通過增加錯誤來返回JSON格式化的對象!並傳遞哈希而不是消息。
error! ( { error : 'unexpected error' , detail : 'missing widget' } , 500 )您可以為響應設置其他標題。在error!稱呼。
error! ( 'Something went wrong' , 500 , 'X-Error-Detail' => 'Invalid token.' )您可以使用葡萄 - 實體寶石使用葡萄實體出示已記錄的錯誤。
module API
class Error < Grape :: Entity
expose :code
expose :message
end
end以下示例指定在http_codes定義中使用的實體。
desc 'My Route' do
failure [ [ 408 , 'Unauthorized' , API :: Error ] ]
end
error! ( { message : 'Unauthorized' } , 408 )以下示例在錯誤消息中明確指定了所介紹的實體。
desc 'My Route' do
failure [ [ 408 , 'Unauthorized' ] ]
end
error! ( { message : 'Unauthorized' , with : API :: Error } , 408 )默認情況下,葡萄從error! 。您可以使用default_error_status更改此操作。
class API < Grape :: API
default_error_status 400
get '/example' do
error! 'This should have http status code 400'
end
end為了使葡萄處理API的所有404s,使用全部使用可能是有用的。以最簡單的形式,它可能就像:
route :any , '*path' do
error! # or something else
end在API末尾定義此端點非常重要,因為它實際上接受了每個請求。
可以告訴葡萄以挽救所有StandardError Except,並以API格式返回它們。
class Twitter :: API < Grape :: API
rescue_from :all
end當未提供異常類型時,此模仿默認rescue行為。任何其他例外都應明確救出,請參見下文。
葡萄還可以從所有例外營救,並且仍然使用內置異常交接。這將產生與rescue_from :all添加的葡萄都將使用所有例外處理,這些Grape::Exceptions::Base 。
此設置的目的是提供一種簡單的方法來涵蓋最常見的異常並返回API格式中的任何意外異常。
class Twitter :: API < Grape :: API
rescue_from :grape_exceptions
end如果要自定義返回給用戶的葡萄異常rescue_from :grape_exceptions形狀,以匹配您的:all
rescue_from :grape_exceptions do | e |
error! ( e , e . status )
end您也可以挽救特定的例外。
class Twitter :: API < Grape :: API
rescue_from ArgumentError , UserDefinedError
end在這種情況下,必須從StandardError繼承UserDefinedError 。
請注意,您可以將這兩種方法結合起來(拯救自定義錯誤需要優先考慮)。例如,它對於處理除葡萄驗證錯誤以外的所有異常都很有用。
class Twitter :: API < Grape :: API
rescue_from Grape :: Exceptions :: ValidationErrors do | e |
error! ( e , 400 )
end
rescue_from :all
end錯誤格式將匹配請求格式。請參閱下面的“內容類型”。
可以使用PROC定義現有類型的自定義錯誤格式。
class Twitter :: API < Grape :: API
error_formatter :txt , -> ( message , backtrace , options , env , original_exception ) {
"error: #{ message } from #{ backtrace } "
}
end您也可以使用模塊或類。
module CustomFormatter
def self . call ( message , backtrace , options , env , original_exception )
{ message : message , backtrace : backtrace }
end
end
class Twitter :: API < Grape :: API
error_formatter :custom , CustomFormatter
end您可以使用代碼塊挽救所有異常。 error!包裝器會自動設置默認錯誤代碼和內容類型。
class Twitter :: API < Grape :: API
rescue_from :all do | e |
error! ( "rescued from #{ e . class . name } " )
end
end您可以選擇設置格式,狀態代碼和標題。
class Twitter :: API < Grape :: API
format :json
rescue_from :all do | e |
error! ( { error : 'Server error.' } , 500 , { 'Content-Type' => 'text/error' } )
end
end您還可以用代碼塊挽救所有異常,並以最低級別處理機架響應。
class Twitter :: API < Grape :: API
rescue_from :all do | e |
Rack :: Response . new ( [ e . message ] , 500 , { 'Content-type' => 'text/error' } )
end
end或營救特定的例外。
class Twitter :: API < Grape :: API
rescue_from ArgumentError do | e |
error! ( "ArgumentError: #{ e . message } " )
end
rescue_from NoMethodError do | e |
error! ( "NoMethodError: #{ e . message } " )
end
end默認情況下, rescue_from將挽救列出的例外及其所有子類。
假設您有以下例外類定義。
module APIErrors
class ParentError < StandardError ; end
class ChildError < ParentError ; end
end然後,以下rescue_from子句將為APIErrors::ParentError及其子類(在本例中APIErrors::ChildError )挽救例外。
rescue_from APIErrors :: ParentError do | e |
error! ( {
error : " #{ e . class } error" ,
message : e . message
} , e . status )
end要僅拯救基本異常類,請設置rescue_subclasses: false 。下面的代碼將挽救類型RuntimeError的例外,而不是其子類。
rescue_from RuntimeError , rescue_subclasses : false do | e |
error! ( {
status : e . status ,
message : e . message ,
errors : e . errors
} , e . status )
end助手也可以在rescue_from內提供。
class Twitter :: API < Grape :: API
format :json
helpers do
def server_error!
error! ( { error : 'Server error.' } , 500 , { 'Content-Type' => 'text/error' } )
end
end
rescue_from :all do | e |
server_error!
end
end rescue_from程序必須返回Rack::Response對象,請通話error! ,或提出異常(原始異常或其他自定義)。從rescue_from提出的例外將在葡萄外處理。例如,如果將葡萄安裝在導軌中,則將由Rails Action Controller處理。
或者,從rescue_from中使用WAND with選項來指定方法或proc 。
class Twitter :: API < Grape :: API
format :json
helpers do
def server_error!
error! ( { error : 'Server error.' } , 500 , { 'Content-Type' => 'text/error' } )
end
end
rescue_from :all , with : :server_error!
rescue_from ArgumentError , with : -> { Rack :: Response . new ( 'rescued with a method' , 400 ) }
end在rescue_from塊內部,可以通過#context方法訪問原始控制器方法( .self接收器)的環境。
class Twitter :: API < Grape :: API
rescue_from :all do | e |
user_id = context . params [ :user_id ]
error! ( "error for #{ user_id } " )
end
end 您可以將rescue_from從句放在名稱空間中,它們將優先於根部範圍中的定義:
class Twitter :: API < Grape :: API
rescue_from ArgumentError do | e |
error! ( "outer" )
end
namespace :statuses do
rescue_from ArgumentError do | e |
error! ( "inner" )
end
get do
raise ArgumentError . new
end
end
end在這裡, 'inner'將是ArgumentError的結果。
Grape::Exceptions::InvalidVersionHeader (當請求標題中的版本與端點的當前評估版本都與當前評估的版本不匹配時,它將永遠不會從rescue_from Block(甚至是rescue_from :all )中獲救,這是因為葡萄依賴於在機架上捕獲該錯誤,並嘗試使用具有不同版本的相同葡萄端點的情況下,嘗試下一個版本的路由。
任何不是StandardError子類的例外都應明確救出。通常情況下,應用程序邏輯不是一個情況,因為此類錯誤指出了Ruby運行時的問題。這是根據例外處理的標準建議。
Grape::API提供了一種logger方法,默認情況下,它將從Ruby的標準庫中返回Logger類的實例。
要從端點內登錄消息,您需要定義一個助手,以使端點上下文中的記錄器可用。
class API < Grape :: API
helpers do
def logger
API . logger
end
end
post '/statuses' do
logger . info " #{ current_user } has statused"
end
end更改記錄器級別。
class API < Grape :: API
self . logger . level = Logger :: INFO
end您還可以設置自己的記錄儀。
class MyLogger
def warning ( message )
puts "this is a warning: #{ message } "
end
end
class API < Grape :: API
logger MyLogger . new
helpers do
def logger
API . logger
end
end
get '/statuses' do
logger . warning " #{ current_user } has statused"
end
end類似於Rails請求記錄,請嘗試使用Grape_logging或Grape-Middleware-Logger Gems。
您的API可以使用content_type聲明哪些內容類型。如果未指定任何內容,葡萄將支持XML , JSON , Binary和TXT Content-Types。默認格式為:txt ;您可以使用default_format更改此操作。本質上,以下兩個API等效。
class Twitter :: API < Grape :: API
# no content_type declarations, so Grape uses the defaults
end
class Twitter :: API < Grape :: API
# the following declarations are equivalent to the defaults
content_type :xml , 'application/xml'
content_type :json , 'application/json'
content_type :binary , 'application/octet-stream'
content_type :txt , 'text/plain'
default_format :txt
end如果您聲明任何content_type ,葡萄默認值將被覆蓋。例如,以下API僅支持:xml和:rss Content-types,但不支持:txt , :json ,或:binary .。重要的是,這意味著不支持:txt默認格式!因此,請確保設置一個新的default_format 。
class Twitter :: API < Grape :: API
content_type :xml , 'application/xml'
content_type :rss , 'application/xml+rss'
default_format :xml
end序列化會自動進行。例如,您不必在每個JSON API端點實現中調用to_json 。響應格式(因此是自動序列化)按以下順序確定:
format參數的值。format選項設置的格式(如果指定)。Accept標頭找到可接受的格式。default_format選項指定,請使用默認格式。:txt 。例如,考慮以下API。
class MultipleFormatAPI < Grape :: API
content_type :xml , 'application/xml'
content_type :json , 'application/json'
default_format :json
get :hello do
{ hello : 'world' }
end
endGET /hello ( Accept: */*標頭)沒有擴展名或format參數,因此它將以JSON(默認格式)響應。GET /hello.xml具有公認的擴展名,因此它將以XML響應。GET /hello?format=xml具有識別format參數,因此它將使用XML響應。GET /hello.xml?format=json具有公認的擴展名(優先於format參數),因此它將使用XML響應。GET /hello.xls (帶有Accept: */*標頭)具有擴展名,但是該擴展名未識別,因此它將以JSON(默認格式)響應。GET /hello.xls帶有Accept: application/xml標頭具有未識別的擴展名,但是Accept頭器對應於公認的格式,因此它將使用XML響應。GET /hello.xls帶有Accept: text/plain標頭具有未識別的擴展名和未識別的Accept標頭,因此它將以JSON(默認格式)響應。您可以通過在API本身中調用api_format來明確覆蓋此過程。例如,以下API將讓您上傳任意文件,並以正確的MIME類型作為附件返回其內容。
class Twitter :: API < Grape :: API
post 'attachment' do
filename = params [ :file ] [ :filename ]
content_type MIME :: Types . type_for ( filename ) [ 0 ] . to_s
api_format :binary # there's no formatter for :binary, data will be returned "as is"
header 'Content-Disposition' , "attachment; filename*=UTF-8'' #{ CGI . escape ( filename ) } "
params [ :file ] [ :tempfile ] . read
end
end您只能讓API響應使用format的單一格式。如果您使用此功能,API將不會響應format指定以外的文件擴展名。例如,考慮以下API。
class SingleFormatAPI < Grape :: API
format :json
get :hello do
{ hello : 'world' }
end
endGET /hello將與JSON回應。GET /hello.json將與JSON回應。GET /hello.xml GET /hello.foobar ,或任何其他擴展程序將使用HTTP 404錯誤代碼響應。GET /hello?format=xml將使用HTTP 406錯誤代碼響應,因為不支持請求參數指定的XML格式。GET /hello Accept: application/xml標頭仍將與JSON做出響應,因為它無法從標題中協商公認的內容類型,而JSON是有效的默認值。格式也適用於解析。以下API只能響應JSON Content-type,並且除了application/json , application/x-www-form-urlencoded , multipart/form-data Ressact和multipart/related multipart/mixed 。所有其他請求將使用HTTP 406錯誤代碼失敗。
class Twitter :: API < Grape :: API
format :json
end當省略內容類型時,除非指定default_format ,否則葡萄將返回406錯誤代碼。以下API將嘗試使用JSON解析器的內容類型來解析任何數據。
class Twitter :: API < Grape :: API
format :json
default_format :json
end如果將format與rescue_from :all ,則將使用相同格式呈現錯誤。如果您不想要此行為,請使用default_error_formatter設置默認錯誤格式。
class Twitter :: API < Grape :: API
format :json
content_type :txt , 'text/plain'
default_error_formatter :txt
end可以使用Proc定義現有類型的自定義格式化器。
class Twitter :: API < Grape :: API
content_type :xls , 'application/vnd.ms-excel'
formatter :xls , -> ( object , env ) { object . to_xls }
end您也可以使用模塊或類。
module XlsFormatter
def self . call ( object , env )
object . to_xls
end
end
class Twitter :: API < Grape :: API
content_type :xls , 'application/vnd.ms-excel'
formatter :xls , XlsFormatter
end內置格式是以下內容。
:json :使用對象的to_json ,否則請致電MultiJson.dump:xml :通常通過MultiXml使用對象的to_xml:txt :可用時使用對象的to_txt ,否則to_s:serializable_hash :可用時使用對象的serializable_hash ,否則後備為:json:binary :數據將“原樣”返回如果對API的請求中存在一個正文,則具有內容類型的標頭值,該值為不支持的A類型A“ 415未支撐的媒體類型”錯誤代碼將由葡萄返回。
響應狀態表明此處未定義的架子定義的內容將繞過序列化,而身體實體(儘管應該沒有)不會被修改。
葡萄支持JSONP通過RACK :: JSONP,Rack-Contrib寶石的一部分。將rack-contrib添加到您的Gemfile中。
require 'rack/contrib'
class API < Grape :: API
use Rack :: JSONP
format :json
get '/' do
'Hello World'
end
end葡萄通過架子:: CORS支持CORS,這是架子cors寶石的一部分。將rack-cors添加到您的Gemfile ,然後在您的config.ru文件中使用中間件。
require 'rack/cors'
use Rack :: Cors do
allow do
origins '*'
resource '*' , headers : :any , methods : :get
end
end
run Twitter :: API 內容類型是由格式設置的。您可以通過設置Content-Type標頭來覆蓋運行時響應的內容類型。
class API < Grape :: API
get '/home_timeline_js' do
content_type 'application/javascript'
"var statuses = ...;"
end
end 葡萄接受和解析輸入數據隨帖子發送,並按照上述參數部分中所述放置方法。它還支持自定義數據格式。您必須通過content_type聲明其他內容類型,並選擇通過parser提供解析器,除非已經在葡萄中可以使用解析器來啟用自定義格式。這樣的解析器可以是函數或類。
使用解析器,可以在env['api.request.body']中使用“ AS-IS”數據。如果沒有解析器,則可以在“ AS-IS”和env['api.request.input']中獲得數據。
以下示例是一個瑣碎的解析器,它將將帶有“文本/自定義”內容類型的任何輸入分配給:value 。該參數將通過API調用中的params[:value]提供。
module CustomParser
def self . call ( object , env )
{ value : object . to_s }
end
end content_type :txt , 'text/plain'
content_type :custom , 'text/custom'
parser :custom , CustomParser
put 'value' do
params [ :value ]
end您可以如下調用上述API。
curl -X PUT -d 'data' 'http://localhost:9292/value' -H Content-Type:text/custom -v
您可以禁用使用nil的內容類型的解析。例如, parser :json, nil將完全禁用JSON解析。然後,請求數據可在env['api.request.body']中提供。
Grape使用JSON和ActiveSupport::XmlMini進行JSON和XML解析。它還檢測並支持Multi_json和Multi_xml。將這些寶石添加到您的Gemfile中並需要它們將使它們啟用,並允許您交換JSON和XML後端。
葡萄支持通過通用present方法的一些幫助來展示數據的範圍,該方法接受兩個參數:要提出的對像以及與之關聯的選項。哈希選項可能包括:with ,它定義了實體公開。
將葡萄 - 實體寶石添加到您的gemfile中。有關更多詳細信息,請參考葡萄 - 實體文檔。
以下示例暴露了狀態。
module API
module Entities
class Status < Grape :: Entity
expose :user_name
expose :text , documentation : { type : 'string' , desc : 'Status update text.' }
expose :ip , if : { type : :full }
expose :user_type , :user_id , if : -> ( status , options ) { status . user . public? }
expose :digest do | status , options |
Digest :: MD5 . hexdigest ( status . txt )
end
expose :replies , using : API :: Status , as : :replies
end
end
class Statuses < Grape :: API
version 'v1'
desc 'Statuses index' do
params : API :: Entities :: Status . documentation
end
get '/statuses' do
statuses = Status . all
type = current_user . admin? ? :full : :default
present statuses , with : API :: Entities :: Status , type : type
end
end
end您可以使用以下方式直接在參數塊中using: Entity.documentation 。
module API
class Statuses < Grape :: API
version 'v1'
desc 'Create a status'
params do
requires :all , except : [ :ip ] , using : API :: Entities :: Status . documentation . except ( :id )
end
post '/status' do
Status . create! params
end
end
end您可以使用可選符號參數提供多個實體。
get '/statuses' do
statuses = Status . all . page ( 1 ) . per ( 20 )
present :total_page , 10
present :per_page , 20
present :statuses , statuses , with : API :: Entities :: Status
end回應將是
{
total_page: 10,
per_page: 20,
statuses: []
}
除了單獨組織實體外,將它們作為其代表模型下方的命名級類可能很有用。
class Status
def entity
Entity . new ( self )
end
class Entity < Grape :: Entity
expose :text , :user_id
end
end如果您以這種方式組織實體,葡萄將自動檢測Entity類並使用它來展示您的模型。在此示例中,如果您將present Status.new添加到您的端點上,則葡萄會自動檢測到存在Status::Entity類並將其用作代表性實體。使用:with方式可以通過以下represents覆蓋這一點。
您可以向hash添加Grape::Presenters::Presenter保持一致。
get '/users' do
present { id : 10 , name : :dgz } , with : Grape :: Presenters :: Presenter
end回應將是
{
id : 10 ,
name : 'dgz'
}它具有相同的結果
get '/users' do
present :id , 10
present :name , :dgz
end您可以在葡萄roar的幫助下使用咆哮來渲染HAL或Collection+JSON,該葡萄roar定義了自定義的JSON格式格式,並啟用了用Grape的present關鍵字呈現實體。
您可以在定義自定義的葡萄Rabl Formatter的葡萄寶石的幫助下使用RABL模板。
您可以在葡萄Active_model_serializers Gem的幫助下使用活動模型序列化序列化序列化,該葡萄serializers Gem定義了自定義的葡萄AMS格式化。
通常,使用二進制格式發送原始數據。
class API < Grape :: API
get '/file' do
content_type 'application/octet-stream'
File . binread 'file.bin'
end
end您可以用body明確設置響應主體。
class API < Grape :: API
get '/' do
content_type 'text/plain'
body 'Hello World'
# return value ignored
end
end使用body false返回204 No Content 。
如果您想使用204 No Content以外的HTTP狀態代碼清空身體,則可以在指定body false之後覆蓋狀態代碼
class API < Grape :: API
get '/' do
body false
status 304
end
end您還可以將響應設置為帶有sendfile文件。這與機架:: sendfile中間件一起使用,可以通過您的Web服務器軟件最佳地發送文件。
class API < Grape :: API
get '/' do
sendfile '/path/to/file'
end
end在塊中流式傳輸文件使用stream
class API < Grape :: API
get '/' do
stream '/path/to/file'
end
end如果要流式傳輸非文件數據,請使用stream方法和Stream對象。這是一個對each響應的對象,並屈服於每個塊以發送給客戶。每個塊將被發送,因為它被屈服,而不是等待所有內容可用。
class MyStream
def each
yield 'part 1'
yield 'part 2'
yield 'part 3'
end
end
class API < Grape :: API
get '/' do
stream MyStream . new
end
end 葡萄具有內置的基本身份驗證(在當前Endpoint的上下文中執行給定block )。身份驗證適用於當前名稱空間和任何孩子,但不適用於父母。
http_basic do | username , password |
# verify user's password here
# IMPORTANT: make sure you use a comparison method which isn't prone to a timing attack
end葡萄可以使用自定義中間件進行身份驗證。如何實施這些中間件可以查看Rack::Auth::Basic或類似的實現。
要註冊中間件,您需要以下選項:
label - 驗證者以後使用它的名稱MiddlewareClass用於身份驗證的中間沃雷克拉option_lookup_proc一個帶有一個參數的proc可以在運行時查找選項(返回值是中間件的參數的Array )。例子:
Grape :: Middleware :: Auth :: Strategies . add ( :my_auth , AuthMiddleware , -> ( options ) { [ options [ :realm ] ] } )
auth :my_auth , { realm : 'Test Api' } do | credentials |
# lookup the user's password here
{ 'user1' => 'password1' } [ username ]
end使用門守,看守-OAUTH2或RACK-OAUTH2進行OAuth2支持。
您可以通過上下文訪問控制器參數,標頭和助手,並使用#context方法中的任何auth Middleware內部從Grape::Middleware::Auth::Base繼承。
葡萄路線可以在運行時反映。這對於生成文檔非常有用。
葡萄揭示了API版本和編譯路線的數組。每個路由都包含一個prefix , version , namespace , method和params 。您可以使用route_setting將自定義路由設置添加到路由元數據中。
class TwitterAPI < Grape :: API
version 'v1'
desc 'Includes custom settings.'
route_setting :custom , key : 'value'
get do
end
end檢查運行時路線。
TwitterAPI :: versions # yields [ 'v1', 'v2' ]
TwitterAPI :: routes # yields an array of Grape::Route objects
TwitterAPI :: routes [ 0 ] . version # => 'v1'
TwitterAPI :: routes [ 0 ] . description # => 'Includes custom settings.'
TwitterAPI :: routes [ 0 ] . settings [ :custom ] # => { key: 'value' }請注意,自0.15.0以來, Route#route_xyz方法已被棄用,自2.0.1以來被刪除。
請改用Route#xyz 。
請注意, Route#options和Route#settings的差異。
可以從您的路線中轉介options ,應通過在動詞方法(例如get , post和put上指定鍵和值來設置。 settings也可以從您的路由中引用,但應通過指定鍵和route_setting的價值來設置它。
可以從API呼叫的route中檢索有關當前路線的信息。
class MyAPI < Grape :: API
desc 'Returns a description of a parameter.'
params do
requires :id , type : Integer , desc : 'Identity.'
end
get 'params/:id' do
route . params [ params [ :id ] ] # yields the parameter description
end
end當前對請求的端點是在其他地方的API塊或env['api.endpoint']中的self 。端點具有一些有趣的屬性,例如source ,您可以訪問API實現的原始代碼塊。這對於構建Logger中間件特別有用。
class ApiLogger < Grape :: Middleware :: Base
def before
file = env [ 'api.endpoint' ] . source . source_location [ 0 ]
line = env [ 'api.endpoint' ] . source . source_location [ 1 ]
logger . debug "[api] #{ file } : #{ line } "
end
end 可以在每個API調用之前或之後執行塊,使用before , after , before_validation和after_validation 。如果API失敗,則不會觸發after呼叫,如果您需要執行代碼確保finally使用。
回調之前和之後按以下順序執行:
beforebefore_validationafter_validation (成功驗證後)after (成功驗證和API電話)finally (總是)步驟4、5和6僅在驗證成功時才發生。
如果使用不支持的HTTP方法(返回HTTP 405)提出資源請求,則僅在執行回調before 。其餘的回調將被繞過。
如果提出了觸發內置OPTIONS處理程序的資源請求,則只有在回調before和after才能執行。其餘的回調將被繞過。
例如,使用一個簡單的before塊設置標頭。
before do
header 'X-Robots-Tag' , 'noindex'
end您可以在每個請求(包括失敗)之後確保一系列代碼運行finally
finally do
# this code will run after every request (successful or failed)
end名稱空間
回調適用於當前名稱空間內外的每個API呼叫:
class MyAPI < Grape :: API
get '/' do
"root - #{ @blah } "
end
namespace :foo do
before do
@blah = 'blah'
end
get '/' do
"root - foo - #{ @blah } "
end
namespace :bar do
get '/' do
"root - foo - bar - #{ @blah } "
end
end
end
end這樣的行為是:
GET / # 'root - '
GET /foo # 'root - foo - blah'
GET /foo/bar # 'root - foo - bar - blah'使用before_validation或after_validation時,在namespace上(或您使用的任何別名)上的參數也將可用:
class MyAPI < Grape :: API
params do
requires :blah , type : Integer
end
resource ':blah' do
after_validation do
# if we reach this point validations will have passed
@blah = declared ( params , include_missing : false ) [ :blah ]
end
get '/' do
@blah . class
end
end
end這樣的行為是:
GET /123 # 'Integer'
GET /foo # 400 error - 'blah is invalid'版本控制
當在版本塊中定義回調時,它僅用於該塊中定義的路由。
class Test < Grape :: API
resource :foo do
version 'v1' , :using => :path do
before do
@output ||= 'v1-'
end
get '/' do
@output += 'hello'
end
end
version 'v2' , :using => :path do
before do
@output ||= 'v2-'
end
get '/' do
@output += 'hello'
end
end
end
end這樣的行為是:
GET /foo/v1 # 'v1-hello'
GET /foo/v2 # 'v2-hello'改變反應
在任何回調中使用的present都可以使您可以將數據添加到響應中:
class MyAPI < Grape :: API
format :json
after_validation do
present :name , params [ :name ] if params [ :name ]
end
get '/greeting' do
present :greeting , 'Hello!'
end
end這樣的行為是:
GET /greeting # {"greeting":"Hello!"}
GET /greeting ? name=Alan # {"name":"Alan","greeting":"Hello!"}您還可以使用error! ,包括after 。這將導致該過程中的所有後續步驟不被調用。這包括實際的API調用和任何回調
默認情況下,葡萄錨點所有請求路徑,這意味著請求URL應從開始到結尾匹配,否則404 Not Found 。但是,這有時不是您想要的,因為它並不總是預先知道的。這是因為默認情況下,機架安裝了從開始到結束或根本不匹配的請求。 Rails通過使用anchor: false選項解決此問題。在葡萄中,當定義方法時,也可以使用此選項。
例如,當您的API需要獲得URL的一部分時,例如:
class TwitterAPI < Grape :: API
namespace :statuses do
get '/(*:status)' , anchor : false do
end
end
end這將匹配所有以'/status/'開頭的路徑。但是有一個警告: params[:status]參數僅保存請求URL的第一部分。幸運的是,通過使用上述語法進行路徑規範,並使用env['PATH_INFO']使用PATH_INFO機架環境變量,可以通過使用上述語法來規避這一點。這將容納“/status/'零件”之後的所有內容。
您可以使用實例變量在請求的各個階段傳遞信息。在端點代碼中可以訪問驗證器before一個實例變量集,也可以在rescue_from程序中使用。
class TwitterAPI < Grape :: API
before do
@var = 1
end
get '/' do
puts @var # => 1
raise
end
rescue_from :all do
puts @var # => 1
end
end實例變量的值不能在同一API中的各個端點之間共享。由於葡萄生成了每個請求的新實例而產生的限制。因此,在一個請求期間設置的實例變量與後續請求中集合的端點設置不同,因為它們存在於單獨的實例中。
class TwitterAPI < Grape :: API
get '/first' do
@var = 1
puts @var # => 1
end
get '/second' do
puts @var # => nil
end
end 您可以使用Grape::Middleware::Base製作自定義中間件。實際上,它是從一些葡萄官方中間的中繼承而來的。
例如,您可以將中間件寫入日誌應用程序異常。
class LoggingError < Grape :: Middleware :: Base
def after
return unless @app_response && @app_response [ 0 ] == 500
env [ 'rack.logger' ] . error ( "Raised error on #{ env [ 'PATH_INFO' ] } " )
end
end您的中間軟件可以如下覆蓋應用程序響應,但錯誤情況除外。
class Overwriter < Grape :: Middleware :: Base
def after
[ 200 , { 'Content-Type' => 'text/plain' } , [ 'Overwritten.' ] ]
end
end您可以在use中添加自定義中間件,將中間件推到堆棧上,還可以控制使用insert , insert_before和insert_after插入中間件的位置。
class CustomOverwriter < Grape :: Middleware :: Base
def after
[ 200 , { 'Content-Type' => 'text/plain' } , [ @options [ :message ] ] ]
end
end
class API < Grape :: API
use Overwriter
insert_before Overwriter , CustomOverwriter , message : 'Overwritten again.'
insert 0 , CustomOverwriter , message : 'Overwrites all other middleware.'
get '/' do
end
end您可以通過上下文訪問控制器參數,標題和助手,並使用#context方法中的任何中間件中的任何中間件中從Grape::Middleware::Base繼承。
請注意,當您使用安裝在軌道上的葡萄時,您不必使用Rails Mifdreware,因為它已經包含在中間件堆棧中。您只需要實現助手即可訪問特定的env變量。
如果您使用的是從Rails::Application繼承的自定義應用程序,並且需要在通過Rails啟動的中間件中插入新中間件,則需要在自定義應用程序類中手動註冊它。
class Company :: Application < Rails :: Application
config . middleware . insert_before ( Rack :: Attack , Middleware :: ApiLogger )
end默認情況下,您可以使用request.ip訪問遠程IP。這是機架實現的遠程IP地址。有時,希望使用ActionDispatch::RemoteIp獲得遠程IP軌道風格。
將gem 'actionpack'添加到您的Gemfile,並require 'action_dispatch/middleware/remote_ip.rb' 。使用API中的中間軟件,並暴露client_ip助手。有關其他選項,請參見此文檔。
class API < Grape :: API
use ActionDispatch :: RemoteIp
helpers do
def client_ip
env [ 'action_dispatch.remote_ip' ] . to_s
end
end
get :remote_ip do
{ ip : client_ip }
end
end 使用rack-test並將API定義為app 。
您可以通過提出HTTP請求並檢查響應來測試使用RSPEC的葡萄API。
describe Twitter :: API do
include Rack :: Test :: Methods
def app
Twitter :: API
end
context 'GET /api/statuses/public_timeline' do
it 'returns an empty array of statuses' do
get '/api/statuses/public_timeline'
expect ( last_response . status ) . to eq ( 200 )
expect ( JSON . parse ( last_response . body ) ) . to eq [ ]
end
end
context 'GET /api/statuses/:id' do
it 'returns a status by id' do
status = Status . create!
get "/api/statuses/ #{ status . id } "
expect ( last_response . body ) . to eq status . to_json
end
end
end沒有標準的方式可以通過HTTP GET發送對像數組,因此請發布JSON數據並指定正確的內容類型。
describe Twitter :: API do
context 'POST /api/statuses' do
it 'creates many statuses' do
statuses = [ { text : '...' } , { text : '...' } ]
post '/api/statuses' , statuses . to_json , 'CONTENT_TYPE' => 'application/json'
expect ( last_response . body ) . to eq 201
end
end
end 您可以使用其他基於RSPEC的框架進行測試,其中包括使用rack-test來提出請求的機載。
require 'airborne'
Airborne . configure do | config |
config . rack_app = Twitter :: API
end
describe Twitter :: API do
context 'GET /api/statuses/:id' do
it 'returns a status by id' do
status = Status . create!
get "/api/statuses/ #{ status . id } "
expect_json ( status . as_json )
end
end
end require 'test_helper'
class Twitter :: APITest < MiniTest :: Test
include Rack :: Test :: Methods
def app
Twitter :: API
end
def test_get_api_statuses_public_timeline_returns_an_empty_array_of_statuses
get '/api/statuses/public_timeline'
assert last_response . ok?
assert_equal [ ] , JSON . parse ( last_response . body )
end
def test_get_api_statuses_id_returns_a_status_by_id
status = Status . create!
get "/api/statuses/ #{ status . id } "
assert_equal status . to_json , last_response . body
end
end describe Twitter :: API do
context 'GET /api/statuses/public_timeline' do
it 'returns an empty array of statuses' do
get '/api/statuses/public_timeline'
expect ( response . status ) . to eq ( 200 )
expect ( JSON . parse ( response . body ) ) . to eq [ ]
end
end
context 'GET /api/statuses/:id' do
it 'returns a status by id' do
status = Status . create!
get "/api/statuses/ #{ status . id } "
expect ( response . body ) . to eq status . to_json
end
end
end在Rails中,HTTP請求測試將進入spec/requests組。您可能希望您的API代碼進入app/api您可以通過在spec/rails_helper.rb中添加以下spec來匹配該佈局。
RSpec . configure do | config |
config . include RSpec :: Rails :: RequestExampleGroup , type : :request , file_path : /spec / api/
end class Twitter :: APITest < ActiveSupport :: TestCase
include Rack :: Test :: Methods
def app
Rails . application
end
test 'GET /api/statuses/public_timeline returns an empty array of statuses' do
get '/api/statuses/public_timeline'
assert last_response . ok?
assert_equal [ ] , JSON . parse ( last_response . body )
end
test 'GET /api/statuses/:id returns a status by id' do
status = Status . create!
get "/api/statuses/ #{ status . id } "
assert_equal status . to_json , last_response . body
end
end由於基於定義端點的上下文中的上下文混合了助手,因此很難將其固定或模擬測試。 Grape::Endpoint.before_each方法可以通過允許您在每個請求之前運行的端點上定義行為來提供幫助。
describe 'an endpoint that needs helpers stubbed' do
before do
Grape :: Endpoint . before_each do | endpoint |
allow ( endpoint ) . to receive ( :helper_name ) . and_return ( 'desired_value' )
end
end
after do
Grape :: Endpoint . before_each nil
end
it 'stubs the helper' do
end
end 使用葡萄收緊。
將API路徑添加到config/application.rb 。
# Auto-load API and its subdirectories
config . paths . add File . join ( 'app' , 'api' ) , glob : File . join ( '**' , '*.rb' )
config . autoload_paths += Dir [ Rails . root . join ( 'app' , 'api' , '*' ) ]創建config/initializers/reload_api.rb 。
if Rails . env . development?
ActiveSupport :: Dependencies . explicitly_unloadable_constants << 'Twitter::API'
api_files = Dir [ Rails . root . join ( 'app' , 'api' , '**' , '*.rb' ) ]
api_reloader = ActiveSupport :: FileUpdateChecker . new ( api_files ) do
Rails . application . reload_routes!
end
ActionDispatch :: Callbacks . to_prepare do
api_reloader . execute_if_updated
end
end對於導軌> = 5.1.4,更改以下內容:
ActionDispatch :: Callbacks . to_prepare do
api_reloader . execute_if_updated
end因此:
ActiveSupport :: Reloader . to_prepare do
api_reloader . execute_if_updated
end有關更多信息,請參見Stackoverflow#3282655。
Grape對ActiveSupport ::通知具有內置的支持,該通知為您的應用程序的關鍵部分提供了簡單的掛鉤點。
目前支持以下內容:
端點的主要執行,包括過濾器和渲染。
端點的主內容塊的執行。
執行驗證器。
序列化或模板渲染。
Grape::Formatter::Json )有關如何訂閱這些事件的信息,請參見ActiveSupport ::通知文檔。
葡萄與以下第三方工具集成:
葡萄是數百名貢獻者的作品。鼓勵您提交拉力請求,提出功能並討論問題。
參見貢獻。
有關詳細信息,請參見安全性。
麻省理工學院許可證。有關詳細信息,請參見許可證。
版權所有(C)2010-2020 Michael Bleigh,Intidea Inc.及其貢獻者。