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 end
ruby 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]}!" end
Chú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}!" end
Trong 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}" end
II. 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 end
cấ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 ;; esac
Starting 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 ý.