+3

Giới thiệu về Active Resource trong Rails

consuming-rest-services-with-activeresource-3-728.jpg

Active Resource

Active Resource giúp quản lý các kết nối giữa RESTful(Representational State Transfer) web services và các đối tượng nghiệp vụ, làm giảm số lượng code cần viết để ánh xạ đến các tài nguyên. Active Resource ánh xạ model class đến các tài nguyên REST ở xa cũng giống như cách mà Active Record ánh xạ từ model class đến các bảng cơ sở dữ liệu. Nó cũng cung cấp các cơ chế proxy giữa Active Resource (client) và một RESTful service. Khi có một request cần truy cập đến các tài nguyên ở xa, một REST JSON được sinh ra và được truyền đi, sau đó kết quả sẽ được parse sang các đối tượng Ruby.

Cách cài đặt

Bản mới nhất của Active Resource có thể được cài đặt với RubyGems:

gem install activeresource

hoặc thêm vào Gemfile như sau:

gem 'activeresource'

Cấu hình và cách sử dụng

Các Active Resource objects đại diện cho các RESTful resources của bạn tương tự như các Ruby objects. Để ánh xạ các resources đến các Ruby objects, Active Resource chỉ cần tên của Ruby object tương ứng với tên của resouce (ví dụ như lớp Person ánh xạ với resource people, rất giống với Active Record) và giá trị site - chứa URI của resources. ActiveResource::Base được các model class kế thừa, để có thể ánh xạ được đến với các RESTful resources:

class Person < ActiveResource::Base
  self.site = "http://api.people.com"
end

Bây giờ, lớp Person được ánh xạ tới RESTful resources nằm ở https://api.people.com/people/, và bạn bây giờ có thể sử dụng các methods của Active Resource để khai thác các resources. Trong trường hợp bạn đã có một model với tên giống với RESTful resource thích hợp rồi, bạn có thể thiết lập giá trị element_name:

class PersonResource < ActiveResource::Base
  self.site = "https://api.people.com"
  self.element_name = "person"
end

Nếu Active Resource objects của bạn yêu cầu sử dụng một HTTP proxy, bạn có thể thiết lập giá trị proxy chứa một URI:

class PersonResource < ActiveResource::Base
  self.site = "https://api.people.com"
  self.proxy = "https://user:password@proxy.people.com:8080"
end

Các giao thức của Active Resource

Active Resource được xây dựng trên một định dạng chuẩn JSON hoặc XML cho việc yêu cầu và gửi đi các resources thông qua HTTP. Nó sử dụng các chuẩn RESTful request như sau:

  • GET request được sử dụng cho việc tìm kiếm và truy xuất các resources.
  • POST request được sử dụng cho việc tạo mới các resources.
  • PUT request được sử dụng cho việc cập nhật các resources đang tồn tại.
  • DELETE request được sử dụng để xóa các resources.

Các phương thức truy cập đến resources từ model class

Find

Find request sử dụng phương thức GET và mong đợi trả về một JSON của resources mà nó yêu cầu. Với mỗi một request, JSON của của item đó được trả về trong response như sau:

# Expects a response of
#
# {"id":1,"first":"Vuong","last":"Hung"}
#
# for GET http://api.people.com:3000/people/1.json
#
hung = Person.find(1)

JSON nhận được sẽ sử dụng để xây dựng một đối tượng kiểu Person, với mỗi thành phần của JSON là một thuộc tính của đối tượng.

hung.is_a? Person  # => true
hung.last  # => 'Hung'

Bất kì thành phần phức tạp nào ( một thành phần chứa các thành phần khác) đều trở thành thuộc tính của đối tượng đó

# With this response:
# {"id":1,"first":"Hung","address":{"township":"Dong Anh","city":"Ha Noi"}}
#
# for GET http://api.people.com:3000/people/1.json
#
hung = Person.find(1)
hung.address  # => <Person::Address::xxxxx>
hung.address.city  # => 'Ha Noi'

