2016-10-17 1 views
3

Je monte le projet Grape in my Rails pour construire une API RESTful.Comment gérer avant le filtre pour une action spécifique dans Grape?

Maintenant, certains points d'extrémité ont besoin d'une authentification et d'autres qui n'ont pas besoin d'authentification.

Comme par exemple j'ai users point final qui ressemble à:

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 

Maintenant, comme vous pouvez le voir, toutes les actions sauf password/forget l'utilisateur a besoin d'être connecté/authentifié. Il n'a pas de sens aussi de créer un nouveau point de terminaison disons passwords et de supprimer simplement password/forget là, logiquement parlant, ce point final devrait être lié à la ressource des utilisateurs.

Le problème est avec Raisin before filtre n'a pas d'options comme except, only dans lequel je peux dire appliquer le filtre pour certaines actions.

Comment gérez-vous habituellement un tel cas de manière propre?

Répondre

3

Une façon sale pour aider serait à l'aide namespace, quelque chose comme:

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 

De cette façon, nous ne retournerons pas courir avant filtre pour users/password/forget mais pour le reste, nous courrons before { authenticate! }

+0

upvoted .. Je me demande si maintenant il y a une façon plus élégante de le faire – fabriciofreitag

2

Une façon que je pouvais Pensez à utiliser route_setting pour ajouter des attributs personnalisés pour les routes pour lesquelles vous souhaitez ignorer l'authentification. Vérifiez ces attributs dans le filtre avant avant d'appeler authenticate!. Quelque chose comme le ci-dessous devrait fonctionner:

module Backend 
    module V1 
    class Users < Grape::API 
     include Backend::V1::Defaults 

     before { authenticate! unless route.settings[:auth] && route.settings[:auth][:disabled] } 

     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" 
     route_setting :auth, disabled: true 
     params do 
      requires :email, type: String 
     end 
     post 'password/forget' do 
      PasswordService::Forget.new(current_user,params).call 
     end    

     end 
    end 
    end 
end 
+0

J'aime mieux que la réponse acceptée. L'approche de l'espace de noms signifie que l'action before doit vivre à l'intérieur de l'espace de noms imbriqué. Cela permettrait de l'enregistrer dans la base api et de l'exclure uniquement sur quelques points de terminaison sélectionnés, potentiellement dans des fichiers différents. – erich2k8