Having experiences of developing iCook API, I'd like to share some gems, skills and tips to build an efficient, consistent and well-documented API with Ruby on Rails which makes API users like you more.
9. RESTful and Reasonable routes
# app/models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
!
# routes.rb
resources :dishes do
resources :comments, to: "dishes/comments"
end
!
# GET /dishes/1/comments
# POST /dishes/1/comments
# DELETE /dishes/1/comments/1
- 一般的 dishes has_many comments 的 routes 的寫法沒問題
- 但考慮到 comments 是 polymorphic type,也就是說他可以是料理的留言,也可以是食譜的留言。在 DELETE 留言時其實就不需要特別強調他是料理的
或是食譜的留言,只要給 ID 就可以刪除了
10. RESTful and Reasonable routes
# routes.rb
resources :dishes do
resources :comments, to: “dishes/comments"
, except: [:destroy]
end
resources :comments, only: [:destroy]
!
# GET /dishes/1/comments
# POST /dishes/1/comments
# DELETE /comments/1
- 更換後的 routes,對 API Users 來說更簡單容易理解。
11. Implicit in routes
- RESTful 的一個重要關鍵就是他暗示了所有 route 都是一個 resource
- 這樣的暗示就是一種 API 開發者與 Users 之間的共識,需要更精確的暗示 API Users,來保持 API 的一致性
12. Implicit in routes
resources :users do
resources :settings, to: "users/settings"
end
!
# GET /users/username/settings
# PUT /users/username/settings
!
resources :settings
!
# GET /settings
# PUT /settings
- 上方的 routes 其實會有暗示可以帶入別人的 username 來查詢/修改設定的可能,應該要被修改成下方的形式
13. Debate on page vs. offset
- 曾經與 API Users 討論在翻頁的 API 應該要用哪一套
- 大部分情況下這只是習慣上的選擇,但以下有個 edge case
19. Documentation
# docs/fdoc/members/list-GET.fdoc
description: The list of members.
requestParameters:
properties:
limit:
type: integer
required: no
default: 50
description: Limits the number of results returned.
responseParameters:
properties:
members:
type: array
items:
title: member
description: Representation of a member
type: object
properties:
name:
description: Member's name
type: string
required: yes
example: Captain Smellypants
responseCodes:
- status: 200 OK
successful: yes
description: A list of current members
- status: 400 Bad Request
successful: no
description: Indicates malformed parameters
- 分成 request、response、responseCodes 等區塊
24. jbuilder & serializer
# app/models/recipe.rb
class Dish < ActiveRecord::Base
belongs_to :user
end
!
# app/models/user.rb
class User < ActiveRecord::Base
has_many :dishes
end
!
# app/controllers/dishes_controller.rb
class DishesController < ApplicationController
def index
@dishes = Dish.all
end
end
- 簡單的 model, controller
25. jbuilder & serializer
# app/views/dishes/index.json.jbuilder
json.dishes dishes do |json, dish|
json.id dish.id
json.description dish.description
json.url dish_url(dish)
json.partial! "api/v1/users/user", user: dish.user
end
!
# app/serializers/dish_serializer.rb
class DishSerializer < ActiveModel::Serializer
attributes :id, :description, :url
has_one :user
!
def url
dish_url
end
end
- jbuilder 可以自由組裝 key, value
- jbuilder 也有 partial
- jbuilder 每個 action 要有一個 *.json.jbuilder
- serializer 如同他的名字是 model 的 serializer,一個 model 定義一次
- serializer 比較物件導向(Object Oriented)
- serializer 一致性相當高,不需要重複定義,反之 jbuilder
37. Secure
- Use User-Agent header!
- Constrain your routes, use “only” and “except”!
- kickstarter/rack-attack!
- Rack middleware for blocking & throttling
- API 開發者可以透過 User-Agent 來限制使用者存取,避免 Server 太容易被莫名的 request 攻擊(DDos)
- 盡量限制開放有用到的 routes,不要冒險
- kickstarter/rack-attack 這個 gem 是 rack middleware,可以列黑白名單在 rails 之前就阻擋掉部分不需要的 request
38. – Neil Gaiman 2012
“People will tolerate how unpleasant you are if
your work is good and you deliver it on time. !
!
People will forgive the lateness of your work if it is
good and they like you. !
!
And you don’t have to be as good as everyone
else if you’re on time and it’s always a pleasure to
hear from you.”
- 最後引用一段我滿喜歡的演講,來自於 Neil Gaiman 2012 在 University of Art 的演講
39. “People will tolerate the incomplete document if
your API is efficient and consistent.
!
People will forgive the inconsistency of your API
if it is efficient and the document is fine.
!
And your API doesn’t have to be as efficient as
everyone else if it’s consistent and it’s always a
pleasure to read the documents.”
– David Yun 2014
- 改寫成 API 的三個原則也滿適用的。