Giới thiệu Ruby Rack
Nếu đã từng lập trình web với Ruby, bạn đã làm việc với Rack. Có thể nói Rack chính là nền tảng cho các web framework của Ruby. Từ Sinatra, Rails, đến các framework gần đây như Lotus đều dựa trên nền tảng của Rack. Tìm hiểu về Rack giúp ta có hiểu được cách thức hoạt động của các web framework, từ đó tùy biến chúng dễ dàng hơn.
1. Rack là gì?
Document của Rack cung cấp thông tin về Rack như sau:
Rack provides a minimal interface between webservers supporting Ruby and Ruby frameworks.
Vậy có thể hiểu Rack là bước đệm giữa web server và framework Ruby. Webserver ở đây có thể là WEBrick, Thin, Unicorn, Puma, và web framework ở đây có thể là Rails, Sinatra, … Webserver và web framework sẽ dùng Rack để nói chuyện với nhau.
2. Ứng dụng Rack đơn giản
Một Rack application có cấu trúc rất đơn giản: nó là một Ruby Object, định nghĩa hàm call
. Hàm call
này có tham số là một biến environment và trả về response.
Response là một array có 3 item:
- HTTP response code
- Header
- Body của response
Ta thử viết một Rack application đơn giản như sau:
Tạo file config.ru
có nội dung:
gem install rack
nếu chưa cài gem rack.
Để chạy ứng dụng Rack trên ta dùng lệnh
Giải thích hoạt động của ứng dụng trên:
Ứng dụng này làm một nhiệm vụ rất đơn giản, với tất cả các request, trả về respose là đoạn text “Hello from Rack!”, cùng với response code 200.
Khi rackup
ở trên, mặc định Rack sẽ dùng web server có sẵn của Ruby là WEBrick làm web server. Ở đây ta hoàn toàn có thể config để dùng các web server khác
như unicorn, puma, thin…
WEBrick sẽ lắng nghe ở cổng 9292. Khi dùng browser access vào địa chỉ: http://localhost:9292 ta sẽ thấy nội dung trả về là dòng text: “Hello from Rack!”
Khi WEBrick nhận request từ browser, nó sẽ gọi hàm call
của class SimpleRack
mà ta viết ở trên, truyền vào biến env
, lấy nội dung trả về của hàm này để trả về cho browser.
Ta thử xem biến env này có nội dung như thế nào bằng cách trả về nội dung của env
trong response như sau:
Restart ứng dụng rack và request http://localhost:9292 ta thấy nội dung trả về chính là nội dung của biến env. Trong đó có một số key cần chú ý:
PATH_INFO
: path của request. Mặc định sẽ là/
QUERY_STRING
: params của requestREQUEST_METHOD
: http method, GET, POST,…
Thử access bằng địa chỉ: http://localhost:9292/index.php?id=1010 ta sẽ thấy các value tương ứng với các key trên:
PATH_INFO
: /index.phpQUERY_STRING
: id=1010REQUEST_METHOD
: GET
Ta thấy tất các các tham số liên quan đến request đều được gói trong biến env.
Thử chỉnh lại SimpleRack, trả về chuỗi QUERY_STRING
xem sao!
Trong ví dụ trên, để tiện cho việc xử lý mình implement một hàm đơn giản để parse params từ dạng chuỗi sang dạng hash.
Dùng tham số PATH_INFO
ta có thể implement một hàm routing đơn giản như sau:
2. Rack middleware
Sức mạnh của Rack middle nằm ở chỗ chúng ta có thể nối nhiều Rack application lại với nhau, ouput của Rack application sẽ là input của application khác. Việc này cung cấp tính mềm déo cho ứng dụng Rack, ta có thể thêm hoặc bớt các middleware theo ý mình mà không sợ ảnh hưởng đến middleware có sẵn.
Ví dụ điển hình nhất chính là Rails. Rails là một Rack application được tạo thành bởi nhiều Rack middleware. Chẳng hạn:
Để hiểu rõ hơn, ta viết lại ứng dụng SimpleRack với 2 middleware như sau:
Thứ tự thực hiện của ứng dụng Rack trên như sau:
Request --> WEBrick --> Logger --> SimpleRack --> Logger --> Browser
Logger
sẽ pass request cho SimpleRack
xử lý, SimpleRack
xử lý xong trả response lại cho Logger
, Logger
append một dòng log vào response và trả response này về lại cho browser
Vì thế khi access địa chỉ http://localhost:9292 ta thấy ngoài nội dung “Hello from Rack!” còn thêm 1 dòng “Info: This is log of Logger middleware”, dòng này chính là kết quả việc thực hiện middleware Logger
.
Bên cạnh các chức năng cơ bản trên, Rack còn implement sẵn một số hàm helper như parse params, build response,… Chi tiết hơn có thể tham khảo ở document của Rack tại: http://www.rubydoc.info/github/rack/rack
Trên đây là những kiến thức căn bản về Ruby Rack. Hy vọng đã giúp mọi người hiểu rõ về nó.