restfulness 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +6 -0
- data/README.md +9 -2
- data/Rakefile +6 -0
- data/example/README.md +1 -1
- data/lib/restfulness.rb +2 -7
- data/lib/restfulness/application.rb +1 -4
- data/lib/restfulness/dispatchers/rack.rb +2 -0
- data/lib/restfulness/response.rb +52 -3
- data/lib/restfulness/version.rb +1 -1
- data/restfulness.gemspec +0 -1
- data/spec/unit/application_spec.rb +3 -2
- data/spec/unit/resource_spec.rb +4 -1
- data/spec/unit/response_spec.rb +22 -0
- metadata +3 -18
- data/lib/restfulness/log_formatters/quiet_formatter.rb +0 -7
- data/lib/restfulness/log_formatters/verbose_formatter.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c7504fc661a80914cd4f3e3ad81918799de7b0b
|
4
|
+
data.tar.gz: a6b3d22e6fc9c30ba6010043550d37e3c651be0a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d21da3dc7f1db2dd8b1259c36e710aa31698f31f5b39b37af0ecca2abc433fa15833941359efabcd9d74681b0570e63a1f4c651d0fb309b1b62c2fc656eb031f
|
7
|
+
data.tar.gz: e7fe0be99de3fcf1947e5fc75bfe2fce76bbd629e9b5cdf3b0370db2ae9e6a1f08a4353130392c3aa83770f37f0c00c0d67e67c4c024046eac142b6897b0ab68
|
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
Because REST APIs are all about resources, not routes.
|
4
4
|
|
5
|
+
[![Build Status](https://travis-ci.org/samlown/restfulness.png)](https://travis-ci.org/samlown/restfulness)
|
6
|
+
|
5
7
|
## Introduction
|
6
8
|
|
7
9
|
Restfulness is an attempt to create a Ruby library that helps create truly REST based APIs to your services. The focus is placed on performing HTTP actions on resources via specific routes, as opposed to the current convention of assigning routes and HTTP actions to methods or blocks of code. The difference is subtle, but makes for a much more natural approach to building APIs.
|
@@ -116,7 +118,6 @@ class MyAppAPI < Restfulness::Application
|
|
116
118
|
add 'projects', ProjectsResource
|
117
119
|
end
|
118
120
|
end
|
119
|
-
|
120
121
|
```
|
121
122
|
|
122
123
|
An application is designed to be included in your Rails, Sinatra, or other Rack project, simply include a new instance of your application in the `config.ru` file:
|
@@ -397,11 +398,12 @@ If you're adding Restfulness to a Rails project, you can take advantage of the `
|
|
397
398
|
```ruby
|
398
399
|
class MyAPI < Restfulness::Application
|
399
400
|
if Rails.env.development?
|
400
|
-
middlewares << ActionDispatch::
|
401
|
+
middlewares << ActionDispatch::Reloader
|
401
402
|
end
|
402
403
|
routes do
|
403
404
|
# etc. etc.
|
404
405
|
end
|
406
|
+
end
|
405
407
|
```
|
406
408
|
|
407
409
|
We're still working on ways to improve this. If you have any ideas, please send me a pull request!
|
@@ -422,6 +424,11 @@ Restfulness was created by Sam Lown <me@samlown.com> as a solution for building
|
|
422
424
|
|
423
425
|
## History
|
424
426
|
|
427
|
+
### 0.2.2 - October 31, 2013
|
428
|
+
|
429
|
+
* Refactoring logging support to not depend on Rack CommonLogger nor ShowExceptions.
|
430
|
+
* Using ActiveSupport::Logger instead of MonoLogger.
|
431
|
+
|
425
432
|
### 0.2.1 - October 22, 2013
|
426
433
|
|
427
434
|
* Removing some unnecessary logging and using Rack::CommonLogger.
|
data/Rakefile
CHANGED
data/example/README.md
CHANGED
data/lib/restfulness.rb
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
|
2
2
|
require 'uri'
|
3
3
|
require 'multi_json'
|
4
|
-
require 'mono_logger'
|
5
4
|
require 'active_support/core_ext'
|
6
5
|
require 'active_support/dependencies'
|
6
|
+
require 'active_support/logger'
|
7
7
|
require 'rack/utils'
|
8
8
|
require 'rack/commonlogger'
|
9
9
|
require 'rack/showexceptions'
|
10
10
|
require 'rack/builder'
|
11
11
|
|
12
|
-
|
13
12
|
require "restfulness/resources/events"
|
14
13
|
|
15
14
|
require "restfulness/application"
|
@@ -26,15 +25,11 @@ require "restfulness/version"
|
|
26
25
|
|
27
26
|
require "restfulness/dispatchers/rack"
|
28
27
|
|
29
|
-
require "restfulness/log_formatters/quiet_formatter"
|
30
|
-
require "restfulness/log_formatters/verbose_formatter"
|
31
|
-
|
32
28
|
module Restfulness
|
33
29
|
extend self
|
34
30
|
|
35
31
|
attr_accessor :logger
|
36
32
|
end
|
37
33
|
|
38
|
-
Restfulness.logger =
|
39
|
-
Restfulness.logger.formatter = Restfulness::VerboseFormatter.new
|
34
|
+
Restfulness.logger = ActiveSupport::Logger.new(STDOUT)
|
40
35
|
|
@@ -20,12 +20,14 @@ module Restfulness
|
|
20
20
|
def prepare_request(env)
|
21
21
|
rack_req = ::Rack::Request.new(env)
|
22
22
|
request = Request.new(app)
|
23
|
+
|
23
24
|
request.uri = rack_req.url
|
24
25
|
request.action = parse_action(rack_req.request_method)
|
25
26
|
request.query = rack_req.GET
|
26
27
|
request.body = rack_req.body
|
27
28
|
request.headers = prepare_headers(env)
|
28
29
|
|
30
|
+
# Useful info
|
29
31
|
request.remote_ip = rack_req.ip
|
30
32
|
request.user_agent = rack_req.user_agent
|
31
33
|
|
data/lib/restfulness/response.rb
CHANGED
@@ -6,18 +6,23 @@ module Restfulness
|
|
6
6
|
# Incoming data
|
7
7
|
attr_reader :request
|
8
8
|
|
9
|
+
# The generated resource object
|
10
|
+
attr_reader :resource
|
11
|
+
|
9
12
|
# Outgoing data
|
10
13
|
attr_reader :status, :headers, :payload
|
11
14
|
|
15
|
+
|
12
16
|
def initialize(request)
|
13
17
|
@request = request
|
14
18
|
@headers = {}
|
15
19
|
end
|
16
20
|
|
17
21
|
def run
|
22
|
+
@log_begin_at = Time.now
|
18
23
|
route = request.route
|
19
24
|
if route
|
20
|
-
resource = route.build_resource(request, self)
|
25
|
+
self.resource = route.build_resource(request, self)
|
21
26
|
|
22
27
|
# run callbacks, if any fail, they'll raise an error
|
23
28
|
resource.check_callbacks
|
@@ -33,10 +38,26 @@ module Restfulness
|
|
33
38
|
rescue HTTPException => e # Deal with HTTP exceptions
|
34
39
|
headers.update(e.headers)
|
35
40
|
update_status_and_payload(e.status, e.payload)
|
41
|
+
|
42
|
+
rescue StandardError, LoadError, SyntaxError => e
|
43
|
+
# Useful coding error handling, with backtrace
|
44
|
+
log_exception(e)
|
45
|
+
update_status_and_payload(500, e.message + "\n")
|
46
|
+
|
47
|
+
ensure
|
48
|
+
log! if status
|
49
|
+
end
|
50
|
+
|
51
|
+
def content_length
|
52
|
+
payload.to_s.bytesize.to_s
|
36
53
|
end
|
37
54
|
|
38
55
|
protected
|
39
56
|
|
57
|
+
def resource=(obj)
|
58
|
+
@resource = obj
|
59
|
+
end
|
60
|
+
|
40
61
|
def update_status_and_payload(status, payload = "")
|
41
62
|
self.status = status
|
42
63
|
self.payload = payload
|
@@ -63,9 +84,37 @@ module Restfulness
|
|
63
84
|
else # Assume text
|
64
85
|
headers['Content-Type'] = 'text/plain; charset=utf-8'
|
65
86
|
end
|
66
|
-
headers['Content-Length'] =
|
87
|
+
headers['Content-Length'] = content_length
|
67
88
|
end
|
68
89
|
|
69
|
-
|
90
|
+
def log!
|
91
|
+
dur = @log_begin_at ? Time.now - @log_begin_at : 0.0
|
92
|
+
uri = request.uri
|
93
|
+
|
94
|
+
resource_name = resource ? resource.class.to_s : 'Error'
|
95
|
+
# We're only interested in parsed parameters.
|
96
|
+
params = request.instance_variable_get(:@params)
|
97
|
+
|
98
|
+
msg = %{%s "%s %s%s" %s %d %s %s %0.4fs %s} % [
|
99
|
+
request.remote_ip,
|
100
|
+
request.action.to_s.upcase,
|
101
|
+
uri.path,
|
102
|
+
uri.query ? "?#{uri.query}" : '',
|
103
|
+
resource_name,
|
104
|
+
status.to_s[0..3],
|
105
|
+
STATUSES[status],
|
106
|
+
content_length,
|
107
|
+
dur,
|
108
|
+
params ? params.inspect : ''
|
109
|
+
]
|
110
|
+
Restfulness.logger.info(msg)
|
111
|
+
end
|
70
112
|
|
113
|
+
def log_exception(e)
|
114
|
+
string = "#{e.class}: #{e.message}\n"
|
115
|
+
string << e.backtrace.map { |l| "\t#{l}" }.join("\n")
|
116
|
+
Restfulness.logger.error(string)
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
71
120
|
end
|
data/lib/restfulness/version.rb
CHANGED
data/restfulness.gemspec
CHANGED
@@ -21,7 +21,6 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_dependency "rack", "~> 1.4"
|
22
22
|
spec.add_dependency "multi_json", "~> 1.8"
|
23
23
|
spec.add_dependency "activesupport", ">= 3.1"
|
24
|
-
spec.add_dependency "mono_logger", "~> 1.0"
|
25
24
|
|
26
25
|
spec.add_development_dependency "bundler", "~> 1.3"
|
27
26
|
spec.add_development_dependency "rake"
|
@@ -32,6 +32,7 @@ describe Restfulness::Application do
|
|
32
32
|
describe "#build_rack_app (protected)" do
|
33
33
|
it "should build a new rack app with middlewares" do
|
34
34
|
obj = klass.new
|
35
|
+
obj.class.middlewares << Rack::ShowExceptions
|
35
36
|
app = obj.send(:build_rack_app)
|
36
37
|
app.should be_a(Rack::Builder)
|
37
38
|
# Note, this might brake if Rack changes!
|
@@ -65,9 +66,9 @@ describe Restfulness::Application do
|
|
65
66
|
end
|
66
67
|
|
67
68
|
describe ".middlewares" do
|
68
|
-
it "should provide
|
69
|
+
it "should provide empty array of middlewares" do
|
69
70
|
klass.middlewares.should be_a(Array)
|
70
|
-
klass.middlewares.should
|
71
|
+
klass.middlewares.should be_empty
|
71
72
|
end
|
72
73
|
end
|
73
74
|
|
data/spec/unit/resource_spec.rb
CHANGED
@@ -50,7 +50,10 @@ describe Restfulness::Resource do
|
|
50
50
|
it "should return list of supported methods" do
|
51
51
|
obj = resource.new(request, response)
|
52
52
|
obj.options.should be_nil
|
53
|
-
response.headers['Allow'].
|
53
|
+
acts = response.headers['Allow'].split(/, /)
|
54
|
+
['GET', 'POST', 'OPTIONS'].each do |act|
|
55
|
+
acts.should include(act)
|
56
|
+
end
|
54
57
|
end
|
55
58
|
end
|
56
59
|
|
data/spec/unit/response_spec.rb
CHANGED
@@ -36,6 +36,7 @@ describe Restfulness::Response do
|
|
36
36
|
context "without route" do
|
37
37
|
it "should not do anything" do
|
38
38
|
request.stub(:route).and_return(nil)
|
39
|
+
request.stub(:uri).and_return(URI('http://test.com/test'))
|
39
40
|
obj.run
|
40
41
|
obj.status.should eql(404)
|
41
42
|
obj.payload.should be_empty
|
@@ -51,6 +52,7 @@ describe Restfulness::Response do
|
|
51
52
|
it "should try to build resource and run it" do
|
52
53
|
request.stub(:route).and_return(route)
|
53
54
|
request.action = :get
|
55
|
+
request.stub(:uri).and_return(URI('http://test.com/test'))
|
54
56
|
resource = double(:Resource)
|
55
57
|
resource.should_receive(:check_callbacks)
|
56
58
|
resource.should_receive(:call).and_return({:foo => 'bar'})
|
@@ -66,6 +68,7 @@ describe Restfulness::Response do
|
|
66
68
|
it "should call resource and set 204 result if no content" do
|
67
69
|
request.stub(:route).and_return(route)
|
68
70
|
request.action = :get
|
71
|
+
request.stub(:uri).and_return(URI('http://test.com/test'))
|
69
72
|
resource = double(:Resource)
|
70
73
|
resource.should_receive(:check_callbacks)
|
71
74
|
resource.should_receive(:call).and_return(nil)
|
@@ -78,6 +81,7 @@ describe Restfulness::Response do
|
|
78
81
|
it "should set string content type if payload is a string" do
|
79
82
|
request.stub(:route).and_return(route)
|
80
83
|
request.action = :get
|
84
|
+
request.stub(:uri).and_return(URI('http://test.com/test'))
|
81
85
|
resource = double(:Resource)
|
82
86
|
resource.should_receive(:check_callbacks)
|
83
87
|
resource.should_receive(:call).and_return("This is a text message")
|
@@ -96,6 +100,7 @@ describe Restfulness::Response do
|
|
96
100
|
it "should update the status and payload" do
|
97
101
|
request.stub(:route).and_return(route)
|
98
102
|
request.action = :get
|
103
|
+
request.stub(:uri).and_return(URI('http://test.com/test'))
|
99
104
|
resource = double(:Resource)
|
100
105
|
txt = "This is a text error"
|
101
106
|
resource.stub(:check_callbacks) do
|
@@ -111,6 +116,7 @@ describe Restfulness::Response do
|
|
111
116
|
it "should update the status and provide JSON payload" do
|
112
117
|
request.stub(:route).and_return(route)
|
113
118
|
request.action = :get
|
119
|
+
request.stub(:uri).and_return(URI('http://test.com/test'))
|
114
120
|
resource = double(:Resource)
|
115
121
|
err = {:error => "This is a text error"}
|
116
122
|
resource.stub(:check_callbacks) do
|
@@ -123,6 +129,22 @@ describe Restfulness::Response do
|
|
123
129
|
obj.payload.should eql(err.to_json)
|
124
130
|
end
|
125
131
|
|
132
|
+
context "for non http errors" do
|
133
|
+
|
134
|
+
it "should catch error and provide result" do
|
135
|
+
request.stub(:route).and_return(route)
|
136
|
+
request.action = :get
|
137
|
+
request.stub(:uri).and_return(URI('http://test.com/test'))
|
138
|
+
resource = double(:Resource)
|
139
|
+
resource.stub(:check_callbacks) do
|
140
|
+
raise SyntaxError, 'Bad writing'
|
141
|
+
end
|
142
|
+
route.stub(:build_resource).and_return(resource)
|
143
|
+
obj.run
|
144
|
+
obj.status.should eql(500)
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
126
148
|
|
127
149
|
end
|
128
150
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: restfulness
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Lown
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-10-
|
11
|
+
date: 2013-10-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -52,20 +52,6 @@ dependencies:
|
|
52
52
|
- - '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.1'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: mono_logger
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ~>
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '1.0'
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ~>
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '1.0'
|
69
55
|
- !ruby/object:Gem::Dependency
|
70
56
|
name: bundler
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -116,6 +102,7 @@ extensions: []
|
|
116
102
|
extra_rdoc_files: []
|
117
103
|
files:
|
118
104
|
- .gitignore
|
105
|
+
- .travis.yml
|
119
106
|
- Gemfile
|
120
107
|
- LICENSE.txt
|
121
108
|
- README.md
|
@@ -129,8 +116,6 @@ files:
|
|
129
116
|
- lib/restfulness/dispatcher.rb
|
130
117
|
- lib/restfulness/dispatchers/rack.rb
|
131
118
|
- lib/restfulness/exceptions.rb
|
132
|
-
- lib/restfulness/log_formatters/quiet_formatter.rb
|
133
|
-
- lib/restfulness/log_formatters/verbose_formatter.rb
|
134
119
|
- lib/restfulness/path.rb
|
135
120
|
- lib/restfulness/request.rb
|
136
121
|
- lib/restfulness/resource.rb
|
@@ -1,16 +0,0 @@
|
|
1
|
-
module Restfulness
|
2
|
-
class VerboseFormatter
|
3
|
-
def call(serverity, datetime, progname, msg)
|
4
|
-
time = Time.now.strftime('%Y-%m-%d %H:%M:%S.%L')
|
5
|
-
sym = case serverity
|
6
|
-
when 'ERROR'
|
7
|
-
'EE'
|
8
|
-
when 'INFO'
|
9
|
-
'--'
|
10
|
-
else
|
11
|
-
'**'
|
12
|
-
end
|
13
|
-
"#{sym} #{time}: #{msg}\n"
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|