What framework do you recommand for writing simple web applications in ruby, between WebRick, Mongrel and Sinatra ?
I would like to answer in json to requests from a client. I would like to have my own code decoupled from the Http framework as much as possible.
Do you know any other framework ?
I wouldn't recommend using WEBrick, period. You would best be served by a Rack-compatible framework. You could write directly in Rack for speed, but it's really unnecessary since Sinatra is so much more pleasant and still very fast.
You may also want to check out Halcyon. I don't know if it's still maintained, but it's designed for writing APIs that respond in JSON.
WEBrick and Mongrel are servers, not frameworks for building web applications. As such, they have APIs that are lower level and tied to their own idiosyncrasies which makes them a bad place to start if you want to design your web application so that it can run on different servers.
I would look for a framework that builds on Rack, which is the standard base layer for building web apps and web frameworks in Ruby these days.
If you are making something really simple, learning Rack's interface by itself is a good place to start.
E.G., a Rack Application that parses json out of a post request's body and prints it back out prettified.
# in a file named config.ru
require 'json'
class JSONPrettyPrinterPrinter
def call env
request = Rack::Request.new env
if request.post?
object = JSON.parse request.body
[200, {}, [JSON.pretty_generate(object)]]
else
[200, {}, ["nothing to see here"]]
end
end
end
run JSONPrettyPrinterPrinter
you can run it by running rackup in the same dir as the file.
Or, if you want something a bit more high level, you can use sinatra, which looks like this
require 'sinatra'
post '/' do
object = JSON.parse request.body
JSON.pretty_generate(object)
end
Sinatra's README is a good introduction to it's features.
Related
What is this file config.ru, and what is it for in Sinatra projects? In my lanyard of the project, such code is written:
require './app'
run Sinatra::Application
config.ru is a Rack configuration file (ru stands for "rackup"). Rack provides a minimal interface between web servers that support Ruby and Ruby frameworks. It's like a Ruby implementation of a CGI which offers a standard protocol for web servers to execute programs.
Rack's run command here means for requests to the server, make Sinatra::Application the execution context from which Sinatra's DSL could be used. All DSL methods on the main are then delegated to this class.
So in this config.ru file, first you require your app code which uses Sinatra's DSL then run the Sinatra framework. In the context of Sinatra::Application if your app.rb contained this:
get '/' do
'Hello world!'
end
The get block would mean something to Rack, in this case when someone tries to access (GET) the home url, send back 'Hello world!'
Rack provides a minimal interface between webservers that support Ruby and Ruby frameworks.
The interface just assumes that you have an object that responds to a call method (like a proc) and returns a array with:
The HTTP response code
A Hash of headers
The response body, which must respond to each
You can run a basic Rack server with the rackup command which will search for a config.ru file in the current directory.
You can create a minimal hello world server with:
# config.ru
run Proc.new { |env| ['200', {'Content-Type' => 'text/html'}, ['Hello World']] }
# run this with the `rackup` command
Since Sinatra just like Rails builds on Rack it uses rackup internally to interface between the server and the framework. config.ru is thus the entry point to any Rack based program.
What it does is bootstrap the application and pass the Sinatra::Application class to rack which has a call class method.
Sinatra::Application is then responsible for taking the incoming request (the env) and passing it to the routes your application provides and then passing back the response code, headers, and response body.
config.ru is a default configuration file for a rackup command with a list of instructions for Rack.
Rack is an interface and architecture that provides a domain specific language (DSL) and connects an application with a world of web. In two words, it allows to build web applications and work with requests, responses (and many other web-related technologies) in a most convenient way.
Sinatra as well as Rails are web frameworks, so they both use Rack:
http://recipes.sinatrarb.com/p/middleware
https://guides.rubyonrails.org/rails_on_rack.html
I am trying to have two separate Ruby programs to communicate, one with the Sinatra gem, and another with the HTTParty gem. What I am attempting to do is post data to the Sinatra program from a HTTP post request in the other program.
This is the code that sends the data.
HTTParty.post('https://notgivingawaymydomain/post_data', {something: foo})
However, I don't know how to receive the data on the other end. I've tried a few things I researched on the internet but none seem to work.
EDIT
My code on the other end is really nothing special at the moment, but I'll put what I've been trying.
post '/post_data' do
#not sure how to access the hash that my post request sent here
end
The post data is available in the params object inside your Sinatra route:
post '/post_data' do
data = params["something"] # => my_value is now 'foo' in this example
#... rest of code
end
Sinatra only parses the data if it is application/x-www-form-urlencoded (which it is in this case) or multipart/form-data. If you wanted to POST another type (e.g. JSON) you would need to parse the request body yourself using request.body:
post '/json_data'
# request.body is an IO object
data = JSON.parse(request.body.read)
end
Be sure to get the syntax of your HTTParty call correct. You need to specify the body: key of the options:
HTTParty.post('http://localhost:4567/post_data', body: {something: "foo"})
if you want to post data via HTTP you need a web-server on the receiving end.
sinatra describes itself as Sinatra is a DSL for quickly creating web applications in Ruby with minimal effort
so in itself it is not a webserver, but it can be run through a webserver to process the data that you post via HTTP. it is bundled with a webserver, so you can start it right away.
if you look at the sinatra README it says
It is recommended to also run gem install thin, which Sinatra will pick up if available.
thin is a reliable webserver that is recommended to run sinatra web applications.
In the real world, thanks to Rack::Builder, I've started up two sinatra apps and mapped one to "/api/v1" and the other to "/ui".
I'd like the app mapped to /ui to be able to take advantage of the routes in /api but,
becuase they're separate, the ui app can't perform calls on the api side of things.
Is there a way to call one app's route from another via rack, or should I just use Net::HTTP ?
Here's a simplified example of what I'm trying to do:
#/usr/bin/ruby
require 'sinatra'
class API < Sinatra::Base
get '/accounts/' do
'{"json":"account_data"}'
end
end
class UI < Sinatra::Base
get '/accounts/' do
# How do I get /api/accounts?
# call "/api/accounts" obviously does not work
# would use erb here to render accounts list in human readable form
end
end
rack = Rack::Builder.new
rack.map "/ui" do
run UI.new
end
rack.map "/api" do
run API.new
end
Rack::Server.start :app => rack
exit
Thanks very much!
If these apps are racked up in Rack together, they have no real connectivity. What Rack does call .call(env) on whatever app you have racked up and that responds with [status,env,body] You can have layers in the middle that act on and modify env. Your Rack is triggering #call on whatever app you mapped to respond to that path. The called app has no concept of what is running in Rack. Nor can it call another app unless there is a handle for it in env that was populated upstream.
But you have to consider why you decided to make these 2 different apps in the first place. I would imagine it is due to the fact that there could be multiple apps using the API. Or you enjoy the decoupled nature. So in that case you have to think if you would want some coupling through Rack at all. What if the API was on another server? Any internal link between the 2 through Rack would break the UI application. If you always know your API will be self contained on the same machine you could just as well make it a library and not do HTTP calls.
So even if it is possible to call routes from a co racked up app I would never do it. The whole reason for having API servers is to have a decoupled layer. And you should access that layer via HTTP so it would work if it were on same box or across the world.
I wrote my own FaceBook library that uses actual Curl requests, not libcurl.
Is there a way to test it? I'm asking this because most solutions involve using something like fakeweb which as far as I can tell will not work here.
The existing code can be found on my github page.
One approach would be to use a different host/port in test mode (eg localhost:12345)
Then in your test run a sinatra or webrick servlet on that port that you configure to respond to the requests your code should be making
You could mock Request.dispatcher with an expected behavior, pretty much like Fakeweb would do.
There are a few examples on this file, specially https://github.com/chrisk/fakeweb/blob/master/lib/fake_web/ext/net_http.rb#L44.
When running your tests/specs, monkey-patch the run method of your Request class to hook into the Marston VCR library. See the existing library_hooks subdir for examples and ideas on how to do this -- the fakeweb implementation is a good place to start.
VCR works well with live services like Facebook's because it captures interactions "as is", and VCRs can be easily re-recorded when the services change.
I'm running into problems with your library, however. You need to require the cgi and json libraries; it also looks like it requires a Rails environment (it's failing to find with_indifferent_access on Hash).
ruby newbie alert! (hey that rhymes :))
I have read the official definition but still come up empty handed. What exactly is it when they say middleware? Is the purpose using ruby with https?
the smallish tutorial at patnaik's blog makes things clearer but how do I do something with it on localhost? I have ruby 1.9.2 installed along with rack gem and mongrel server.
Do I start mongrel first? How?
Just to add a simplistic explanation of Rack (as I feel that is missing):
Rack is basically a way in which a web app can communicate with a web server. The communication goes like this:
The web server tells the app about the environment - this contains mainly what the user sent in as his request - the url, the headers, whether it's a GET or a POST, etc.
The web app responds with three things:
the status code which will be something like 200 when everything went OK and above 400 when something went wrong.
the headers which is information web browsers can use like information on how long to hold on to the webpage in their cache and other stuff.
the body which is the actual webpage you see in the browser.
These two steps more or less can define the whole process by which web apps work.
So a very simple Rack app could look like this:
class MyApp
def call(environment) # this method has to be named call
[200, # the status code
{"Content-Type" => "text/plain", "Content-length" => "11" }, # headers
["Hello world"]] # the body
end
end
# presuming you have rack & webrick
if $0 == __FILE__
require 'rack'
Rack::Handler::WEBrick.run MyApp.new
end
You would do well to search for other questions & answers that make sense to you. Try "Getting Started with Rails" or "Ruby Web Development". A lot of different topics on this site have been devoted to this exact subject, so you might save yourself some trouble there...
Ignoring the specifics of your question for a minute, it seems like you want to learn Ruby and build web apps. Before you start delving into Rack or Mongrel or anything else, you should know that there are 2 well established frameworks that help build Ruby web applications. The first is Ruby on Rails, and the other is Sinatra. There are many others, but these are the most well documented on Stack Overflow and the internet in general.
Check out the following links for some background...
www.rubyonrails.org
SO: building-a-website-best-practice-and-architecture-with-ruby
www.railstutorial.org
SO: learning-ruby-on-rails
If you still have a burning desire to answer your question - "what is rack?", you should follow the same process, and end up at this Stack Overflow Answer:
What is Rack middleware?
Good luck!
Very nice answers yes indeed. For my two cents I'll add this because if you know how to get to the documentation behind the scenes here you will find lots of information as I have it stashed here and by no means is all that I have.
http://myrackapps.herokuapp.com/