1.Grape是運行在rack或與rails/sinatra配合使用的一種restful風格的ruby微框架,經過提供簡單的DSL(領域特定語言)簡化APIs開發.它內置支持mutiple formats(),subdomain/prefix restriction, versioning等通用約束(ruby約束高於配置).詳見http://intridea.github.io/grape/.git
2.安裝Grapegithub
gem install grape
或者編輯Gemfile.json
gem "grape"
而後api
bundle install
3.基礎用法ruby
Grape APIs和Rack應用繼承自Grape::API.restful
下面展現一段用Grape寫的簡單的twitter API:app
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
關於上面代碼的簡單解釋:框架
將API文件放在/app/api文件下,而且修改/config/application.rb文件:less
config.paths.add "app/api", glob: "**/*.rb" config.autoload_paths += Dir["#{Rails.root}/app/api/*"]
而且修改路由文件/config/routes.rb:dom
mount Twitter::API => '/'
3.調用API
使用mount方法:
class Twitter::API < Grape::API mount Twitter::APIv1 mount Twitter::APIv2 end
class Twitter::API < Grape::API mount Twitter::APIv1 => '/v1' end
4.爲API添加描述
desc "Returns your public timeline." do detail 'more details' params API::Entities::Status.documentation success API::Entities::Entity failure [[401, 'Unauthorized', "Entities::Error"]] named 'My named route' headers [XAuthToken: { description: 'Valdates your identity', required: true }, XOptionalHeader: { description: 'Not really needed', required: false } ] end get :public_timeline do Status.limit(20) end
details:更加詳細的描述
params:直接從實體定義參數
success:實體對象的默認使用路由
failure:請求失敗返回的http代碼
(====續=====)
參數認證和約束
(1).在block中定義設置參數的約束項:
params do requires :id, type: Integer optional :text, type: String, regexp: /^[a-z]+$/ #text全是小寫字母 group :media do #參數嵌套;與[:id]協同 requires :url end end put ':id' do # params[:id] is an Integer end
(2).命名空間認證和約束
容許定義參數以及在命名空間內部使用各類方法,命名空間就是一個sandbox,叫作module;採用這種模塊化機制能夠有效限定做用域;
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]) #經過 :user_id獲取:status_id; end end end
(3)用戶認證
class AlphaNumeric < Grape::Validations::Validator def validate_param!(attr_name, params) unless params[attr_name] =~ /^[[:alnum:]]+$/ #[:alnum] posix字符類字母數字類 throw :error, status: 400, message: "#{attr_name}: must consist of alpha-numeric characters" end end end
params do
requires :text, alpha_numeric: true #也可這樣約束類型
end
class Length < Grape::Validations::SingleOptionValidator def validate_param!(attr_name, params) unless params[attr_name].length <= @option throw :error, status: 400, message: "#{attr_name}: must be at the most #{@option} characters long" end end end
params do requires :text, length: 140 end
請求頭
get do error!('Unauthorized', 401) unless headers['Secret-Password'] == 'swordfish' end get do error!('Unauthorized', 401) unless env['HTTP_SECRET_PASSWORD'] == 'swordfish' end
header "X-Robots-Tag", "noindex"
路由
get ':id', requirements: { id: /[0-9]*/ } do #Regexp 條件過濾 Status.find(params[:id]) end namespace :outer, requirements: { id: /[0-9]*/ } do get :id do end get ":id/edit" do end end
module StatusHelpers def user_info(user) "#{user} has statused #{user.statuses} status(s)" 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 a module helpers StatusHelpers get 'info' do # helpers available in your endpoint and filters user_info(current_user) end end