restfolia 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/.travis.yml +3 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +11 -0
- data/Readme.md +101 -0
- data/ReadmeDeveloper.md +30 -0
- data/lib/restfolia/entry_point.rb +156 -0
- data/lib/restfolia/exceptions.rb +109 -0
- data/lib/restfolia/http/behaviour.rb +164 -0
- data/lib/restfolia/http/configuration.rb +74 -0
- data/lib/restfolia/http/request.rb +54 -0
- data/lib/restfolia/http.rb +135 -0
- data/lib/restfolia/resource.rb +109 -0
- data/lib/restfolia/resource_creator.rb +97 -0
- data/lib/restfolia/version.rb +3 -0
- data/lib/restfolia.rb +97 -0
- data/restfolia.gemspec +28 -0
- data/samples/changing_behaviour.rb +32 -0
- data/samples/changing_links_parse.rb +38 -0
- data/samples/cookies_options.rb +23 -0
- data/samples/headers_options.rb +27 -0
- data/samples/http_behaviour.rb +52 -0
- data/samples/using_custom_factory.rb +25 -0
- data/samples/using_custom_resource.rb +25 -0
- data/test/restfolia/entry_point_test.rb +123 -0
- data/test/restfolia/http_behaviour_test.rb +86 -0
- data/test/restfolia/http_configuration_test.rb +45 -0
- data/test/restfolia/resource_creator_test.rb +54 -0
- data/test/restfolia/resource_test.rb +89 -0
- data/test/restfolia_test.rb +10 -0
- data/test/support/json_samples.rb +41 -0
- data/test/support/stub_helpers.rb +36 -0
- data/test/test_helper.rb +13 -0
- metadata +182 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
module Restfolia::HTTP
|
2
|
+
|
3
|
+
# Public: Wraps Net::HTTP interface.
|
4
|
+
class Request
|
5
|
+
|
6
|
+
# Public: Do a HTTP Request.
|
7
|
+
#
|
8
|
+
# method - HTTP verb to be used. Options: :get, :post, :put, :delete
|
9
|
+
# url - a String to request. (ex: http://fake.com/service)
|
10
|
+
# args - Hash options to build request (default: {}):
|
11
|
+
# :query - String to be set with url (optional).
|
12
|
+
# :body - String to be set with request (optional).
|
13
|
+
# :headers - Hash with headers to be sent in request (optional).
|
14
|
+
#
|
15
|
+
# Returns an instance of Net::HTTPResponse.
|
16
|
+
#
|
17
|
+
# Raises URI::InvalidURIError if url attribute is invalid.
|
18
|
+
def self.do_request(method, url, args = {})
|
19
|
+
query = args[:query]
|
20
|
+
body = args[:body]
|
21
|
+
|
22
|
+
uri = URI.parse(url)
|
23
|
+
uri.query = query if query
|
24
|
+
|
25
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
26
|
+
verb = case method
|
27
|
+
when :get
|
28
|
+
Net::HTTP::Get.new(uri.request_uri)
|
29
|
+
when :post
|
30
|
+
Net::HTTP::Post.new(uri.request_uri)
|
31
|
+
when :put
|
32
|
+
Net::HTTP::Put.new(uri.request_uri)
|
33
|
+
when :delete
|
34
|
+
Net::HTTP::Delete.new(uri.request_uri)
|
35
|
+
else
|
36
|
+
msg = "Method have to be one of: :get, post, :put, :delete"
|
37
|
+
raise ArgumentError, msg
|
38
|
+
end
|
39
|
+
verb.body = body if body
|
40
|
+
if (headers = args[:headers])
|
41
|
+
headers.each do |header, value|
|
42
|
+
verb[header] = value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
if (cookies = args[:cookies])
|
46
|
+
verb["Cookie"] = cookies
|
47
|
+
end
|
48
|
+
|
49
|
+
http.request(verb)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module Restfolia
|
2
|
+
|
3
|
+
# Public: Store and execute behaviours defined by user. Behaviour is action
|
4
|
+
# for one or more HTTP code. See "default behaviours" below.
|
5
|
+
#
|
6
|
+
# Examples
|
7
|
+
#
|
8
|
+
# default behaviours
|
9
|
+
# behaviours do
|
10
|
+
#
|
11
|
+
# # 2xx
|
12
|
+
# on(200...300) do |http_response|
|
13
|
+
# content_type = (http_response["content-type"] =~ /application\/json/)
|
14
|
+
# if !content_type
|
15
|
+
# msg_error = "Response \"content-type\" header should be \"application/json\""
|
16
|
+
# raise Restfolia::ResponseError.new(msg_error, caller, http_response)
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# http_body = http_response.body.to_s
|
20
|
+
# if !http_body.empty?
|
21
|
+
# json_parsed = helpers.parse_json(http_response)
|
22
|
+
# Restfolia.create_resource(json_parsed)
|
23
|
+
# elsif (location = http_response["location"])
|
24
|
+
# helpers.follow_url(location)
|
25
|
+
# else
|
26
|
+
# nil
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# # 3xx
|
31
|
+
# on(300...400) do |http_response|
|
32
|
+
# if (location = http_response["location"])
|
33
|
+
# helpers.follow_url(location)
|
34
|
+
# else
|
35
|
+
# msg_error = "HTTP status #{http_response.code} not supported"
|
36
|
+
# raise Restfolia::ResponseError.new(msg_error, caller, http_response)
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# # 4xx
|
41
|
+
# on(400...500) do |http_response|
|
42
|
+
# raise Restfolia::ResponseError.new("Resource not found.",
|
43
|
+
# caller, http_response)
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# # 5xx
|
47
|
+
# on(500...600) do |http_response|
|
48
|
+
# raise Restfolia::ResponseError.new("Internal Server Error",
|
49
|
+
# caller, http_response)
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
module HTTP
|
55
|
+
autoload :Behaviour, "restfolia/http/behaviour"
|
56
|
+
autoload :Configuration, "restfolia/http/configuration"
|
57
|
+
autoload :Request, "restfolia/http/request"
|
58
|
+
|
59
|
+
# Public: Execute behaviour from HTTP Response code.
|
60
|
+
#
|
61
|
+
# http_response - Net::HTTPResponse with code attribute.
|
62
|
+
#
|
63
|
+
# Returns value from "block behaviour".
|
64
|
+
def self.response_by_status_code(http_response)
|
65
|
+
Behaviour.store.execute(http_response)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Public: It's a nice way to define configurations for
|
69
|
+
# your behaves using a block.
|
70
|
+
#
|
71
|
+
# block - Required block to customize your behaves. Below are
|
72
|
+
# the methods available inside block:
|
73
|
+
# #on - See #on
|
74
|
+
#
|
75
|
+
# Examples
|
76
|
+
#
|
77
|
+
# Restfolia::HTTP.behaviours do
|
78
|
+
# on(200) { '200 behaviour' }
|
79
|
+
# on([201, 204]) { 'behaviour for 201 and 204 codes' }
|
80
|
+
# on(300...400) { '3xx range' }
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# Returns nothing.
|
84
|
+
def self.behaviours(&block)
|
85
|
+
Behaviour.store.behaviours(&block)
|
86
|
+
end
|
87
|
+
|
88
|
+
#default behaviours
|
89
|
+
behaviours do
|
90
|
+
|
91
|
+
# 2xx
|
92
|
+
on(200...300) do |http_response|
|
93
|
+
content_type = (http_response["content-type"] =~ /application\/json/)
|
94
|
+
if !content_type
|
95
|
+
msg_error = "Response \"content-type\" header should be \"application/json\""
|
96
|
+
raise Restfolia::ResponseError.new(msg_error, caller, http_response)
|
97
|
+
end
|
98
|
+
|
99
|
+
http_body = http_response.body.to_s
|
100
|
+
if !http_body.empty?
|
101
|
+
json_parsed = helpers.parse_json(http_response)
|
102
|
+
Restfolia.create_resource(json_parsed)
|
103
|
+
elsif (location = http_response["location"])
|
104
|
+
helpers.follow_url(location)
|
105
|
+
else
|
106
|
+
nil
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# 3xx
|
111
|
+
on(300...400) do |http_response|
|
112
|
+
if (location = http_response["location"])
|
113
|
+
helpers.follow_url(location)
|
114
|
+
else
|
115
|
+
msg_error = "HTTP status #{http_response.code} not supported"
|
116
|
+
raise Restfolia::ResponseError.new(msg_error, caller, http_response)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# 4xx
|
121
|
+
on(400...500) do |http_response|
|
122
|
+
raise Restfolia::ResponseError.new("Resource not found.",
|
123
|
+
caller, http_response)
|
124
|
+
end
|
125
|
+
|
126
|
+
# 5xx
|
127
|
+
on(500...600) do |http_response|
|
128
|
+
raise Restfolia::ResponseError.new("Internal Server Error",
|
129
|
+
caller, http_response)
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Restfolia
|
2
|
+
|
3
|
+
# Public: Resource is the representation of JSON response. It transforms
|
4
|
+
# all JSON attributes in attributes and provides a "links" method, to
|
5
|
+
# help with hypermedia navigation.
|
6
|
+
#
|
7
|
+
# Examples
|
8
|
+
#
|
9
|
+
# resource = Resource.new(:attr_test => "test")
|
10
|
+
# resource.attr_test # => "test"
|
11
|
+
# resource.links # => []
|
12
|
+
#
|
13
|
+
# resource = Resource.new(:attr_test => "test",
|
14
|
+
# :links => {:href => "http://service.com",
|
15
|
+
# :rel => "self",
|
16
|
+
# :type => "application/json"})
|
17
|
+
# resource.attr_test # => "test"
|
18
|
+
# resource.links # => [#<Restfolia::EntryPoint ...>]
|
19
|
+
#
|
20
|
+
# By default, "links" method, expects from JSON to be the following formats:
|
21
|
+
#
|
22
|
+
# # Array de Links
|
23
|
+
# "links" : [{ "href" : "http://fakeurl.com/some/service",
|
24
|
+
# "rel" : "self",
|
25
|
+
# "type" : "application/json"
|
26
|
+
# }]
|
27
|
+
#
|
28
|
+
# # OR 'single' Links
|
29
|
+
# "links" : { "href" : "http://fakeurl.com/some/service",
|
30
|
+
# "rel" : "self",
|
31
|
+
# "type" : "application/json"
|
32
|
+
# }
|
33
|
+
#
|
34
|
+
# # OR node 'Link', that can be Array or single too
|
35
|
+
# "link" : { "href" : "http://fakeurl.com/some/service",
|
36
|
+
# "rel" : "self",
|
37
|
+
# "type" : "application/json"
|
38
|
+
# }
|
39
|
+
#
|
40
|
+
class Resource
|
41
|
+
|
42
|
+
# Public: Returns the Hash that represents parsed JSON.
|
43
|
+
attr_reader :_json
|
44
|
+
|
45
|
+
# Public: Initialize a Resource.
|
46
|
+
#
|
47
|
+
# json - Hash that represents parsed JSON.
|
48
|
+
#
|
49
|
+
# Raises ArgumentError if json parameter is not a Hash object.
|
50
|
+
def initialize(json)
|
51
|
+
unless json.is_a?(Hash)
|
52
|
+
raise(ArgumentError, "json parameter have to be a Hash object", caller)
|
53
|
+
end
|
54
|
+
@_json = json
|
55
|
+
|
56
|
+
#Add json keys as methods of Resource
|
57
|
+
#http://blog.jayfields.com/2008/02/ruby-replace-methodmissing-with-dynamic.html
|
58
|
+
@_json.each do |method, value|
|
59
|
+
next if self.respond_to?(method) #avoid method already defined
|
60
|
+
|
61
|
+
(class << self; self; end).class_eval do
|
62
|
+
define_method(method) do |*args|
|
63
|
+
value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Public: Read links from Resource. Links are optional.
|
70
|
+
# See Resource root doc for details.
|
71
|
+
#
|
72
|
+
# rel - Optional String parameter. Filter links by rel attribute.
|
73
|
+
#
|
74
|
+
# Returns Empty Array or Array of EntryPoints, if "rel" is informed
|
75
|
+
# it returns nil or an instance of EntryPoint.
|
76
|
+
def links(rel = nil)
|
77
|
+
@links ||= parse_links(@_json)
|
78
|
+
|
79
|
+
return nil if @links.empty? && !rel.nil?
|
80
|
+
return @links if @links.empty? || rel.nil?
|
81
|
+
|
82
|
+
@links.detect { |ep| ep.rel == rel }
|
83
|
+
end
|
84
|
+
|
85
|
+
protected
|
86
|
+
|
87
|
+
# Internal: Parse links from hash. Always normalize to return
|
88
|
+
# an Array of EntryPoints. Check if link has :href and :rel
|
89
|
+
# keys.
|
90
|
+
#
|
91
|
+
# Returns Array of EntryPoints or Empty Array if :links not exist.
|
92
|
+
# Raises RuntimeError if link doesn't have :href and :rel keys.
|
93
|
+
def parse_links(json)
|
94
|
+
links = json[:links] || json[:link]
|
95
|
+
return [] if links.nil?
|
96
|
+
|
97
|
+
links = [links] unless links.is_a?(Array)
|
98
|
+
links.map do |link|
|
99
|
+
if link[:href].nil? || link[:rel].nil?
|
100
|
+
msg = "Invalid hash link: #{link.inspect}"
|
101
|
+
raise(RuntimeError, msg, caller)
|
102
|
+
end
|
103
|
+
EntryPoint.new(link[:href], link[:rel])
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Restfolia
|
2
|
+
|
3
|
+
# Public: Call a Factory of Resources. This is a good place to override and
|
4
|
+
# returns a custom Resource Factory. By default, Restfolia uses
|
5
|
+
# Restfolia::ResourceCreator.
|
6
|
+
#
|
7
|
+
# json - Hash parsed from Response body.
|
8
|
+
#
|
9
|
+
# Returns Resource instance, configured at ResourceCreator.
|
10
|
+
# Raises ArgumentError if json is not a Hash.
|
11
|
+
def self.create_resource(json)
|
12
|
+
@creator ||= Restfolia::ResourceCreator.new
|
13
|
+
@creator.create(json)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Public: Factory of Resources. It transforms all JSON objects in Resources.
|
17
|
+
#
|
18
|
+
# Examples
|
19
|
+
#
|
20
|
+
# factory = Restfolia::ResourceCreator.new
|
21
|
+
# resource = factory.create(:attr_test => "test",
|
22
|
+
# :attr_tags => ["tag1", "tag2"],
|
23
|
+
# :attr_array_obj => [{:nested => "nested"}],
|
24
|
+
# :links => [{:href => "http://service.com",
|
25
|
+
# :rel => "contacts",
|
26
|
+
# :type => "application/json"},
|
27
|
+
# {:href => "http://another.com",
|
28
|
+
# :rel => "relations",
|
29
|
+
# :type => "application/json"}
|
30
|
+
# ])
|
31
|
+
# resource.attr_test # => "test"
|
32
|
+
# resource.attr_tags # => ["tag1", "tag2"]
|
33
|
+
# resource.attr_array_obj # => [#<Restfolia::Resource ...>]
|
34
|
+
#
|
35
|
+
class ResourceCreator
|
36
|
+
|
37
|
+
# Public: By default, returns Restfolia::Resource. You can use
|
38
|
+
# this method to override and returns a custom Resource. See examples.
|
39
|
+
#
|
40
|
+
# Examples
|
41
|
+
#
|
42
|
+
# # using a custom Resource
|
43
|
+
# class Restfolia::ResourceCreator
|
44
|
+
# def resource_class
|
45
|
+
# OpenStruct #dont forget to require 'ostruct'
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# Returns class of Resource to be constructed.
|
50
|
+
def resource_class
|
51
|
+
Restfolia::Resource
|
52
|
+
end
|
53
|
+
|
54
|
+
# Public: creates Resource looking recursively for JSON
|
55
|
+
# objects and transforming in Resources. To create Resource,
|
56
|
+
# this method use #resource_class.new(json).
|
57
|
+
#
|
58
|
+
# json - Hash parsed from Response body.
|
59
|
+
#
|
60
|
+
# Returns Resource from #resource_class.
|
61
|
+
# Raises ArgumentError if json is not a Hash.
|
62
|
+
def create(json)
|
63
|
+
unless json.is_a?(Hash)
|
64
|
+
raise(ArgumentError, "JSON parameter have to be a Hash object", caller)
|
65
|
+
end
|
66
|
+
|
67
|
+
json_parsed = {}
|
68
|
+
json.each do |attr, value|
|
69
|
+
json_parsed[attr] = look_for_resource(value)
|
70
|
+
end
|
71
|
+
resource_class.new(json_parsed)
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
# Internal: Check if value is eligible to become a Restfolia::Resource.
|
77
|
+
# If value is Array object, looks inner contents, using rules below.
|
78
|
+
# If value is Hash object, it becomes a Restfolia::Resource.
|
79
|
+
# Else return itself.
|
80
|
+
#
|
81
|
+
# value - object to be checked.
|
82
|
+
#
|
83
|
+
# Returns value itself or Resource.
|
84
|
+
def look_for_resource(value)
|
85
|
+
if value.is_a?(Array)
|
86
|
+
value = value.inject([]) do |resources, array_obj|
|
87
|
+
resources << look_for_resource(array_obj)
|
88
|
+
end
|
89
|
+
elsif value.is_a?(Hash)
|
90
|
+
value = resource_class.new(value)
|
91
|
+
end
|
92
|
+
value
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
data/lib/restfolia.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "uri"
|
3
|
+
|
4
|
+
require "rubygems"
|
5
|
+
require "multi_json"
|
6
|
+
|
7
|
+
require "restfolia/version"
|
8
|
+
require "restfolia/exceptions"
|
9
|
+
require "restfolia/http"
|
10
|
+
require "restfolia/entry_point"
|
11
|
+
require "restfolia/resource_creator"
|
12
|
+
require "restfolia/resource"
|
13
|
+
|
14
|
+
# Public: Restfolia: a REST client to consume and interact with Hypermedia API.
|
15
|
+
#
|
16
|
+
# Against the grain, Restfolia is very opinionated about some REST's concepts:
|
17
|
+
# * Aims only *JSON Media Type*.
|
18
|
+
# * All responses are parsed and returned as Restfolia::Resource.
|
19
|
+
# * Less is more. Restfolia is very proud to be small, easy to maintain and evolve.
|
20
|
+
# * Restfolia::Resource is Ruby object with attributes from JSON and can optionally contains *hypermedia links* which have to be a specific format. See the examples below.
|
21
|
+
# * All code is very well documented, using "TomDoc":http://tomdoc.org style.
|
22
|
+
#
|
23
|
+
# Obs: This is a draft version. Not ready for production (yet!).
|
24
|
+
#
|
25
|
+
# References
|
26
|
+
#
|
27
|
+
# You can find more information about arquitecture REST below:
|
28
|
+
# * "Roy Fielding's":http://roy.gbiv.com/untangled see this post for example: "REST APIs must be hypertext-driven":http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
|
29
|
+
# * "Rest in Practice":http://restinpractice.com, especially the chapter titled "Hypermedia Formats".
|
30
|
+
# * "Mike Amundsen's Blog":http://amundsen.com/blog/
|
31
|
+
# * ROAR - "Resource Oriented Arquitectures in Ruby":https://github.com/apotonick/roar it seems really good to build a hypermedia API, of course you can go with Sinatra+rabl solutions too.
|
32
|
+
#
|
33
|
+
# Examples
|
34
|
+
#
|
35
|
+
# # GET http://localhost:9292/recursos/busca
|
36
|
+
# { "itens_por_pagina" : 10,
|
37
|
+
# "paginal_atual" : 1,
|
38
|
+
# "paginas_totais" : 1,
|
39
|
+
# "query" : "",
|
40
|
+
# "total_resultado" : 100,
|
41
|
+
# "resultado" : [ { "id" : 1,
|
42
|
+
# "name" : "Test1",
|
43
|
+
# "links" : [ { "href" : "http://localhost:9292/recursos/id/1",
|
44
|
+
# "rel" : "recurso",
|
45
|
+
# "type" : "application/json"
|
46
|
+
# } ]
|
47
|
+
# },
|
48
|
+
# { "id" : 2,
|
49
|
+
# "name" : "Test2",
|
50
|
+
# "links" : [ { "href" : "http://localhost:9292/recursos/id/2",
|
51
|
+
# "rel" : "recurso",
|
52
|
+
# "type" : "application/json"
|
53
|
+
# } ]
|
54
|
+
# }
|
55
|
+
# ],
|
56
|
+
# "links" : { "href" : "http://localhost:9292/recursos/busca",
|
57
|
+
# "rel" : "self",
|
58
|
+
# "type" : "application/json"
|
59
|
+
# },
|
60
|
+
# }
|
61
|
+
#
|
62
|
+
# # GET http://localhost:9292/recursos/id/1
|
63
|
+
# { "id" : 1,
|
64
|
+
# "name" : "Test1",
|
65
|
+
# "links" : { "href" : "http://localhost:9292/recursos/id/1",
|
66
|
+
# "rel" : "self",
|
67
|
+
# "type" : "application/json"
|
68
|
+
# }
|
69
|
+
# }
|
70
|
+
#
|
71
|
+
# # getting a resource
|
72
|
+
# resource = Restfolia.at('http://localhost:9292/recursos/busca').get
|
73
|
+
# resource.pagina_atual # => 1
|
74
|
+
# resource.resultado # => [#<Resource ...>, #<Resource ...>]
|
75
|
+
#
|
76
|
+
# # example of hypermedia navigation
|
77
|
+
# r1 = resource.resultado.first
|
78
|
+
# r1 = r1.links("recurso").get # => #<Resource ...>
|
79
|
+
# r1.name # => "Test1"
|
80
|
+
#
|
81
|
+
module Restfolia
|
82
|
+
|
83
|
+
# Public: Start point for getting the first Resource.
|
84
|
+
#
|
85
|
+
# url - String with the address of service to be accessed.
|
86
|
+
#
|
87
|
+
# Examples
|
88
|
+
#
|
89
|
+
# entry_point = Restfolia.at("http://localhost:9292/recursos/busca")
|
90
|
+
# entry_point.get # => #<Resource ...>
|
91
|
+
#
|
92
|
+
# Returns Restfolia::EntryPoint object.
|
93
|
+
def self.at(url)
|
94
|
+
EntryPoint.new(url)
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
data/restfolia.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "restfolia/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "restfolia"
|
7
|
+
s.version = Restfolia::VERSION
|
8
|
+
s.authors = `git log --raw | grep Author: | awk -F ': | <|>' '{ print $2 }' | sort | uniq`.split("\n")
|
9
|
+
s.email = ["roger.barreto@gmail.com"]
|
10
|
+
s.homepage = "http://rogerleite.github.com/restfolia"
|
11
|
+
s.summary = %q{REST client to consume and interact with Hypermedia API}
|
12
|
+
s.description = %q{REST client to consume and interact with Hypermedia API}
|
13
|
+
s.license = 'MIT'
|
14
|
+
|
15
|
+
s.rubyforge_project = "restfolia"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_runtime_dependency "multi_json", "~> 1.3.0"
|
23
|
+
|
24
|
+
s.add_development_dependency "rake"
|
25
|
+
s.add_development_dependency "minitest"
|
26
|
+
s.add_development_dependency "minitest-reporters"
|
27
|
+
s.add_development_dependency "webmock"
|
28
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
# Run this sample from root project:
|
3
|
+
# $ ruby samples/changing_behaviour.rb
|
4
|
+
|
5
|
+
require "rubygems"
|
6
|
+
$LOAD_PATH << "lib"
|
7
|
+
require "restfolia"
|
8
|
+
|
9
|
+
begin
|
10
|
+
# Default behaviour to redirect 3xx is raise Error
|
11
|
+
Restfolia.at("http://google.com.br").get
|
12
|
+
rescue Restfolia::ResponseError => ex
|
13
|
+
puts ex.message
|
14
|
+
end
|
15
|
+
|
16
|
+
module Restfolia::HTTP::Behaviour
|
17
|
+
|
18
|
+
# We can change behaviour of many HTTP status
|
19
|
+
# on_2xx(http_response)
|
20
|
+
# on_3xx(http_response)
|
21
|
+
# on_4xx(http_response)
|
22
|
+
# on_5xx(http_response)
|
23
|
+
|
24
|
+
# Here we change 3xx behaviour to return a Resource
|
25
|
+
def on_3xx(http_response)
|
26
|
+
Restfolia.create_resource(:redirected => "I'm free! :D")
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
resource = Restfolia.at("http://google.com.br").get
|
32
|
+
puts resource.redirected
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
# Run this sample from root project:
|
3
|
+
# $ ruby samples/changing_links_parse.rb
|
4
|
+
|
5
|
+
require "rubygems"
|
6
|
+
$LOAD_PATH << "lib"
|
7
|
+
require "restfolia"
|
8
|
+
|
9
|
+
resource = Restfolia::Resource.new(:attr_test => "test",
|
10
|
+
:custom_links => [
|
11
|
+
{:url => "http://test.com", :rel => "rel"}
|
12
|
+
])
|
13
|
+
puts resource.links.inspect # => []
|
14
|
+
|
15
|
+
# Now let's change the way Resource parses links
|
16
|
+
class Restfolia::Resource
|
17
|
+
|
18
|
+
def parse_links(json)
|
19
|
+
links = json[:custom_links]
|
20
|
+
return [] if links.nil?
|
21
|
+
|
22
|
+
links = [links] unless links.is_a?(Array)
|
23
|
+
links.map do |link|
|
24
|
+
if link[:url].nil? || link[:rel].nil?
|
25
|
+
msg = "Invalid hash link: #{link.inspect}"
|
26
|
+
raise(RuntimeError, msg, caller)
|
27
|
+
end
|
28
|
+
Restfolia::EntryPoint.new(link[:url], link[:rel])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
resource = Restfolia::Resource.new(:attr_test => "test",
|
35
|
+
:custom_links => [
|
36
|
+
{:url => "http://test.com", :rel => "rel"}
|
37
|
+
])
|
38
|
+
puts resource.links.inspect # => [#<Restfolia::EntryPoint ...>]
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
# Run this sample from root project:
|
3
|
+
# $ ruby samples/cookies_options.rb
|
4
|
+
|
5
|
+
require "rubygems"
|
6
|
+
$LOAD_PATH << "lib"
|
7
|
+
require "restfolia"
|
8
|
+
|
9
|
+
SERVICE_URL = "http://localhost:9292/recursos/busca"
|
10
|
+
|
11
|
+
sample_cookie = "PREF=ID=988f14fa5edd3243:TM=1335470032:LM=1335470032:S=KVBslNbyz6bG0DqU; expires=Sat, 26-Apr-2014 19:53:52 GMT; path=/; domain=.google.com, NID=59=peUyZQuLWQ_0gELr1yDf0FT4ZlT7ZdITNrO5OhkEnAvp_8MZ4TT6pHq7_q_Su-puTw7vGml_Ok6du8fLreGHzfpMs4Qh1v-qBCFYGuCNbzpwN670x5MFbGKy0KUXA3WP; expires=Fri, 26-Oct-2012 19:53:52 GMT; path=/; domain=.google.com; HttpOnly"
|
12
|
+
|
13
|
+
# accessing cookies attribute
|
14
|
+
entry_point = Restfolia.at(SERVICE_URL)
|
15
|
+
entry_point.cookies = sample_cookie
|
16
|
+
resource = entry_point.get
|
17
|
+
|
18
|
+
# adding in a fancy way
|
19
|
+
resource = Restfolia.at(SERVICE_URL).
|
20
|
+
set_cookies(sample_cookie).get
|
21
|
+
|
22
|
+
puts "Done!"
|
23
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
# Run this sample from root project:
|
3
|
+
# $ ruby samples/headers_options.rb
|
4
|
+
|
5
|
+
require "rubygems"
|
6
|
+
$LOAD_PATH << "lib"
|
7
|
+
require "restfolia"
|
8
|
+
|
9
|
+
SERVICE_URL = "http://localhost:9292/recursos/busca"
|
10
|
+
|
11
|
+
# accessing headers attribute
|
12
|
+
entry_point = Restfolia.at(SERVICE_URL)
|
13
|
+
entry_point.headers["ContentyType"] = "application/json"
|
14
|
+
resource = entry_point.get
|
15
|
+
|
16
|
+
# adding in a fancy way
|
17
|
+
resource = Restfolia.at(SERVICE_URL).
|
18
|
+
with_headers("Content-Type" => "application/json",
|
19
|
+
"Accept" => "application/json").
|
20
|
+
get
|
21
|
+
|
22
|
+
# helper that sets Content-Type and Accept headers
|
23
|
+
resource = Restfolia.at(SERVICE_URL).
|
24
|
+
as("application/json").
|
25
|
+
get
|
26
|
+
|
27
|
+
puts "Done!"
|