← 上一章:背景工作及工作排程 下一章:寫測試讓你更有信心 Part 1 →
API 模式
在開發手機應用程式或是一些前端比較吃重的網站應用程式時,常會需要跟後端伺服器交換資料,交換資料的格式常見的有 JSON 或 XML 等格式,這樣的交換介面又稱之 API(Application Programming Interface)。雖然 Rails 的強項之一是資料的 CRUD(新增、修改、刪除)功能,但其實要拿來做 API 伺服器也沒什麼問題。
輸出成 JSON 格式 - 使用 render
這是一個普通的 User Controller:
class UsersController < ApplicationController
# ...[略]...
def index
@users = User.all
end
# ...[略]...
end
這邊的 index
Action 如果沒特別聲明 render
方法,它就會去 app/views/users/
目錄下找同名的 index.html.erb
來呈現畫面,這個我們在前面的章節曾介紹過。但如果不需要輸出 HTML 畫面,可以把 index
Action 改成這樣:
def index
@users = User.all
render json: @users
end
原本的樣子長這樣:
這樣就會直接在 Controller 階段就直接以 JSON 格式輸出,輸出結果如下:
排版整理後結果如下:
[
{
"id": 1,
"name": "孫悟空",
"email": "[email protected]",
"created_at": "2017-07-02T01:04:01.063Z",
"updated_at": "2017-07-02T01:04:01.063Z",
"url": "http://localhost:3000/users/1.json"
},
{
"id": 2,
"name": "貝吉達",
"email": "[email protected]",
"created_at": "2017-07-02T01:04:46.312Z",
"updated_at": "2017-07-02T01:04:46.312Z",
"url": "http://localhost:3000/users/2.json"
},
{
"id": 3,
"name": "丁小雨",
"email": "[email protected]",
"created_at": "2017-07-02T01:04:56.089Z",
"updated_at": "2017-07-02T01:04:56.089Z",
"url": "http://localhost:3000/users/3.json"
}
]
如果你原本是開發手機應用程式的工程師或前端工程師,不需要拜託別人,簡單幾行就可以取得你所需要的 JSON 格式資料了。
但上面這樣的寫法,原本 /users
的頁面連不上了,也就是說如果要同時可以呈現 HTML 跟 JSON,得另外想辦法:
def index
@users = User.all
respond_to do |format|
format.json { render json: @users }
format.html { render :index }
end
end
使用 respond_to
可以針對不同的格式(html 或 json)輸出不同的結果。除了用 respond_to
之外,讓我們接著看看另一種做法。
輸出成 JSON 格式 - 使用 Jbuilder
不知道大家有沒注意到,其實在使用 Scaffold 產生一堆檔案的時候,在 View 的目錄裡有多一些特別的檔案:
這幾個結尾是 .json.jbuilder
的檔案,就跟 .html.erb
的概念一樣,.html.erb
是指會使用 ERB 樣版引擎來解讀這個檔案,並轉換成 HTML 格式;而 .json.jbuilder
則是使用 Jbuilder 這個 gem,把結果輸出成 JSON 格式。
讓我們看一下 app/views/users/index.json.jbuilder
這個檔案的內容:
json.array! @users, partial: 'users/user', as: :user
看來是去 render users/_user
這個檔案,裡面的內容是:
json.extract! user, :id, :name, :email, :created_at, :updated_at
json.url user_url(user, format: :json)
意思大概就是會輸出 user
物件的 id
、name
…updated_at
等欄位的資料。
原本網址 http://localhost:3000/users
可以看到使用者列表,如果把網址後面加上 .json
變成 http://localhost:3000/users.json
就能得到跟前面 render json: @users
一樣的結果。
不只如此,/users/2
會用 HTML 格式輸出 2 號使用者資料,如果是 /users/2.json
則是會以 JSON 格式輸出這筆資料。
另外,如果我只想印出姓名跟 Email,可以把 users/_user.json.jbuilder
的內容修改成這樣:
json.extract! user, :name, :email
輸出結果就會變成(經過排版結果):
[
{
"name": "孫悟空",
"email": "[email protected]"
},
{
"name": "貝吉達",
"email": "[email protected]"
},
{
"name": "丁小雨",
"email": "[email protected]"
}
]
使用 render json: @users
的寫法只能一口氣把 @users
的內容全部印出來,而使用 Jbuilder 則是可以微調要輸出的欄位。另一個好處就是原本 /users
的頁面還是可保持 HTML 的頁面呈現,只有 /users.json
的時候才會以 JSON 格式輸出。
為什麼加 .json
就可以了?
其實這算是 Route 做的好事,先看一下 rails routes
的結果:
$ bin/rails routes
Prefix Verb URI Pattern Controller#Action
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
有注意到後面那個 (.:format)
嗎?就是這個東西。假設你輸入網址 /users.html
,後面的附檔名就會被捕捉成 format
,如果在 Controller 的 Action 沒有特別聲明要以什麼方式 render,就會依據這個 format
去找對應的檔案,也就是說會找到 app/views/index.html
.erb。(還記得 .html.erb
的意思嗎?)
同理可證,當網址是輸入 /users.json
,它會去找 app/views/index.json
.jbuilder 來輸出結果。 而 format
的預設值是 html
,所以如果後面沒有附檔名,像是 /users
,則會去找 html
的樣版。
API-Only 模式
Rails 方便歸方便,它本身是個有點肥大的框架,這是一直以來 Rails 被詬病的地方。在 Rails 5 之後,Rails 加入了 API only 的模式,讓你在產生專案的時候減少一些不必要的套件及 middleware。讓我們使用 API Only 模式產生一個全新的專案:
$ rails new my_blog --api
後面加上了 --api
參數產生出來的專案,因為僅需要做 API 的輸出,所以不僅用的 Gem 數量變少了,連用到的 middleware 也比較少一點,在效能的提昇上是有一些幫助的。
更多詳細資料請參閱 http://guides.rubyonrails.org/api_app.html
但即使如此,Rails 畢竟是一個功能完整的網站開發框架,改成 API only 也只是從很胖的胖子變成普通胖的胖子,如果真的有效能考量,而且沒有要用到那麼完整的功能,也許可直接考慮使用更輕量化的工具,例如 Sinatra (http://www.sinatrarb.com/) 或 Hanami (http://hanamirb.org/)。
Comments