Published 2022-12-02.
Last modified 2022-12-04.
Time to read: 3 minutes.
ruby
collection.
Sinatra is a F/OSS DSL, also referred to as a micro-framework, for quickly creating web applications in Ruby with minimal effort.
About Sinatra
Sinatra is tiny; its source code is less than 2000 lines. Small, but mighty, and very influential. Since its release in 2007, a partial list of other web frameworks that Sinatra has inspired and are currently active at the time of writing includes Compojure, Express.js, Fiber, Finatra, Flask, Javalin, Padrino, Pedestal, Play Framework, Roda, Scalatra, Scotty, Spark, Spring Boot, and Trot.
Sinatra is the second-most popular web framework in the Ruby ecosystem, after Ruby on Rails.
Sinatra and Ruby on Rails are somewhat similar
because they both extend Rack.
This means that middleware that conforms to the
rack
specification
works with all web frameworks that extend rack
.
Sinatra is a good choice for system integration because it is simple, malleable, has few dependencies and is reasonably efficient. Sinatra webapps are a good mechanism for integrating web servers such as nginx and Apache httpd with other services, such as e-commerce payment gateways.
The following builds upon this Sinatra webapp:
If you are eager to learn Sinatra, here are two good references:
- Jump Start Sinatra
- Rack is foundational for Sinatra and Ruby on Rails. I will use it in the next article.
Automatic Restart
Sinatra applications can automatically be restarted when their source code changes.
This requires a helper application, such as rerun;
other projects also do similar things.
To install rerun
on Ubuntu:
$ yes | sudo apt install rerun
Rerun is not currently compatible with WSL or WSL2.
Future versions of WSL2 will likely work with rerun
.
Setting Up a Ruby Development
Previously, I wrote about Setting Up a Ruby Development Environment. Follow those instructions first if you want to type along with this article.
Sinatra Request Explorer
Get the project:
$ git clone https://github.com/mslinn/SinatraRequestExplorer.git
$ cd SinatraRequestExplorer
Install the SinatraRequestExplorer
gems:
$ bundle install
Run Sinatra Request Explorer
Development
$ rerun ruby main.rb 9:39:55 [rerun] Sinatrarequestexplorer launched 09:39:55 [rerun] Rerun (760521) running Sinatrarequestexplorer (760542) == Sinatra (v3.0.3) has taken the stage on 9876 for development with backup from Puma Puma starting in single mode... * Puma version: 6.0.0 (ruby 3.1.0-p0) ("Sunflower") * Min threads: 0 * Max threads: 5 * Environment: development * PID: 760542 * Listening on http://127.0.0.1:9876 * Listening on http://[::1]:9876 Use Ctrl-C to stop 09:39:57 [rerun] Watching . for **/*.{rb,js,coffee,css,scss,sass,erb,html,haml,ru,yml,slim,md,feature,c,h} with Linux adapter
Visit the SinatraRequestExplorer
webapp at port 9876.
The web page displayed in response to the GET Test link above is:
HTTP_USER_AGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Method: GET request.accept: */* application/signed-exchange application/xhtml+xml application/xml image/apng image/avif image/webp text/html request.url=http://localhost:9876/dump?a=b&c=d request.fullpath=/dump?a=b&c=d request.path_info=/dump request.params: a=b c=d Computed Content-Type: plain
The web page displayed in response to the POST Test button above is:
HTTP_USER_AGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Method: POST request.accept: */* application/signed-exchange application/xhtml+xml application/xml image/apng image/avif image/webp text/html
request.url=http://localhost:9876/dump request.fullpath=/dump request.path_info=/dump
request.params:
Computed Content-Type: plain
The web page displayed in response to the JSON Test button above is:
HTTP_USER_AGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Method: POST request.accept: */* application/signed-exchange application/xhtml+xml application/xml image/apng image/avif image/webp text/html
request.url=http://localhost:9876/dump request.fullpath=/dump request.path_info=/dump
request.params: field1=value1 field2=value2
Computed Content-Type: plain
Using Curl
Use curl
to invoke the SinatraRequestExplorer
webapp:
$ URL=http://localhost:9876/dump $ curl -d "param1=value1¶m2=value2" -X POST "$URL" <title>SinatraRequestExplorer dump</title> <h2>Post Method</h2> <p>Generated by the post /dump handler.</p> <p>Go to <a href="/">Root</a>.</p> <h2>Request Parameters</h2> <pre> request.url=http://localhost:9876/dump request.fullpath=/dump request.path_info=/dump request.params= param1=value1 param2=value2 HTTP_USER_AGENT=curl/7.85.0 </pre>
The test
script in SinatraRequestExplorer
automates the above invocation and includes others.
#!/bin/bash # Curl, and most browsers, default to sending Content-Type: application/x-www-form-urlencoded for a POST. # Get requests should not specify Content-type because they do not have a body. # Curl defaults to Accept: */*, however each browser defaults to a different default value. # Chrome defaults to Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 # See https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation/List_of_default_Accept_values shopt -s expand_aliases alias curl='curl -L --silent --show-error' function label { printf "\n\n=== $@ ===\n" } URL=http://localhost:9876/dump label "Send GET, accept any type of response" curl "$URL?a=b&c=d" label "Send GET, expect a JSON response" curl -H "Accept: application/json" "$URL?a=b&c=d" label "Send POST, accept any type of response" curl -d "param1=value1¶m2=value2" "$URL" label "Send POST with a form-urlencoded body and a query string, accept any type of response" curl -d "param1=value1¶m2=value2" "$URL?a=b&c=d" label "Send POST with a form-urlencoded body, expect a JSON response" curl -d "param1=value1¶m2=value2" \ -H "Accept: application/json" \ $URL label "Send POST with a JSON body, expect a JSON response" curl -d '{"param3":"value3", "param4":"value4"}' \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ $URL
Production
Rerun
is not something you would want or need in production.
Instead, you could launch Sinatra
webapps such as SinatraRequestExplorer
when the system boots with an entry in crontab
, like this:
@reboot ruby /work/ruby/dependencies/sinatra/SinatraRequestExplorer/main.rb
About the Author
I, Mike Slinn, have been working with Ruby for a long time now. Back in 2005, I was the product marketing manager at CodeGear (the company was formerly known as Borland) for their 3rd Rail IDE. 3rd Rail supported Ruby and Ruby on Rails at launch.
In 2006, I co-chaired the Silicon Valley Ruby Conference on behalf of the SD Forum in Silicon Valley. As you can see, I have the t-shirt. I was the sole chairman of the 2007 Silicon Valley Ruby Conference.
Several court cases have come my way over the years in my capacity as a software expert witness. The court cases featured questions about IP misappropriation for Ruby on Rails programs. You can read about my experience as a software expert if that interests you.
I currently enjoy writing Jekyll plugins in Ruby for this website and others, as well as Ruby utilities.