Một tập hợp có thể được request tương tự như trên:

# Expects a response of
#
# [
#   {"id":1,"first":"Vuong","last":"Vuong"},
#   {"id":2,"first":"Hung","last":"Hung",}
# ]
#
# for GET http://api.people.com:3000/people.json
#
people = Person.all
people.first  # => <Person::xxx 'first' => 'Vuong' ...>
people.last  # => <Person::xxx 'first' => 'Hung' ...>

Create

Tạo mới một resource gửi đi một JSON của resource như là body của request và kì vọng một Location header trong response trả về với RESTful URL location của resource đã được tạo mới. id của resource đã tạo mới được parse sang Location response header và tự động được set vào id của đối tượng.

# {"first":"Vuong","last":"Hung"}
#
# is submitted as the body on
#
# Nếu include_root_in_json không được set hoặc được set là false => {"first":"Vuong"}
# Nếu include_root_in_json được set là true => {"person":{"first":"Vuong"}}
#
# POST http://api.people.com:3000/people.json
#
# Khi save được gọi trên một đối tượng Person mới.  Một empty response được mong chờ với một giá # trị header 'Location':
#
# Response (201): Location: http://api.people.com:3000/people/2
#
hung = Person.new(first: 'Vuong')
hung.new?  # => true
hung.save  # => true
hung.new?  # => false
hung.id    # => 2

Update

save cũng được sử dụng để cập nhật một resource đang tồn tại và làm theo cùng giao thức như tạo mới một resource với ngoại lệ là không có response headers nào cần thiết - chỉ một empty response khi cập nhật trên server side là thành công.

# {"first":"Hung"}
#
# is submitted as the body on
#
# Nếu include_root_in_json không được set hoặc được set là false => {"first":"Hung"}
# Nếu include_root_in_json được set là true => {"person":{"first":"Hung"}}
#
# PUT http://api.people.com:3000/people/1.json
#
# Khi save được gọi trên một đối tượng Person đang tồn tại. Một empty response được mong chờ với # code (204)
#
hung = Person.find(1)
hung.first # => 'Hung'
hung.first = 'Vuong'
hung.save  # => true

Delete

Destruction of a resource can be invoked as a class and instance method of the resource.

Xóa một resource có thể được gọi như một class và một instace method của resource.

# A request is made to
#
# DELETE http://api.people.com:3000/people/1.json
#
# for both of these forms.  An empty response with
# is expected with response code (200)
#
hung = Person.find(1)
hung.destroy  # => true
hung.exists?  # => false
Person.delete(2)  # => true
Person.exists?(2) # => false

Associations

Mối quan hệ giữa các resources được khai báo bằng cách sử dụng cú pháp chuẩn quen thuộc như những ai đã sử dụng Active Record. Ví dụ, sử dụng định nghĩa lớp như dưới đây:

class Post < ActiveResource::Base
  self.site = "http://blog.io"
  has_many :comments
end

post = Post.find(1)      # issues GET http://blog.io/posts/1.json
comments = post.comments # issues GET http://blog.io/posts/1/comments.json

Nếu như bạn kiểm soát server, bạn có thể sẽ muốn include các nested resources để tránh một yêu cầu mạng thứ hai. Với resource ở trên, nếu response bao gồm các comments, chúng sẽ tự động được load vào Active Resource object. Và server-side model có thể được điều chỉnh như sau để có được các comments trong response:

class Post < ActiveRecord::Base
  has_many :comments

  def as_json(options)
    super.merge(:include=>[:comments])
  end
end

Trên đây, tôi đã giới thiệu qua cho bạn đọc biết về thư viện Active Resource. Trong những bài viết sau, tôi sẽ trình bày cụ thể hơn về nó, hi vọng sẽ giúp ích được cho bạn đọc 😄

Nguồn tham khảo

  1. https://github.com/rails/activeresource
  2. http://api.rubyonrails.org/v3.2.6/classes/ActiveResource/Base.html

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí