I'm mounting Grape in my Rails project to build a RESTful API.
Now some end-points have actions need authentication and others which don't need authentication.
As for example I have users
end-point which looks something like:
module Backend
module V1
class Users < Grape::API
include Backend::V1::Defaults
before { authenticate! }
resource :users do
desc "Return a user"
params do
requires :id, type: Integer, desc: 'User id'
end
get ':id' do
UsersService::Fetch.new(current_user,params).call
end
desc "Update a user"
params do
requires :id, type: Integer, desc: 'User id'
requires :display_name, type: String, desc: 'Display name'
requires :email, type: String, desc: 'Email'
end
post ':id' do
UsersService::Save.new(current_user,params).call
end
desc "Reset user password"
params do
requires :old_password, type: String, desc: 'old password'
requires :password, type: String, desc: 'new password'
end
post 'password/reset' do
PasswordService::Reset.new(current_user,params).call
end
desc "Forget password"
params do
requires :email, type: String
end
post 'password/forget' do
PasswordService::Forget.new(current_user,params).call
end
end
end
end
end
Now as you can see, all the actions except password/forget
needs the user to be logged-in/authenticated. It doesn't make sense too to create a new end-point let's say passwords
and just remove password/forget
there as logically speaking, this end-point should be related to users resource.
The problem is with Grape before
filter has no options like except, only
in which I can say apply the filter for certain actions.
How do you usually handle such a case in a clean way?
A dirty way to help would be by using namespace
, something like:
module Backend
module V1
class Users < Grape::API
include Backend::V1::Defaults
namespace :users do
desc "Forget password"
params do
requires :email, type: String
end
post 'password/forget' do
PasswordService::Forget.new(current_user,params).call
end
namespace do
before { authenticate! }
desc "Return a user"
params do
requires :id, type: Integer, desc: 'User id'
end
get ':id' do
UsersService::Fetch.new(current_user,params).call
end
desc "Update a user"
params do
requires :id, type: Integer, desc: 'User id'
requires :display_name, type: String, desc: 'Display name'
requires :email, type: String, desc: 'Email'
end
post ':id' do
UsersService::Save.new(current_user,params).call
end
desc "Reset user password"
params do
requires :old_password, type: String, desc: 'old password'
requires :password, type: String, desc: 'new password'
end
post 'password/reset' do
PasswordService::Reset.new(current_user,params).call
end
end
end
end
end
end
This way we wont run before filter for users/password/forget
but for the rest we will run before { authenticate! }