How to test/spec Sinatra & MongoDB API with Cucumber? - ruby

I want to spec a Sinatra server that receives HTTP requests, stores things in MongoDB, and responds with JSON. How would I spec both the MongoDB entries and the responses?
I'd like to use Cucmber and RSpec to do this cause I hear they're hot, but I'm not really good with them yet.

My learning so far with BDD is that you need to think in very small steps. E.g. you could start in making specifications with rspec for your routes, example project with sinatra here, and another example, here.
Then you could start in making specifications for your model layer. Small steps also here, check for validations, setting and getting attributes.
Last, you might approach to specify the view, here you need to learn about mocks and stubs for your controller and models.
Cucumber is a different story in my view. You need to write cucumber specifications when you work with your customer, to understand together the requirements of your app. It facilitates acceptances testing as far as I can see.

Related

Laravel Web and API controller structure. Separate vs DRY

I want to build a Laravel application which users both web and API parts. The common (and mine as well) question is whether to use separate controllers or not.
There are 2 options:
Separate controllers
Laravel API controller structure?
Use one controller and check the request type (is Ajax, or depending on the request link) and return either JSON or HTML.
Laravel resource controllers for both API and non-API use
Those who have the 1-st opinion doesn't explain the DRY problem solution - web and API controllers would be the same except the return statement (JSON or HTML view). But since most post recommend to separate controllers I suspect I don't understand something about the DRY problem solution.
I don't see any disadvantage of the second method. But people say something like
If you use only one controller, you will end up soon with a messy class with thousands of lines. Not only this is not going to scale well, but it will be hard to work with for you and your teammates.
Please explain me the DRY problem solution for the first approach (separate controllers) and the possible underwater rocks in the second approach (single controller)
Please explain which approach is preferable.
I think this is a great question, and I too am keen to see the responses.
I can see the arguments for both approaches. I however would create and maintain separate controllers, whilst using services to share common logic between the controllers where it is known that this will never change.
For example, if you allow users to upload avatar images. I would put such logic in a service and consume this service in both controllers.
The reason for this approach in my mind, is that the web and API logic may diverge and it would therefore be easier to iterate each without impacting the other.
If this is unlikely, then I would still create separate routes, but point them both at the same controllers, so that if it did change in the future, you can simply re-point the API routes to their own controllers.

Best practices concerning SQLite queries, Sinatra, and erb?

I'm building a framework that allows users to install apps to add specific functionalities. The intent is for the user to manage these apps through a small web app. The list of installed apps exists in a sqlite3 database, and I'm using Sinatra to route http requests. I'm using erb templates to design the web pages in question.
My question is, what is the best practice for populating my displayed list of installed apps? Should I make the SQL queries in the Sinatra 'do' block and then pass an array containing the app names over to the erb? Or should I be making the database queries in the erb file itself?
Functionally, I'm sure they are very similar (though if there are functional differences, I'd like to know), but I would like to be following best practices if at all possible :)
The best practice consists in doing your SQL queries in the do block, and passing an object to your template.
It is considered a bad idea to write too much code in the templates, and it can be useful to isolate the fetching logic from the displaying logic if you ever want to use the same template from different routes.
By using Ruby's duck typing, you can make your template very flexible. For instance with Haml:
%ul
- #dataset.each do |row|
%li= row['name']
All you need to do is to provide the template with an Enumerable of objects which all respond to []. It can be the result of a database query (most gems return something compatible, I think), or it can be an hard-coded Array of Hashes for instance.

How to Post data to Volt app?

I've got a use case where I'd like to POST some data to my Volt app, but there doesn't seem to be an obvious way to do it. app/main/config/routes.rb doesn't recognize a post method like a Sinatra route.
I also tried a Volt-external class tied into the app via config.ru, and I can POST my data to the same Mongo collection that Volt is using. But that data is not reflected in the app until I refresh the page, which is less than ideal. I was hoping my reactive models would see the change in the DB and reflect that on the front end.
I understand that Volt is in beta, so this feature may not be implemented yet (or even planned for the future). Is it possible to do this?
Long term I'm going to make it so you can route REST requests to Tasks (or possibly another set of classes). In the short term, using rack is the right way. I'm in the process of adding a wrapper to the mongo api that knows how to trigger the updates. Should be out in a day or two, I'll update here when it is.

Rails structure, should I use a service layer in this case?

