mopcon2014 - 使用 sinatra 結合 ruby on rails 輕鬆打造完整 full stack 網站加 api...

151
使 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務 慕凡(@ryudoawaruat MOPCON 2014 http://5xruby.tw

Upload: mu-fan-teng

Post on 14-Jun-2015

770 views

Category:

Technology


1 download

DESCRIPTION

使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

TRANSCRIPT

Page 1: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

使⽤用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack

網站加 API Service服務 慕凡(@ryudoawaru) at MOPCON 2014

http://5xruby.tw

Page 2: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

⼤大家好

Page 3: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

是說議程好像和營運沒有神⾺馬關係

Page 4: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

⾃自我介紹

Page 5: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

遊戲業 10 年1997 - 2007

Page 6: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

1997

http://goo.gl/m2Xga

Page 7: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

2007

Page 8: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

2007.03 開始全職創業

Page 9: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

2007.03 開始全職創業遊⺠民

Page 10: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Tomlan.TW主業:網站開發與維運

Page 11: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

FSC 福特⾞車友會http://www.focus-sport.club.tw

Page 12: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

FREEBBS台灣免費論壇http://www.freebbs.tw

Page 13: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

⾞車界http://www.carclub.tw

Page 14: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

五倍紅寶⽯石http://5xRuby.tw

Page 15: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

全端技術教育訓練包含但不限於 Ruby / Rails / iOS / Git

Page 16: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

專案開發與技術顧問服務Ruby / Rails / iOS

Page 17: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Co-Working Space台北⾞車站旁,三鐵共構加⾼高速網路

Page 18: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

⽀支援各式社群活動以 Ruby 為主但不限於 Ruby

Page 19: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Ruby Taiwan 社群http://ruby.tw

Page 20: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Ruby Tuesday已舉辦 31 次

Page 21: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Rails Girls Taipei已舉辦四屆,學員超過 200 ⼈人

http://railsgirls.tw

Page 22: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

RubyConf Taiwan2010 - 2014,2015 預定於 9⽉月

Page 23: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

WebConf Taiwan下⼀一屆預定於 2015

Page 24: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Agenda

• Sinatra 簡介

• Sinatra on Rails

• 撰寫 Mobile API Service 的⼼心得

Page 25: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Page 26: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Sinatra—歷史

• 2007年開始

• 主要作者Konstantin Haase(@rkh)

• ⺫⽬目前版本1.4

Page 27: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Micro Framework2,000⾏行程式碼,只有Rails 的 1%

Page 28: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

With Minimal Effort只負責路由與Controller,其它組件任選

Page 29: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Smaller Change Between Releases

主要功能幾乎沒有變動,以新增功能為主

Page 30: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Easy to Bootstrap幾乎不需設定即可啟動

Page 31: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Let’s Try

Page 32: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Hello Sinatra

require 'sinatra' get '/hello' do 'Hello World!' end get '/hello/:name' do "Hello #{params[:name]}!" end

Page 33: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Page 34: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Page 35: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Page 36: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Request的⼀一⽣生

1. 將 HTTP Request 抽象為 request 物件

2. 依據 PATH 決定對應的路由(Route)們

3. 依序執⾏行路由中的程式,以返回值為 Response

Page 37: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

RouteCode Block for Making Response

Page 38: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Route

get '/hello/:name' do # matches "GET /hello/foo" and "GET /hello/bar" # params[:name] is 'foo' or 'bar' "Hello #{params[:name]}!" end

1. HTTP VERB

2. PATH INFO

3. RETURN RESPONSE

Page 39: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Route Type

• Named Parameters

• Splat(Wildcard) Parameters

• Regular Expressions Parameters

• Block Parameters

Page 40: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Wildcard Params

get '/say/*/to/*' do # matches /say/hello/to/world params[:splat] # => ["hello", "world"] end

Page 41: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

RegExp Params

get %r{/hello/([\w]+)} do "Hello, #{params[:captures].first}!" end

Page 42: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Block Params

get '/hello/:name' do |n| # n stores params[:name] "Hello #{n}!" end get '/download/*.*' do |path, ext| [path, ext] # => ["path/to/file", "xml"] end get %r{/hello/([\w]+)} do |c| "Hello, #{c}!" end

Page 43: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Post Form Params和 Rails ⼀一樣,被歸納在 params Hash 內

Page 44: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Render Response

Page 45: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Render View

get '/' do @products = Product.all #render index view by default layout file erb :index end

Default to ERB

Page 46: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Render View#./vies/layout.erb <!DOCTYPE html> <html> <head><title>Page Title</title></head> <body><%=yield%></body> </html> #./view/products.erb <ul> <%@products.each do |product|%> <li><%=product.name%></li> <%end%> </ul>

File Template

Page 47: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

和 Rails Render的差異

• 沒有 Partial

• 檔名強制 Symbol

• 沒有 collection

Page 48: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Filter

before do @member = Member.find(session[:member_id]) end !after do LOGGER.info "Request Finished!" end

Page 49: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

和 Route ⼀一樣有 Paramsbefore "/products/:product_id" do @current_product = Product.find(params[:product_id]) end !before /\/products\/(\d+?).*" do |product_id| @current_product = Product.find(product_id) end

Page 50: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

可執⾏行複數 Filter

before do @member = Member.find(session[:member_id]) end !#GET /products/1 before "/products/:product_id" do @product = Product.find(params[:product_id]) end !get "/products/:id" do # @member / @product 都有值 end

依照載⼊入順序

Page 51: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Filter 參數延續傳遞問題

#GET /products/1 before "/products/:product_id" do #params[:product_id] => 1 end !get "/products/:id" do #params[:product_id] => nil #params[:id] => 1 end

Page 52: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Request Object

• 繼承⾃自 Rack::Request

• 和 Rails ⼀一樣,request 物件具有 xhr? / path… 等⽅方法讓你存取 request 的資訊

• 不具備部份 Rails的 request 物件的⽅方法例如 subdomain 等

• 預設 cookies 只能從這裡取

Page 53: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

request.accept # 可接受Response Type request.body # request body request.scheme # "http" request.url # "http://example.com/example/foo" request.host # "example.com" request.path # "/example/foo" request.script_name # "/example" request.path_info # "/foo" request.query_string# GET 查詢參數 request.(get|post)? # 是否為指定 Method request.referrer # 參照⾴頁⾯面URL request.user_agent # user agent request.cookies # Cookie Hash request.xhr? # 是否為 Ajax request.ip # client IP address request.env # Rack ENV Hash

Page 54: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Error Block

not_found do 'This is nowhere to be found.' end error ActiveRecord::RecordNotFound do 404, erb(:not_found) end

Page 55: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Helper

helpers do def post_path(post) to "/posts/#{post.id}" end end

Page 56: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

重要的 Helper們• session

• cookies

• to / url

• redirect

• halt

• settings

Page 57: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Session

get '/:value' do session[:value] = params[:value] end

和 Rails 相同,名為 session 的Hash

Page 58: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Use Another Session Store

require "rack/session/redis" use Rack::Session::Redis, { :url => "redis://localhost:6379/0", :namespace => "rack:session", :expire_after => 600 }

Page 59: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Cookie

get '/:value' do request.cookies['cdb_sid'] end

預設其實沒有 cookie helper,要從 request 物件取得 Hash

Page 60: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

to Helper

#mount in '/' to('/') #=> ‘/' !#mount in '/api/v1' to('/') #=> '/api/v1/'

注意相對路徑,別名url

Page 61: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Redirect

get '/foo' do redirect to('/bar') end

等同 Rails 的 redirect_to

Page 62: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Halt

before "/products/:id" do begin @member = Member.find(session[:member_id]) rescue ActiveRecord::RecordNotFound halt 401, erb(:notfound) end end !delete "/products/:id" do #halt後,將不會執⾏行 end

離開現有流程,停⽌止後續 Route 處理並 Render Response

Page 63: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Setting Valueconfigure do set :foo, 'bar' enable :session #set :session, true disable :logging set(:css_dir) { File.join(views, 'css') } end !get '/' do settings.foo? # => true settings.foo # => 'bar' ... end

Page 64: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Configure Block

configure :development do #Only execute when development env enable :logging end !configure do enable :method_override set :view, "app/views" end

在程式啟動時執⾏行⼀一次,開啟 DB 連接或執⾏行設定

Page 65: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Variable Scopeclass MyApp < Sinatra::Base #此處為 Class Scope set :foo, 42 foo # => 42 get '/foo' do # 進⼊入 Request Scope end end

Class Scope

Instance Scope

Page 66: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Variable Scope

• Application / Class Scope

• 發⽣生於Class 宣告或 Configure 區塊

• Instance / Request Scope

• 發⽣生於Route / Filter 區塊

Page 67: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Class 宣告

開始

Request 發⽣生 尋找 Route

是否還有下⼀一個 Code Block?

執⾏行 Code Block

最後⼀一個 Code Block結束 返回 Response

等待下⼀一個 Request

發⽣生

包含FIlter

class MyApp

MyApp.new

此時還會執⾏行 After Filters

Page 68: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Variable Scope

• Application / Class Scope

• 只發⽣生在載⼊入程式時

• Instance / Request Scope

• 每次 Request 發⽣生,都會產⽣生⼀一個新的 Instance(實體)

Page 69: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

變數傳遞持久性

Named Params

Form Params

Instance Variables

Request Object

持久性 僅限於 Route Block 有 有 有

Page 70: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Modular App Stylerequire 'sinatra/base' class MyApp < Sinatra::Base # OR Sinatra::Application set :sessions, true set :foo, 'bar' get '/' do 'Hello world!' end end

Page 71: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Modular V.S. Classic Style

Page 72: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Rack

Page 73: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Rackup File config.ru

Page 74: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Rackup File

# This file is used by Rack-based servers to start the application. !require ::File.expand_path('../config/environment', __FILE__) run Rails.application

Page 75: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Rack Middlewares in Rails

Page 76: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Modular App in Rackup File

#config.ru require 'sinatra/base' class MyApp < Sinatra::Base # OR Sinatra::Application set :sessions, true set :foo, 'bar' get '/' do 'Hello world!' end end run MyApp

Page 77: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Why need Modular?

• 在 Rackup 中被識別(middleware)

• 在 Rails 中被識別

• 做為⼀一個獨⽴立的模組

Page 78: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Ruby Web

Framework

Application Server

Middlewares End Point

Page 79: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Run Multi App in 1 Rackuprequire 'sinatra/base' class App1 < Sinatra::Application get '/' do 'app1' end end class App2 < Sinatra::Application get '/' do 'app2' end end map('/app1'){run App1} map('/app2'){run App2}

Page 80: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Page 81: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Page 82: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Sinatra on RailsMount Rack Middleware in your Rails App

Page 83: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Mount in Rails Route#routes.rb Rails.application.routes.draw do root 'hello#world' resources :customers mount Api::V1, at: '/api/v1' end #lib/api/v1.rb class Api::V1 < Sinatra::Application get '/' do 'API' end end

Page 84: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Mount Outside Rails# This file is used by Rack-based servers to start the application. require ::File.expand_path('../config/environment', __FILE__) require ::File.expand_path('../lib/api/v1', __FILE__) map '/api/v1' do run Api::V1 end run Rails.application

Page 85: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

哪種⽅方式⽐比較好?

Page 86: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Benchmark

Page 87: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Test Suite

• MacPro Retina ’13 2012

• DB:PostgreSQL

• Rails:4.1,Sinatra:1.4.5

• App Server:Thin

Page 88: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

測試程式

• https://github.com/ryudoawaru/rails-metal-test-example-mopcon2014

• 從 DB 的 Customer 資料庫抓 頭 10筆資料 render JSON

Page 89: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

測試⽅方式

• ab -c 10 -n 10 <URL>

• 反覆測試五次

Page 90: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Model Code

class Customer < ActiveRecord::Base def self.fetch(idgt = nil) where("customerid > ?", idgt.to_i).limit(20).map(&:ser) end end

Page 91: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Rails Controller Code

class CustomersController < ApplicationController def index respond_to do |f| f.json do render json: Customer.fetch.to_json end end end end

Page 92: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Sinatra Code

module Api class V1 < Sinatra::Application get '/customers.json' do Customer.fetch.to_json end end end

Page 93: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

config.ru# This file is used by Rack-based servers to start the application. require ::File.expand_path('../config/environment', __FILE__) require ::File.expand_path('../lib/api/v1', __FILE__) map '/ext/api/v1' do run Api::V1 end run Rails.application

Page 94: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

routes.rb

Rails.application.routes.draw do mount Api::V1, at: '/api/v1' root 'hello#world' resources :customers end

Page 95: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

URL 對應表

Rails http://localhost:3000/customers.json

Mount in Rails Route http://localhost:3000/api/v1/customers.json

Mount in Rackup http://localhost:3000/ext/api/v1/customers.json

Page 96: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

測試結果

Rails Mount in Rails Route

Mount in Rackup (outside of Rails)

RPQ平均 150~ 200~ 300+

Page 97: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Why Rails Slow?

Page 98: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Middlewares Stack

Page 99: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Rack Middleware就是

Endpoint APP

Application Server

Middleware

Middleware

Page 100: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

⼀一個⼀一直玩的概念

Page 101: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

堆疊⽐比較

Rails + Sinatra

Application Server

Middleware

Middleware

Page 102: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Rails

Application Server

Middleware

Middleware

Middleware

PATH

Rails

Middleware

map ‘/’

map ‘/ext/api/v1’

Page 103: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

其實 Rails 也有 rails-api Gem

減少 Middleware Stack

Page 104: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Sinatra on Rails 架構的好處

Page 105: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

在同⼀一個專案下,實際分離前後台

• 程式碼在同⼀一個專案

• 維護性++

Page 106: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

發揮各⾃自⻑⾧長處

• ⽤用 Rails 寫後台—> 快速⽅方便

• Sinatra 寫 API —> 簡潔有⼒力

Page 107: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

共⽤用部份資源

• Model

• Library

• 載⼊入的 Gem

• Helper(不建議)

Page 108: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

節省⾃自⾏行編寫 Bootstrap 程序的時間與精⼒力

Page 109: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

沒有 Rails 就要⾃自⼰己寫

• Rubygem / Bundler

• Require

• Model / DB 連接

• Library的前置作業或設定(例如 Uploader)

Page 110: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

前後台⽤用 Hostname 分離

• api.example.com -> API ⽤用

• backend.example.com -> 管理介⾯面⽤用

Page 111: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

可以只開啟Rails或只開啟Sinatra

#config.ru if ENV['RUN_ONLY'] == 'rails' run Rails.application elsif ENV['RUN_ONLY'] == 'sinatra' run MySinatraApp else map '/api/v1' do run MySinatraApp end run Rails.application end

Page 112: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

使⽤用 Sinatra 開發 Mobile API的注意事項

Page 113: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

注意 Content-Type Header

Page 114: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

before '*.json' do headers "Content-Type" => "text/json" end

Page 115: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

活⽤用 Status Code

get '/events/:id.json' do begin event = Event.find(params[:id]) halt 404 end end

Page 116: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

活⽤用 Response Header

Page 117: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Response Page Information

get '/events.json' do collection = Event.api_search(…) headers 'total_pages' => collection.total_pages.to_s headers 'total_count' => collection.total_count.to_s headers 'current_size' => collection.size.to_s render_collection(collection).to_json_with_encode end

Page 118: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Mobile API ⾝身份認證⽅方式

以⾃自有服務為主

Page 119: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Request Header通常 APP 的 WEB Client 都不具備 Session 功能

Page 120: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Auth By Header#Helper def current_mobile_session token = request.env[‘HTTP_AUTHTOKEN'] || session[:authtoken] @current_mobile_session ||= MobileSession.auth_api_session(token) end !def current_user @current_user ||= current_mobile_session.user if current_mobile_session.present? end

Page 121: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Token的來源

• 裝置的 UUID(裝置辨認)

• 某種時間段戳記(例如 EPOCH / ⼀一週 or ⼀一天秒數)

• User Table 的某個欄位(Access Token)

• 以上三者 MD5 加密

Page 122: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

WebView in APP問題

• 有時會遇到需要辨認⾝身份的 WebView(如購物)

• WebView 在啟動同時發出的 Request 可以包含⾃自訂 Header,但是在 WebView 內的連結或表單不⾏行

• 反過來,在 WebView 內可以⽤用 Cookie / Session

Page 123: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

流程

1. 開啟WebView,發出初始 HTML Request(有Header)

2. Server 端接收 Request 時,設定 Session

3. WebView 內由 User 點擊再發出的 Request 就會有 Session

Page 124: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

範例

before do token = request.env['HTTP_AUTHTOKEN'] || session[:authtoken] ##接下來⽤用 token 進⾏行認證 end

Page 125: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

JSON Generation

Page 126: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Page 127: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

#config/initializer/hash.rb [Array, Hash].each do |klass| klass.class_eval do def to_json_with_encode JSON.generate(self, ascii_only: true) end end end

Page 128: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

對於從寫 Web 轉到寫 Mobile API 的幾點⼩小建議

Page 129: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

時間欄位請傳EPOCH 整數

class Customer < ActiveRecord::Base def created_at_i created_at.to_i end end

Page 130: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

使⽤用 before / after_id⽽而⾮非分⾴頁

#in Controller # GET ‘/pms/before/12345’ get '/pms/before/:pmid' do Pm.before_pmid(params[:pmid]) .... end

Page 131: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

減少 Request 數量顧及流暢性

Page 132: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

N個願望⼀一次滿⾜足

get '/all.json' do {unread_messages: current_user.pms.all, events: Event.recent(10) }.to_json end

Page 133: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

論寫 Sinatra 的必要性藏在魔法後⾯面的東⻄西

Page 134: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

標準的 Rails 程式碼# in app/controllers/customers_controller.rb class CustomersController < ApplicatoController ... def index @customers = Customer.page(1) end end # in app/views/customers/index.html.erb <ul> <%=render @customers%> </ul> # in app/views/customers/_customer.html.erb <li><%=customer.id%>:<%=customer.name%></li>

Page 135: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

它可以產⽣生的 HTML

<ul> <li>1:很好填</li> <li>2:⾃自⼰己填</li> <li>3:不想填</li> <li>4:給你填</li> </ul>

Page 136: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

你知道 render 那⾏行發⽣生了神⾺馬事嗎?

Page 137: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

順序

1. 查看@customers 集合中的成員 Class -> Customer

2. 以 Class Name 查詢是否有相對應的 Partial View 存在

3. 以 @customers 為 collection 的值來 render Partial

<%=render @customers%>

<%=render partial: 'customer', collection: @customers%>

Page 138: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

另⼀一個常⾒見問題

# <%=form_for @customer do |f|%> .... <%end%> #將會產⽣生 <form action="/customers/1" method="post"> <input name="_method" value="put"/> ... </form>

假設 @customer 是⼀一筆存在的 Customer 紀錄, id為 1

Page 139: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Q:為何 @customer 可以轉成 /customers/1

Page 140: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

@customer.new_record? # false @customer.class.to_s # Customer @customer.class.to_s.underscore # customer @customer.class.to_s.underscore.pluralize # => customers

Page 141: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Q:請問 pluralize 是 Ruby 預設的 String Instance

Method嗎?

Page 142: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

i[~] $ irb 2.1.3 :001 > 'customer' => "customer" 2.1.3 :002 > 'customer'.pluralize NoMethodError: undefined method `pluralize' for "customer":String from (irb):2 from /Users/ryudo/.rvm/rubies/ruby-2.1.3/bin/irb:11:in `<main>' 2.1.3 :003 >

Page 143: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Q:_method 是什麼?

Page 144: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

_method Param

• 瀏覽器不⽀支援 GET / POST 以外的 REQUEST METHOD

• ⽤用 _method 代替 REQUEST METHOD

• 簡稱 Method Override

Page 145: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

寫 Sinatra ,預設你必需⾃自⾏行處理這些問題

Page 146: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

http://shugo.net/tmp/rails-syndrome.pdf

Page 147: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

“Difference between a master and a beginner? The master has failed more times than the beginner has

even tried.”⼤大師與新⼿手之間的差別,就是⼤大師失敗過的次

數,⽐比新⼿手嘗試過的次數還多

Page 148: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

共勉之

Page 149: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Fin

Page 150: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

Contact Me• 慕凡

• http://ryudo.tw

[email protected]

• Github:ryudoawaru

• Twitter:ryudoawaru

Page 151: Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

代客徵求 ROR Developer

• 台北知名網站公司

• ⽉月薪 45 - 60 K

• 職缺:Junior ROR Developer

• 詳情請洽 http://goo.gl/h2YOAU 或找我

• 寄履歷到 [email protected]