xây dựng API với Napa
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ỉ ...
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
https://github.com/bellycard/napa