xây dựng API với Napa
Bài đăng này đã không được cập nhật trong 8 năm
Hiện nay Việc xây dựng API dường như đã quá quen thuộc với mỗi lập trình viên. Bằng ngôn ngữ Ruby chúng ta có rất nhiều cách để viết API. Và để hỗ trợ viết API nhanh và tiện nhất thì hiện nay có một framework giúp ta thực hiện điều đó. Đó là Napa
.
Cài đặt
gem install napa
chú ý là napa
chỉ hỗ trợ cho Ruby từ 2.0 trở lên.
Khởi tạo project
napa new demo-napa
CSDL mặc định của napa là mysql. Cấu trúc thư mục của project như sau
demo-napa
- app
- apis
- models
- representers
- config
- db
- lib
- log
- spec
- Gemfile
- Rakefile
Khá giống với rails
nhưng được giản lược hơn. Hầu hết code của chúng ta sẽ viết trong thư mục app
. Ta thấy có 1 thư mục khá mới là representers
sẽ chưá các file làm nhiệm vụ convert model thành cấu trúc JSON.
Ta tiến hành bundle install như với rails
cd demo-napa
bundle install
Tiếp đó ta config database trong file .env
và
rake db:create
Nếu có lỗi không tạo đượ database do sai password thì do phiên bản napa không tương thích với mysql. Để khắc phục ta vào Gemfile
và sửa
gem 'napa'
thành
gem 'napa', github: "bellycard/napa"
rồi tiến hành
bundle update
Viết API
trước tiên ta cũng tạo model như với rails. Ở đây ta tạo model Contact với các thuộc tính cơ bản
napa generate model Contact name:string email:string phone:string
sau đó chạy migrate
rake db:migrate
Tạo API end point
napa generate api contact
napa
sẽ generate API class app/apis/contacts_api.rb
và representer class app/representers/contact_representer.rb
.
contacts_api.rb
sẽ có cú pháp và cấu trúc giống với Grape API
. Ta sẽ viết các hàm restful cho API contact
class ContactsApi < Grape::API
desc 'Get a list of contacts'
params do
optional :ids, type: Array, desc: 'Array of contact ids'
end
get do
contacts = params[:ids] ? Contact.where(id: params[:ids]) : Contact.all
represent contacts, with: ContactRepresenter
end
desc 'Create a contact'
params do
end
post do
contact = Contact.create!(permitted_params)
represent contact, with: ContactRepresenter
end
params do
requires :id, desc: 'ID of the contact'
end
route_param :id do
desc 'Get an contact'
get do
contact = Contact.find(params[:id])
represent contact, with: ContactRepresenter
end
desc 'Update a contact'
params do
end
put do
# fetch contact record and update attributes. exceptions caught in app.rb
contact = Contact.find(params[:id])
contact.update_attributes!(permitted_params)
represent contact, with: ContactRepresenter
end
end
end
Mặc định napa sẽ để trống phần khai báo các params. Tuỳ vào login của chúng ta mà sẽ khai báo thêm. Ví dụ các params bắt buộc thì ta dùng require
, hay nếu ko bắt buộc thì ta dùng optional
...
desc 'Create an contact'
params do
optional :name, type: String, desc: 'The Name of the contact'
optional :phone, type: String, desc: 'The Phone of the contact'
optional :email, type: String, desc: 'The Email Address of the contact'
end
...
...
desc 'Update a contact'
params do
optional :name, type: String, desc: 'The Name of the contact'
optional :phone, type: String, desc: 'The Phone of the contact'
optional :email, type: String, desc: 'The Email Address of the contact'
end
...
Tiếp theo ta sẽ update file presenter. Ta sẽ khai báo các trường của model contact
mà muốn thêm vào trong JSON response.
class ContactRepresenter < Napa::Representer
property :id, type: String
property :name
property :phone
property :email
end
Cuối cùng ta khai bào trong application_api.rb
để mount API contact.
class ApplicationApi < Grape::API
format :json
extend Napa::GrapeExtenders
mount ContactsApi => '/contacts'
add_swagger_documentation
end
Thực hiện request
Ta đã thực hiện xong việc viết API. Bây giờ ta bật server để thực hiện request
shotgun
Để test việc thực hiện request có rất nhiều cách như dùng postman, rest client hay thực hiện curl
trên terminal.
Đầu tiên ta thực hiện tạo contact
curl -X POST -d name="Devdatta Kane" -d email="kane.devdatta@gmail.com" -d phone="25451512544" http://localhost:9393/contacts
Ta sẽ nhận đuuwocj response
{
"data": {
"object_type": "contact",
"id": "1",
"name": "Devdatta Kane",
"email": "kane.devdatta@gmail.com",
"phone": "25451512544"
}
}
Bây giờ ta sẽ thực hiện request để get contact vừa tạo được
curl -X GET http://localhost:9393/contacts
Response trả về
{
"data": [
{
"object_type": "contact",
"id": "1",
"name": "Devdatta Kane",
"email": "kane.devdatta@gmail.com",
"phone": "25451512544"
}
]
}
Tương tự ta có thể update contact bằng việc thực hiện request đến API.
Bảo mật
Bên trên ta đã thực hiên viết API và đã request thành công tuy nhiên ta cần thiết lâoj chế độ bảo mật cho API nếu ko muốn bất cứ ai cũng có thể request đến API và xem, sửa, xoá dữ liệu. Để làm việc này thì ta sẽ yêu cầ mỗi request đến API đều phải có access_token
hợp lệ, nếu không sẽ báo lỗi.
Token này có thể lấy từ user. mỗi user sẽ dược sinh ra 1 token và ta cần truyền đúng token mói request đc API.
Ta viết thêm hàm check trong
before do
error!("401 Unauthorized", 401) unless authenticated?
end
helpers do
def authenticated?
# return true if valid token
end
end
Bây giờ thử request mà không truyền access_ken:
curl -X GET http://localhost:9393/contacts
thì ta sẽ nhận được response
{"error":{"code":"api_error","message":"401 Unauthorized"}}
Kết luận
Có thể nói napa
là phương tiện viết API bằng ngôn ngữ Ruby khá mạnh. Chúng ta có thể nhanh chóng triển khai API bằng napa nếu project của ta không quan tâm đến view. Trên đây chỉ mang tính giới thiệu cơ bản về napa. Khi triển khai trong dự án thật ta cần đầu tư thêm về cấu trúc API và quản lý version ...
Tham khảo
All rights reserved