2015-08-02 1 views
0

J'essaie d'utiliser Grape pour créer une API en utilisant uniquement des objets Ruby. Je ne veux pas utiliser une base de données/Rails/ActiveSupport/etc - juste Rack, Ruby et Grape.Utilisation de Grape pour créer une API avec seulement des objets Ruby au lieu d'une base de données ou Rails

J'ai défini une classe pour un Directory avec laquelle je veux interagir via l'API. Donc, Directory#sort_by("last_name") renvoie les données JSON avec une liste d'objets People dans mon Directory. J'ai aussi une méthode Directory#create_person(attributes) qui prend une chaîne et l'utilise pour ajouter Person objets au Directory. Le répertoire est peuplé de personnes lors de la création.

Je suis nouveau à travailler avec Rack and Grape, donc je ne sais pas où/comment créer mon objet Directory et le rendre accessible via les GET/POST dans ma classe API Grape. En utilisant une variable de classe à l'intérieur de cette classe semble fonctionner, i.e.,:.

module API 
    class DirectoryAPI < Grape::API 
    format 'json' 

    @@directory = Directory.new("1.txt", "2.txt", "3.txt") 

    get 'last_name' do 
     @@directory.sort_by("last_name") 
    end 
    end 
end 

mais en utilisant des variables de classe semble juste mal. Existe-t-il une meilleure façon de créer mon objet Directory? Peut-être dans mon fichier config.ru? Ou pourrais-je le faire à travers une méthode de classe à l'intérieur de Directory en quelque sorte?

Répondre

1

Ce que vous cherchez est un singleton:

Habituellement singletons sont utilisés pour la gestion centralisée des ressources internes ou externes et ils fournissent un point d'accès global à eux-mêmes.

Malheureusement, Ruby ne joue pas bien avec les singletons. Mais vous pouvez utiliser une "classe composée de méthodes de classe seulement", la deuxième stratégie préconisée dans ce article. Je crois que vous travaillez sur un défi de codage que j'ai complété il y a quelques mois. Dans ma réponse, j'ai utilisé une "classe composée de seulement des méthodes de classe" appelée API::Store. Voici la sortie de rspec -fd:

API::Store 
    ::add 
    adds record to store 
    appends data line to file 
    ::has_line? 
    instantiates a record from the data line 
    without the record in the store 
     should equal false 
    with the record in the store 
     should equal true 
    ::new 
    should raise NoMethodError 
    ::records 
    with original file 
     on initial access 
     should eq Records 
     on subsequent access 
     should eq Records 
    when file replaced 
     should eq OtherRecords 

Finished in 0.07199 seconds (files took 2.68 seconds to load) 
9 examples, 0 failures 

Notez que Store ne peut pas être instancié; il lance un NoMethodError si vous essayez. Ce n'est pas un problème, cependant. Dans le point de terminaison Grape, vous pouvez appeler Store.records pour accéder aux données. En ce qui concerne le tri des enregistrements, cela devrait être fait dans une autre classe. Pourquoi un Store ou un Directory devrait-il trier les données dans ses fichiers? Enfin, vous avez demandé où faire la préparation initiale (pas l'initialisation, bien sûr). Vous pouvez préparer votre singleton dans config.ru, de sorte qu'il est prêt lorsque l'application commence:

# config.ru 

# load application code here 

file = File.open('data/records.txt', 'a+') 
at_exit { file.close } 

API::Store.file = file 
run API::Base 

instructions est le défi dire « Vous pouvez utiliser toutes les ressources dont vous avez besoin pour le compléter, » on peut donc supposer, demander débordement de la pile est permis. Si vous faites ce défi pour une demande d'emploi, veuillez le mentionner lorsque vous posez des questions, car il est juste que ceux qui répondent soient informés. Il serait sage de mentionner également lors de votre entrevue que vous avez obtenu de l'aide sur SO. Bonne chance et bonne codification.

+1

Cela semble bon, mais je ne pense pas qu'il répond à la question. OP pose des questions sur le code dans le contrôleur, pas comment créer une classe de gestion de données. Ce qui vous manque est de montrer comment il serait utilisé dans le contrôleur. Peut-être une ligne comme 'Store.records' à la place de la ligne de l'OP' @@ directory.sort_by ("last_name") '? –

+0

Merci, @NeilSlater. Je crois que la question essentielle de l'OP n'était pas «Que devrais-je faire dans mon contrôleur? mais "Comment dois-je accéder à mes données?" Néanmoins, j'ai édité ma réponse pour aller droit au but, à la fois sur les singletons et d'être avec nous à propos du défi de codage. – amar47shah

0

Le problème principal que je vois avec votre exemple n'est pas l'utilisation de variables de classe exactement, mais l'instanciation de vos données en ligne dans le code du contrôleur API.Idéalement, les données devraient être plus autonomes, de sorte que vous pouvez accéder aux mêmes données à partir d'autres endroits dans votre code. Si vous créez une API similaire à un module d'accès aux données léger, vous utiliserez un modèle familier dans vos contrôleurs de route. Il sera également facile de migrer vers SQL ou tout autre magasin de données si et quand vous en aurez besoin.

Il existe de nombreuses approches valides, mais je pourrais créer un nouvel objet singleton pour représenter votre source de données et le connecter à vos données codées en dur comme s'il s'agissait de tables. Le résultat final ici se sentirait un peu comme utiliser Sequel (mais vous pouvez suivre tout autre modèle que vous préférez):

inline_data.rb

module InlineDB 
    TABLES = Hash[ 
    :directory => Directory.new("1.txt", "2.txt", "3.txt") 
    ] 

    def self.[] table_name 
    TABLES[table_name] 
    end 
end 

app.rb

require_relative 'inline_data' # actual path may be more structured 
module API 
    class DirectoryAPI < Grape::API 
    format 'json' 

    get 'last_name' do 
     InlineDB[:directory].sort_by("last_name") 
    end 
    end 
end