使用 Grape 构建 RESTful API

grape

Rails中构建API的方式有很多种,Grape因性能而被推荐,其可构建于任何Rack上,仍建议使用Rails作为载体,来构建Grape,会非常省心。

安装配置

首先确保安装:

1
2
3
4
5
6
## Platform
gem 'rails', '4.2.0'
## RESTful API Engine
gem 'grape'
gem 'grape-entity'

组织架构

目录结构

1
2
3
4
5
6
7
8
9
10
11
12
api
├── api.rb
└── v1
├── base.rb
├── entities
│   ├── base.rb
│   └── user_basic.rb
├── helpers
│   ├── page_helper.rb
│   └── user_helper.rb
├── base_api.rb
└── users_api.rb
  • base.rb 中定义着API的版本、输出格式,及挂载更多API。
  • users_api.rb 就像controller,对每个resources都进行分开写,然后在base.rb中进行mount
  • entities 使用grape-entity,控制输出中的对象及格式。
  • helper 放置常用的helper,像分页,用户验证。
entities/user_basic.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module V1
module Entities
class UserBasic < Entities::Base
format_with(:iso8601) { |dt| dt.iso8601 }
expose :id
expose :name
# 如果需要输出层级对象,可以按这种方式
# expose :company, using: Entities::Company
# 日期、时间一律使用ISO 8601
expose :created_at, format_with: :iso8601
# with_options(format_with: :iso8601) do
# expose :created_at
# end
end
end
end
base.rb
1
2
3
4
5
6
7
8
9
module V1
class Base < Grape::API
version 'v1'
format :json
# Mount the APIs
mount UsersApi
end
end

挂载

routes.rb
1
mount V1::API => '/'

测试

http://localhost:3000/v1/users

Best Practices

非常推荐 Vinay Sahni的实践,说明的非常清晰,而 RESTful Tutorial 也是推荐,但Wrapper一节不作推荐。

- Doc with Swagger UI

1
gem 'grape-swagger'
1
add_swagger_documentation
./config/initializers/swagger.rb
1
2
GrapeSwaggerRails.options.url = '/swagger_doc.json'
GrapeSwaggerRails.options.app_url = 'http://swagger.wordnik.com'

http://localhost:3000/swagger_doc.json

1
gem 'grape-swagger-rails'
1
mount GrapeSwaggerRails::Engine +> '/docs'

- 分页

类库有will_paginate和 Kaminari,示例中选后者。

和Grape结合部分,使用 api-pagination

测试:
http://localhost:3000/v1/users?page=2&per_page=2

分页有很多种定义方式,建议采用RFC-5988 中所定义。(如上链接)

- JSend

RESTful Tutorial 中推荐过JSend,而之前项目中也使用了类似的格式,就是在数据源外包一层,并加上其它的一些信息,像code, status, message。

这些信息主要是应用于JSONP。建议用该方式:,或者是一些无法获取或处理HTTP Header的JS类库。

- Partial Response

Grape中实现参见该文:Crafting Ruby Grape APIs: Partial Response

- Error 处理

REF::