GET /uses HTTP/1.1
Host: jsrn.net
GET | The HTTP verb. Commonly GET, POST, PATCH or DELETE. |
/uses | The path being requested. |
HTTP/1.1 | The version of HTTP to be used. |
Host: | One of potentially several headers passed along with the request. |
HTTP/1.1 200 OK
Date: Mon, 23 May 2005 22:38:34 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 155
Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux)
Accept-Ranges: bytes
Connection: close
<html>
<head><title>An Example Page</title></head>
<body><p>Hello World!</p></body>
</html>
How does the request reach our Ruby application?
_____________________ _______________ | | | | | webserver | | "the web" |->| (nginx, apache | |_____________| | etc.) | |___________________| __________V__________ ______________________ | | | | | app server | | | | (puma, unicorn |->| your application | | etc.) | | | |___________________| |____________________|
require 'socket'
server = TCPServer.new(5678) # Bind to a socket
while session = server.accept # Take the next connection
request = session.gets # Read the request
session.print "HTTP/1.1 200\r\n" # Respond
session.print "Content-Type: text/html\r\n"
session.print "\r\n"
session.print "Hello world!"
session.close # Close the connection
end
What application servers are there?
unicorn, puma, passenger, thin, falcon, prax, okay, OKAY. That's enough. Jeez.Your application server is going to want to pass requests to your application.
Do they speak the same language?
Who defines that language?
"a modular Ruby webserver interface"
Rack does the thinking, so you don't have to.
Your favourite Ruby (Rails, Hanami, Sinatra) applications are actually Rack applications.
#call(env)
[status_code, headers, body]
.
{
"REQUEST_METHOD" => "GET",
"PATH_INFO" => "/uses",
"SERVER_PORT" => 80,
"REMOTE_ADDR" => "127.0.0.1",
"HTTP_USER_AGENT" => "Mozilla/5.0 blah blah"
# lots more!
}
[
200,
{ 'Content-Type' => 'text/html' },
["Hello, world!"]
]
✅ | ❌ |
---|---|
unicorn | |
puma | |
passenger | |
thin | |
falcon | |
prax |
# app.rb
class App
def call(env)
[
200,
{ 'Content-Type' => 'text/html' },
["Hello, world!"]
]
end
end
# config.ru
require './app'
run App.new
rackup is a useful tool for running Rack applications
# Automatically looks for config.ru
# and runs the application on port 3001
rackup -p 3001
This is the configuration file used by Rack-based servers. Here's the one from a new Rails 6.1 project.
require_relative "config/environment"
run Rails.application
Rails.application.load_server
Add behaviour without changing your application.
Essentially also a rack application.
<insert incredible live coding sequence>
We just made a very (very) lightweight MVC framework.
No Rails, no Hanami, no Sinatra. Scarcely any gems at all.
What we've just done is Rack and a little Ruby code. Rails is Rack and a lot of Ruby code.
Ruby web frameworks do a heck of a lot, but we really owe a debt of gratitude to just plain ol' rack.
The top 100 Rack contributors as of 19th January 2021.
leahneukirchen, raggi, tenderlove, scytrin, josh, jeremyevans, ioquatix, rkh, spastorino, manveru, rtomayko, jeremy, deepj, josevalim, qerub, brainopia, oscardelben, rafaelfranca, postmodern, eileencodes, FooBarWidget, thomasklemm, yhirano55, zenspider, olleolleolle, changemewtf, krzysiek1507, jodosha, styd, kamipo, rinaldifonseca, lukaso, mtodd, tgxworld, sigmavirus24, vipulnsward, thedarkone, radar, jkowens, janko, matthewd, vais, schneems, sophiedeziel, thinkerbot, byroot, dkubb, fatkodima, SamSaffron, ender672, tonytonyjan, bestie, Drenmi, dblock, Jamie0, andrykonchin, alup, osamtimizer, lenny, felixbuenemann, evanphx, KitaitiMakoto, carlzulauf, technomancy, yeban, lanzhiheng, VBart, gjtorikian, alindeman, urielka, dayflower, eregon, davydovanton, martoche, candlerb, itnsk, esparta, AlexKVal, p8, NikolayRys, Sean0628, AlexWayfer, NickLaMuro, ChrisBr, igas, tomelm, tompng, CJKinni, ohler55, bdewater, da2x, okuramasafumi, kirs, prathamesh-sonpatki, greysteil, hyun-park, zzak, alecclarke, ziggythehamster, pvande, and many more