I'm new to Ruby and Rails and I'm making my first app. Basically I'm parsing HTML and sending it as JSON to the client.
Right now I've two sources for the HTML data but I could have more in the future. Because of this I thought that it'd be a good idea to remove the code responsible to parse the HTML from the controller and put it into a service layer. I came up with this structure:
app
controllers
main_controller.rb
model
project.rb
task.rb
services
source1_service.rb
source2_service.rb
The MainController call both services to get the projects and tasks; each service parse its own HTML.
Is this a good solution? Is there a more RoR way to do this?
put your services in your models directory, there is no rule that all models have to extend from ActiveRecord::Base, but your services are opaquely data models to the rest of your app (if I understand you right). Ideally, let the service code mimic active record so other people that are just using your model code dont have to know its a different than any other model in your rails app.
Unlike in the Java world, 'the service layer classes' concept is not really popular/used in the RoR world. Its a good idea to remove that code form your controllers (you want your controllers to be thin). But i think you can inject them to your models. If you feel its getting too complicated you can break up your extra code into modules and mixin those modules to your models.
Its not the one and only way of doing things though.
However if parsing HTML include some common logic that can be reused, even in another project its a good idea to put it inside the lib/ folder.

How to create a REST API for a Ruby application?

I would like to know how to provide a Ruby application with a REST API. I could code something based on Ruby's TCPServer API, but that seems a bit low-level. Do you think it would be a good solution? Or do you recommend a better approach?
You can use Sinatra to write tiny, focused web applications and lightweight REST services very quickly.
In the documentation section they highlight a couple of videos on that matter:
Adam Wiggins and Blake Mizerany present Sinatra and RestClient at RubyConf 2008. The talk details Sinatra’s underlying philosophy and reflects on using Sinatra to build real world applications.
Adam Keys and The Pragmatic Programmers have started a series of screencasts on Sinatra. The first two episodes cover creating a tiny web app and creating a REST service. $5 a pop.
You can also use rails as well, but that's a little overkill...
There are several layers involved when desiging a RESTful API, and at each layer there are several valid approaches.
TCPServer is indeed very low level, since you would have to implement the HTTP protocol yourself, which is not recommended.
One step up would be Rack, which takes care of all the low-level HTTP details. This is what all Ruby web frameworks like Rails, Sinatra or Ramaze use under the hood. It also assures that your application works on various application servers, like Passenger, Thin or Unicorn.
But even Rack is still low level, it gives you HTTP, but higher level frameworks take the boilerplate out of typical web programming. For an API you could look at a minimal framework like Sinatra, or a framework specifically designed for APIs like Grape or Rails::API. These will already assume a RESTful style API, so you should find them to be a natural fit.
Typical RESTful APIs are characterized by having resources identified by guessable (convention driven) URLs, and operations on those based on HTTP methods (verbs) like GET, POST, PUT, DELETE and PATCH. To truly embrace the spirit of REST as it was described by Roy Fielding however, you could move towards a more full "Hypermedia" API. The most visible difference is that responses are more self-contained. They are of well-defined media types (defined by yourself or by existing specs) containing links to related resources, rather than merely numerical ids. Similarly responses contain templates/forms describing the operations that can be performed. (There is more to it, but on the surface level that's what you will notice.)
This makes the API more discoverable, both by humans and machines, and it allows for a greater freedom in evolving the API. There could be a performance drawback, since a client typically would need to do more requests to achieve the same thing, but this can be prevented by well thought out design and caching. Garner is specifically made to provide easy server-side caching.
You could define your own media types that suit your application, commonly on top of JSON or XML, or you could look at existing specifications, notably Collection+JSON, HAL and JSON-API. It seems at the moment HAL has the biggest traction, with several libraries available on a variety of platforms.
There is seemingly not a whole lot happening around JSON-API, but two signifacnt projects, ActiveModel::Serializers and Ember-data, are both adopting (and at the same time, developing) this format, which means it could become a popular choice in the Ruby/Rails world.
Edit : typo
I'm using Sinatra too to develop simple REST solutions.
The thing is Sinatra is so flexible in many ways. You can build your project structure the way you like more. Usualy we have a lib/ tmp/ and public/ directories and a config.ru and app.rb files but as I sayd you can build whatever you want.
To remember is that Sinatra is not an usual MVC just because de M (model). For you to use sinatra for Simple CRUD web applications you need simply to load a gem.
require 'datamapper'
or other of your choice like sqlite, sequel, ActiveRecord, ...
and voilá you got a ORM under your Sinatra.
Under Sinatra you define routes that obey to four main proposes GET, PUT POST and DELETE.
require 'rubygems'
require 'sinatra'
get '/' do
erb :home
end
get '/API/*' do
api = params[:splat]
#command_test = api[0]
#command_helo = api[1]
#...
def do_things(with_it)
#...
end
#...
end
__END__
##home
helo
well you got the ideia :)
Finally. Learning Sinatra is not a waste of time because of it simplicity and because it gives (me) foundations of what web programming is.
I think In a near future it will be possible to "inject" Sinatra apps (Rack Apps) into a Rails3 project.
Take a look into github, there you will find many project built with Sinatra.
For further reading checkout Sinatra::Base.
For simple REST APIs I would also consider working directly against the Rack library (i.e. you may not need a framework like Sinatra). Routing for example can be quite easy for simple cases. I've put together a little example here: https://gist.github.com/4685445

Resources