Ruby API with Sinatra

Để viết API có rất nhiều cách để viết bạn có thể tạo vởi rails project. Nhưng ở đây mình xin giới thiệu với mọi người cách tạo ra các API 1 cách đơn giản với sinatra.
I. API with Sinatra.
1, Install.
cài đặt sinatra gem file:
gem install sinatra
2, Getting started: Hello World
đầu tiên bạn cần tạo file: app.rb
# app.rb
require 'sinatra'
class HelloWorldApp < Sinatra::Base
get '/' do
"Hello, world!"
end
endruby app.rb là có thể chạy được api rồi.
3. Routes
trong sinatra 1 route được định nghĩa với 1 method HTTP
get '/' do .. show something .. end post '/' do .. create something .. end put '/' do .. replace something .. end patch '/' do .. modify something .. end delete '/' do .. annihilate something .. end options '/' do .. appease something .. end link '/' do .. affiliate something .. end unlink '/' do .. separate something .. end
Trong link cũng có thể bao gồm các parameters. Dữ liệu được lấy thông qua hash: params.
get '/hello/:name' do
# Khi gọi link "GET /hello/foo" and "GET /hello/bar"
# params[:name] sẽ lấy được ra là 'foo' or 'bar'
"Hello #{params[:name]}!"
endChúng ta cũng có thể đặt tên cho param chuy cập. như ví dụ trên ta sẽ gắn param name vào biến n.
get '/hello/:name' do |n|
# khi gọi link "GET /hello/foo" and "GET /hello/bar"
# params[:name] sẽ là 'foo' hoặc 'bar' và được lưu trong biến n
"Hello #{n}!"
endTrong route ta cũng có thể sử dụng ký hiệu *, các giá trị được truyền vào * sẽ dược lưu trong params[:splat] kiểu array.
get '/say/*/to/*' do # gọi link /say/hello/to/world params[:splat] # = ["hello", "world"] end get '/download/*.*' do # gọi link /download/path/to/file.xml params[:splat] # = ["path/to/file", "xml"] end
cũng giống như trên ta có thể gắn các * vào các biến khác nhau.
get '/download/*.*' do |path, ext| [path, ext] # = ["path/to/file", "xml"] end
Ta cũng có thể sử dụng matching với Regular Expressions!.
get %r{/get/(\d\d)-(\d\d)-(\d\d\d\d)} do|month,day,year|
"Get requested from #{month}/#{day} in #{year}"
endII. Nginx Proxied to Unicorn
Để chạy các ứng dụng API của sinatra trên server 1 cách dễ dàng và tốt hơn người ta thường dùng kết hợp Nginx và Unicorn. Hướng dẫn dưới đây sẽ giúp các bạn thiết lập nó. Trước tiên ban phải cài đặt nginx và uncron.
install nginx.
add-apt-repository ppa:nginx/$nginx apt-get update apt-get install nginx
install uncron
gem install unicorn
Chúng ta sẽ tìm hiểu sâu hơn thông qua ví dụ dưới đây. Chúng ta tạo ra 1 app với cấu trúc như sau:
app | +-config.rb | +-myapp.rb | +-unicorn.rb | +-tmp | | | +-shockets | | | +-pids | +-log
trong config.rb ta dùng đoạn code sau
require "rubygems" require "sinatra" require File.expand_path '../myapp.rb', __FILE__ run MyApp
trong file myapp.rb sử dụng code sau
require "rubygems"
require "sinatra/base"
class MyApp \< Sinatra::Base
get "/" do
"Hello, nginx and unicorn!"
end
endcấu hình trong unicorn.rb
# set path to app that will be used to configure unicorn,
# note the trailing slash in this example
@dir = "/path/to/app/"
worker_processes 2
working_directory @dir
timeout 30
# Specify path to socket unicorn listens to,
# we will use this in our nginx.conf later
listen "#{@dir}tmp/sockets/unicorn.sock", :backlog => 64
# Set process id path
pid "#{@dir}tmp/pids/unicorn.pid"
# Set log file paths
stderr_path "#{@dir}log/unicorn.stderr.log"
stdout_path "#{@dir}log/unicorn.stdout.log"Trong /etc/nginx/ ta sử file config như sau:
# this sets the user nginx will run as,
#and the number of worker processes
user nobody nogroup;
worker_processes 1;
# setup where nginx will log errors to
# and where the nginx process id resides
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
# set to on if you have more than 1 worker_processes
accept_mutex off;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /tmp/nginx.access.log combined;
# use the kernel sendfile
sendfile on;
# prepend http headers before sendfile()
tcp_nopush on;
keepalive_timeout 5;
tcp_nodelay on;
gzip on;
gzip_vary on;
gzip_min_length 500;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
gzip_types text/plain text/xml text/css
text/comma-separated-values
text/javascript application/x-javascript
application/atom+xml image/x-icon;
# use the socket we configured in our unicorn.rb
upstream unicorn_server {
server unix:/path/to/app/tmp/sockets/unicorn.sock
fail_timeout=0;
}
# configure the virtual host
server {
# replace with your domain name
server_name localhost:8081; # tên URL
# replace this with your static Sinatra app files, root + public
root /path/to/app; # dẫn tới nơi để project của bạn.
# port to listen for requests on
listen 8081; # nghe ở cổng: 8081 ban có thể lựa chon cổng cho riêng mình.
# maximum accepted body size of client request
client_max_body_size 4G;
# the server will close connections after this time
keepalive_timeout 5;
location / {
try_files $uri @app;
}
location @app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
# pass to the upstream unicorn server mentioned above
proxy_pass http://unicorn_server;
}
}
}Để chạy chương trình ta có thể sử dụng 1 file sh(run.sh) như sau
#!/bin/sh
### BEGIN INIT INFO
# Provides: unicorn
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts unicorn
# Description: starts uniconr using start-stop-daemon
### END INIT INFO
set -u
set -e
export PATH=/usr/local/rbenv/bin:$PATH
export RBENV_DIR=/usr/local/rbenv
export RBENV_ROOT=/usr/local/rbenv
APP_ROOT=/path/to/app/ # đường link tới app.
PID=APP_ROOT/tmp/pids/unicorn.pid
RAILS_ENV=development
export PATH="$RBENV_ROOT/shims:$RBENV_ROOT/rbenv:$PATH"
CMD="bundle exec unicorn -D -E $RAILS_ENV -c $APP_ROOT/unicorn.rb"
old_pid="$PID.oldbin"
cd $APP_ROOT || exit 1
sig () {
test -s "$PID" && kill -$1 `cat $PID`
}
oldsig () {
test -s $old_pid && kill -$1 `cat $old_pid`
}
case $1 in
start)
sig 0 && echo >&2 "Already running" && exit 0
$CMD
;;
stop)
sig QUIT && exit 0
echo >&2 "Not running"
;;
force-stop)
sig TERM && 0
echo >&2 "Not running"
;;
restart|reload)
sig HUP && echo reloaded OK && exit 0
echo >&2 "Couldn't reload, starting '$CMD' instead"
$CMD
;;
upgrade)
sig USR2 && exit 0
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
;;
rotate)
sig USR1 && echo rotated logs OK && exit 0
echo >&2 "Couldn't rotate logs" && 1
;;
*)
echo >&2 "Usage $0 <start|stop|restart|upgrade|rotate|force-stop>"
exit 1
;;
esacStarting the server
đầu tiên ta khởi dộng nginx:
/etc/init.d/nginx start
sau đó chạy lệnh: ./run.sh start
Stopping the server
rất đơn giản khi muốn dừng server ta chỉ cẩn chạy lệnh:
./run.sh stop
Trên đây là một số hướng dẫn đơn giản của mình về việc tạo và chạy 1 API với sinatra, nginx và uncron. Bài viết còn sơ sài rất mong mọi người góp ý.



