1.Grape是运行在rack或与rails/sinatra配合使用的一种restful风格的ruby微框架,通过提供简单的DSL(领域特定语言)简化APIs开发.它内置支持mutiple formats(),subdomain/prefix restriction, versioning等通用约束(ruby约束高于配置).详见http://intridea.github.io/grape/.
2.安装Grape
gem install grape
或者编辑Gemfile.
gem "grape"
然后
bundle install
3.基础用法
Grape APIs和Rack应用继承自Grape::API.
下面展示一段用Grape写的简单的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
关于上面代码的简单解释:
将API文件放在/app/api文件下,并且修改/config/application.rb文件:
config.paths.add "app/api", glob: "**/*.rb"
config.autoload_paths += Dir["#{Rails.root}/app/api/*"]
并且修改路由文件/config/routes.rb:
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