webmachine 1.2.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +13 -11
- data/README.md +85 -89
- data/Rakefile +0 -1
- data/documentation/adapters.md +39 -0
- data/documentation/authentication-and-authorization.md +37 -0
- data/documentation/configurator.md +19 -0
- data/documentation/error-handling.md +86 -0
- data/documentation/examples.md +215 -0
- data/documentation/how-it-works.md +76 -0
- data/documentation/routes.md +97 -0
- data/documentation/validation.md +159 -0
- data/documentation/versioning-apis.md +74 -0
- data/documentation/visual-debugger.md +38 -0
- data/examples/application.rb +2 -2
- data/examples/debugger.rb +1 -1
- data/lib/webmachine.rb +3 -1
- data/lib/webmachine/adapter.rb +7 -13
- data/lib/webmachine/adapters.rb +1 -2
- data/lib/webmachine/adapters/httpkit.rb +74 -0
- data/lib/webmachine/adapters/lazy_request_body.rb +1 -2
- data/lib/webmachine/adapters/rack.rb +37 -21
- data/lib/webmachine/adapters/reel.rb +21 -23
- data/lib/webmachine/adapters/webrick.rb +16 -16
- data/lib/webmachine/application.rb +2 -2
- data/lib/webmachine/chunked_body.rb +3 -4
- data/lib/webmachine/constants.rb +75 -0
- data/lib/webmachine/decision/conneg.rb +12 -10
- data/lib/webmachine/decision/flow.rb +31 -21
- data/lib/webmachine/decision/fsm.rb +10 -18
- data/lib/webmachine/decision/helpers.rb +9 -37
- data/lib/webmachine/dispatcher.rb +13 -10
- data/lib/webmachine/dispatcher/route.rb +18 -8
- data/lib/webmachine/errors.rb +7 -1
- data/lib/webmachine/header_negotiation.rb +25 -0
- data/lib/webmachine/headers.rb +7 -2
- data/lib/webmachine/locale/en.yml +7 -5
- data/lib/webmachine/media_type.rb +10 -8
- data/lib/webmachine/request.rb +44 -15
- data/lib/webmachine/resource.rb +1 -1
- data/lib/webmachine/resource/callbacks.rb +6 -4
- data/lib/webmachine/spec/IO_response.body +1 -0
- data/lib/webmachine/spec/adapter_lint.rb +70 -36
- data/lib/webmachine/spec/test_resource.rb +10 -4
- data/lib/webmachine/streaming/fiber_encoder.rb +1 -5
- data/lib/webmachine/streaming/io_encoder.rb +6 -0
- data/lib/webmachine/trace.rb +1 -0
- data/lib/webmachine/trace/fsm.rb +20 -10
- data/lib/webmachine/trace/resource_proxy.rb +2 -0
- data/lib/webmachine/translation.rb +2 -1
- data/lib/webmachine/version.rb +3 -3
- data/memory_test.rb +37 -0
- data/spec/spec_helper.rb +9 -9
- data/spec/webmachine/adapter_spec.rb +14 -15
- data/spec/webmachine/adapters/httpkit_spec.rb +10 -0
- data/spec/webmachine/adapters/rack_spec.rb +6 -6
- data/spec/webmachine/adapters/reel_spec.rb +15 -11
- data/spec/webmachine/adapters/webrick_spec.rb +2 -2
- data/spec/webmachine/application_spec.rb +18 -17
- data/spec/webmachine/chunked_body_spec.rb +3 -3
- data/spec/webmachine/configuration_spec.rb +5 -5
- data/spec/webmachine/cookie_spec.rb +13 -13
- data/spec/webmachine/decision/conneg_spec.rb +48 -42
- data/spec/webmachine/decision/falsey_spec.rb +4 -4
- data/spec/webmachine/decision/flow_spec.rb +194 -144
- data/spec/webmachine/decision/fsm_spec.rb +17 -17
- data/spec/webmachine/decision/helpers_spec.rb +20 -20
- data/spec/webmachine/dispatcher/route_spec.rb +73 -27
- data/spec/webmachine/dispatcher_spec.rb +34 -24
- data/spec/webmachine/errors_spec.rb +1 -1
- data/spec/webmachine/etags_spec.rb +19 -19
- data/spec/webmachine/events_spec.rb +6 -6
- data/spec/webmachine/headers_spec.rb +14 -14
- data/spec/webmachine/media_type_spec.rb +36 -36
- data/spec/webmachine/request_spec.rb +33 -33
- data/spec/webmachine/resource/authentication_spec.rb +6 -6
- data/spec/webmachine/response_spec.rb +12 -12
- data/spec/webmachine/trace/fsm_spec.rb +8 -8
- data/spec/webmachine/trace/resource_proxy_spec.rb +9 -9
- data/spec/webmachine/trace/trace_store_spec.rb +5 -5
- data/spec/webmachine/trace_spec.rb +3 -3
- data/webmachine.gemspec +2 -6
- metadata +48 -206
- data/lib/webmachine/adapters/hatetepe.rb +0 -108
- data/lib/webmachine/adapters/mongrel.rb +0 -127
- data/lib/webmachine/dispatcher/not_found_resource.rb +0 -5
- data/lib/webmachine/fiber18.rb +0 -88
- data/spec/webmachine/adapters/hatetepe_spec.rb +0 -60
- data/spec/webmachine/adapters/mongrel_spec.rb +0 -16
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9c535ba9701c69baab3387693d7060214271a615
|
4
|
+
data.tar.gz: 2701314eb2dd27ba6af46013532b6e653f63ac95
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5e24dfb767ed02c92a69c8d8962dad39abb1652baeb0f7852a692cf61f5baa6fbd36ca297dfca9b10a3262579c4047b83ea6fe1861927177fa50f4e6522803d2
|
7
|
+
data.tar.gz: a2cabce4143030fbec07b5ebdc65c38c1018df32fe6844a23c0ced95c1dc88e434be17c260dadb0205d6279a6c915c67c321f62665a4a4b247f1da9145d42775
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
@@ -1,15 +1,22 @@
|
|
1
1
|
require 'rbconfig'
|
2
|
-
|
3
2
|
source 'https://rubygems.org'
|
4
|
-
|
5
3
|
gemspec
|
6
4
|
|
7
|
-
|
5
|
+
group :development do
|
6
|
+
gem "yard"
|
7
|
+
gem "rake"
|
8
|
+
end
|
9
|
+
|
10
|
+
group :test do
|
11
|
+
gem "rspec", '~> 3.0.0'
|
12
|
+
gem "rspec-its"
|
13
|
+
gem "rack"
|
14
|
+
end
|
8
15
|
|
9
16
|
group :webservers do
|
10
|
-
gem '
|
11
|
-
gem '
|
12
|
-
gem '
|
17
|
+
gem 'reel', '~> 0.5.0'
|
18
|
+
gem 'http', '~> 0.6.0'
|
19
|
+
gem 'httpkit', :platform => [:mri, :rbx]
|
13
20
|
end
|
14
21
|
|
15
22
|
group :guard do
|
@@ -34,8 +41,3 @@ end
|
|
34
41
|
platforms :jruby do
|
35
42
|
gem 'jruby-openssl'
|
36
43
|
end
|
37
|
-
|
38
|
-
platform :rbx do
|
39
|
-
gem 'rubysl'
|
40
|
-
gem 'racc'
|
41
|
-
end
|
data/README.md
CHANGED
@@ -4,9 +4,10 @@ webmachine-ruby is a port of
|
|
4
4
|
[Webmachine](https://github.com/basho/webmachine), which is written in
|
5
5
|
Erlang. The goal of both projects is to expose interesting parts of
|
6
6
|
the HTTP protocol to your application in a declarative way. This
|
7
|
-
means that you are less concerned with
|
8
|
-
more with describing
|
9
|
-
|
7
|
+
means that you are less concerned with the procedures involved in handling
|
8
|
+
requests directly and more with describing facts about the resources
|
9
|
+
that make up your application.
|
10
|
+
Webmachine is not a web framework _per se_, but more of a
|
10
11
|
toolkit for building HTTP-friendly applications. For example, it does
|
11
12
|
not provide a templating engine or a persistence layer; those choices
|
12
13
|
are up to you.
|
@@ -15,46 +16,34 @@ are up to you.
|
|
15
16
|
|
16
17
|
* Handles the hard parts of content negotiation, conditional
|
17
18
|
requests, and response codes for you.
|
18
|
-
*
|
19
|
-
|
20
|
-
|
21
|
-
* Supports WEBrick and Mongrel (1.2pre+), and a Rack shim. Other host
|
19
|
+
* Provides a base resource with points of extension to let you
|
20
|
+
describe what is relevant about your particular resource.
|
21
|
+
* Supports WEBrick, Reel, HTTPkit, and a Rack shim. Other host
|
22
22
|
servers are being investigated.
|
23
23
|
* Streaming/chunked response bodies are permitted as Enumerables,
|
24
24
|
Procs, or Fibers!
|
25
25
|
* Unlike the Erlang original, it does real Language negotiation.
|
26
|
-
* Includes
|
26
|
+
* Includes a visual debugger so you can look through the decision
|
27
27
|
graph to determine how your resources are behaving.
|
28
28
|
|
29
29
|
## Documentation & Finding Help
|
30
30
|
|
31
|
+
* [How it works](/documentation/how-it-works.md) - understand how Webmachine works and the basics of creating a resource.
|
32
|
+
* [Example resources][example-resources] showing how to implement each HTTP method.
|
33
|
+
* [Routes][routes]
|
34
|
+
* [Authentication and authorization][authentication-and-authorization]
|
35
|
+
* [Validation][validation]
|
36
|
+
* [Error handling][error-handling]
|
37
|
+
* [Visual debugger][visual-debugger]
|
38
|
+
* [Configurator][configurator]
|
39
|
+
* [Webserver adapters][adapters]
|
40
|
+
* [Versioning APIs][versioning-apis]
|
31
41
|
* [API documentation](http://rubydoc.info/gems/webmachine/frames/file/README.md)
|
32
42
|
* [Mailing list](mailto:webmachine.rb@librelist.com)
|
33
43
|
* IRC channel #webmachine on freenode
|
34
44
|
|
35
|
-
## A Note about Rack
|
36
|
-
|
37
|
-
In order to be compatible with popular deployment stacks,
|
38
|
-
Webmachine has a [Rack](https://github.com/rack/rack) adapter (thanks to Jamis Buck).
|
39
|
-
**n.b.:** We recommend that NO middleware is used. The
|
40
|
-
behaviors that are encapsulated in Webmachine assume that no modifications
|
41
|
-
are done to requests or response outside of Webmachine.
|
42
|
-
|
43
|
-
## A Note about MRI 1.9
|
44
|
-
|
45
|
-
The [Reel](https://github.com/celluloid/reel) and [Hatetepe](https://github.com/lgierth/hatetepe)
|
46
|
-
adapters might crash with a `SystemStackError` on MRI 1.9 due to its
|
47
|
-
limited fiber stack size. If your application is affected by this, the
|
48
|
-
only known solution is to switch to JRuby, Rubinius or MRI 2.0.
|
49
|
-
|
50
|
-
|
51
45
|
## Getting Started
|
52
46
|
|
53
|
-
[GiddyUp](https://github.com/basho/giddyup) is an actively
|
54
|
-
developed webmachine-ruby app that is in production. You
|
55
|
-
can look there for an example of how to write and structure a
|
56
|
-
webmachine-ruby app (although it is hacky in places).
|
57
|
-
|
58
47
|
Below we go through some examples of how to do basic things
|
59
48
|
with webmachine-ruby.
|
60
49
|
|
@@ -71,8 +60,11 @@ There are many other HTTP features exposed to a resource through
|
|
71
60
|
of the decision tree Webmachine implements, and the decision tree
|
72
61
|
is what makes Webmachine unique and powerful.
|
73
62
|
|
63
|
+
### A simple static HTML resource
|
64
|
+
|
74
65
|
```ruby
|
75
66
|
require 'webmachine'
|
67
|
+
|
76
68
|
class MyResource < Webmachine::Resource
|
77
69
|
def to_html
|
78
70
|
"<html><body>Hello, world!</body></html>"
|
@@ -83,6 +75,39 @@ end
|
|
83
75
|
MyResource.run
|
84
76
|
```
|
85
77
|
|
78
|
+
### A simple dynamic JSON Resource
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
require 'webmachine'
|
82
|
+
require 'widget'
|
83
|
+
|
84
|
+
class MyResource < Webmachine::Resource
|
85
|
+
|
86
|
+
# GET and HEAD are allowed by default, but are shown here for clarity.
|
87
|
+
def allowed_methods
|
88
|
+
['GET','HEAD']
|
89
|
+
end
|
90
|
+
|
91
|
+
def content_types_provided
|
92
|
+
[['application/json', :to_json]]
|
93
|
+
end
|
94
|
+
|
95
|
+
# Return a Truthy or Falsey value
|
96
|
+
def resource_exists?
|
97
|
+
widget
|
98
|
+
end
|
99
|
+
|
100
|
+
def widget
|
101
|
+
@widget ||= Widget.find(request.path_info[:id])
|
102
|
+
end
|
103
|
+
|
104
|
+
def to_json
|
105
|
+
widget.to_json
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
```
|
110
|
+
|
86
111
|
### Router
|
87
112
|
|
88
113
|
The router is used to map a resource to a given path. To map the class `MyResource` to
|
@@ -97,83 +122,44 @@ end
|
|
97
122
|
Webmachine.application.run
|
98
123
|
```
|
99
124
|
|
100
|
-
|
101
|
-
|
102
|
-
There's a configurator that allows you to set what IP address and port
|
103
|
-
a web server should bind to as well as what web server should serve a
|
104
|
-
webmachine resource.
|
105
|
-
|
106
|
-
A call to `Webmachine::Application#configure` returns a `Webmachine::Application` instance,
|
107
|
-
so you could chain other method calls if you like. If you don't want to create your own separate
|
108
|
-
application object `Webmachine.application` will return a global one.
|
125
|
+
When the resource needs to be mapped with variables that will be passed into the resource, use symbols to identify which path components are variables.
|
109
126
|
|
110
127
|
```ruby
|
111
|
-
require 'webmachine'
|
112
|
-
require 'my_resource'
|
113
128
|
|
114
|
-
Webmachine.application.
|
115
|
-
|
116
|
-
config.port = 3000
|
117
|
-
config.adapter = :Mongrel
|
129
|
+
Webmachine.application.routes do
|
130
|
+
add ['myresource', :id], MyResource
|
118
131
|
end
|
119
132
|
|
120
|
-
# Start a web server to serve requests via localhost
|
121
|
-
Webmachine.application.run
|
122
133
|
```
|
123
134
|
|
124
|
-
|
125
|
-
[Reel][reel], and [Hatetepe][hatetepe]. Additionally, the [Rack][rack] adapter lets it
|
126
|
-
run on any webserver that provides a Rack interface. It also lets it run on
|
127
|
-
[Shotgun][shotgun] ([example][shotgun_example]).
|
128
|
-
|
129
|
-
[webrick]: http://rubydoc.info/stdlib/webrick
|
130
|
-
[mongrel]: https://github.com/evan/mongrel
|
131
|
-
[reel]: https://github.com/celluloid/reel
|
132
|
-
[hatetepe]: https://github.com/lgierth/hatetepe
|
133
|
-
[rack]: https://github.com/rack/rack
|
134
|
-
[shotgun]: https://github.com/rtomayko/shotgun
|
135
|
-
[shotgun_example]: https://gist.github.com/4389220
|
136
|
-
|
137
|
-
### Visual debugger
|
138
|
-
|
139
|
-
It can be hard to understand all of the decisions that Webmachine
|
140
|
-
makes when servicing a request to your resource, which is why we have
|
141
|
-
the "visual debugger". In development, you can turn on tracing of the
|
142
|
-
decision graph for a resource by implementing the `#trace?` callback
|
143
|
-
so that it returns true:
|
135
|
+
To add more components to the URL mapping, simply add them to the array.
|
144
136
|
|
145
137
|
```ruby
|
146
|
-
class MyTracedResource < Webmachine::Resource
|
147
|
-
def trace?
|
148
|
-
true
|
149
|
-
end
|
150
138
|
|
151
|
-
|
139
|
+
Webmachine.application.routes do
|
140
|
+
add ['myparentresource', :parent_id, 'myresource', :id], MyResource
|
152
141
|
end
|
142
|
+
|
153
143
|
```
|
154
144
|
|
155
|
-
|
156
|
-
configuration:
|
145
|
+
Read more about routing [here][routes].
|
157
146
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
end
|
164
|
-
```
|
147
|
+
### Application/Configurator
|
148
|
+
|
149
|
+
There is a configurator that allows you to set what IP address and port
|
150
|
+
a web server should bind to as well as what web server should serve a
|
151
|
+
webmachine resource. Learn how to configure your application [here][configurator].
|
165
152
|
|
166
|
-
Now when you visit your traced resource, a trace of the request
|
167
|
-
process will be recorded in memory. Open your browser to `/trace` to
|
168
|
-
list the recorded traces and inspect the result. The response from your
|
169
|
-
traced resource will also include the `X-Webmachine-Trace-Id` that you
|
170
|
-
can use to lookup the trace. It might look something like this:
|
171
153
|
|
172
|
-
|
154
|
+
### Adapters
|
173
155
|
|
174
|
-
|
175
|
-
|
176
|
-
|
156
|
+
Webmachine provides adapters for many popular webservers. Learn more [here][adapters].
|
157
|
+
|
158
|
+
### Visual debugger
|
159
|
+
|
160
|
+
It can be hard to understand all of the decisions that Webmachine
|
161
|
+
makes when servicing a request to your resource, which is why we have
|
162
|
+
the "visual debugger". Learn how to configure it [here][visual-debugger].
|
177
163
|
|
178
164
|
## Related libraries
|
179
165
|
|
@@ -183,6 +169,7 @@ for an example of how to enable the debugger.
|
|
183
169
|
* [webmachine-sprockets](https://github.com/lgierth/webmachine-sprockets) - Integration with Sprockets assets packaging system
|
184
170
|
* [webmachine-actionview](https://github.com/rgarner/webmachine-actionview) - Integration of some Rails-style view conventions into Webmachine
|
185
171
|
* [jruby-http-kit](https://github.com/nLight/jruby-http-kit) - Includes an adapter for the Clojure-based Ring library/server
|
172
|
+
* [newrelic-webmachine](https://github.com/mdub/newrelic-webmachine) - NewRelic instrumentation
|
186
173
|
|
187
174
|
## LICENSE
|
188
175
|
|
@@ -190,3 +177,12 @@ webmachine-ruby is licensed under the
|
|
190
177
|
[Apache v2.0 license](http://www.apache.org/licenses/LICENSE-2.0). See
|
191
178
|
LICENSE for details.
|
192
179
|
|
180
|
+
[example-resources]: /documentation/examples.md
|
181
|
+
[versioning-apis]: /documentation/versioning-apis.md
|
182
|
+
[routes]: /documentation/routes.md
|
183
|
+
[error-handling]: /documentation/error-handling.md
|
184
|
+
[authentication-and-authorization]: /documentation/authentication-and-authorization.md
|
185
|
+
[adapters]: /documentation/adapters.md
|
186
|
+
[visual-debugger]: /documentation/visual-debugger.md
|
187
|
+
[configurator]: /documentation/configurator.md
|
188
|
+
[validation]: /documentation/validation.md
|
data/Rakefile
CHANGED
@@ -0,0 +1,39 @@
|
|
1
|
+
### Adapters
|
2
|
+
|
3
|
+
Webmachine includes adapters for [WEBrick][webrick], [Reel][reel], and
|
4
|
+
[HTTPkit][httpkit]. Additionally, the [Rack][rack] adapter lets it
|
5
|
+
run on any webserver that provides a Rack interface. It also lets it run on
|
6
|
+
[Shotgun][shotgun] ([example][shotgun_example]).
|
7
|
+
|
8
|
+
#### A Note about Rack
|
9
|
+
|
10
|
+
In order to be compatible with popular deployment stacks,
|
11
|
+
Webmachine has a [Rack](https://github.com/rack/rack) adapter (thanks to Jamis Buck).
|
12
|
+
|
13
|
+
Webmachine can be used with Rack middlware features such as Rack::Map and Rack::Cascade as long as:
|
14
|
+
|
15
|
+
1. The Webmachine app is mounted at the root directory.
|
16
|
+
2. Any requests/responses that are handled by the Webmachine app are not modified by the middleware. The behaviours that are encapsulated in Webmachine assume that no modifications
|
17
|
+
are done to requests or response outside of Webmachine.
|
18
|
+
|
19
|
+
Keep in mind that Webmachine already supports many things that Rack middleware is used for with other HTTP frameworks (eg. etags, specifying supported/preferred Accept and Content-Types).
|
20
|
+
|
21
|
+
For an example of using Webmachine with Rack middleware, see the [Pact Broker][middleware-example].
|
22
|
+
|
23
|
+
See the [Rack Adapter API docs][rack-adapter-api-docs] for more information.
|
24
|
+
|
25
|
+
#### A Note about MRI 1.9
|
26
|
+
|
27
|
+
The [Reel][reel] and [HTTPkit][httpkit]
|
28
|
+
adapters might crash with a `SystemStackError` on MRI 1.9 due to its
|
29
|
+
limited fiber stack size. If your application is affected by this, the
|
30
|
+
only known solution is to switch to JRuby, Rubinius or MRI 2.0.
|
31
|
+
|
32
|
+
[webrick]: http://rubydoc.info/stdlib/webrick
|
33
|
+
[reel]: https://github.com/celluloid/reel
|
34
|
+
[httpkit]: https://github.com/lgierth/httpkit
|
35
|
+
[rack]: https://github.com/rack/rack
|
36
|
+
[shotgun]: https://github.com/rtomayko/shotgun
|
37
|
+
[shotgun_example]: https://gist.github.com/4389220
|
38
|
+
[rack-adapter-api-docs]: http://rubydoc.info/gems/webmachine/Webmachine/Adapters/Rack
|
39
|
+
[middleware-example]: https://github.com/bethesque/pact_broker/blob/6dfa71d98e38be94f0776d30bf66cfca58f97d61/lib/pact_broker/app.rb
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Authentication
|
2
|
+
|
3
|
+
To secure a resource, override the `is_authorized?` method to return a boolean indicating whether or not the client is authenticated (ie. your application believes they are who they say they are). Confusingly, the HTTP "401 Unauthorized" response code actually relates to authentication, not authorization (see the [Authorization](#authorization) section below).
|
4
|
+
|
5
|
+
## HTTP Basic Auth
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
|
9
|
+
class MySecureResource < Webmachine::Resource
|
10
|
+
|
11
|
+
include Webmachine::Resource::Authentication
|
12
|
+
|
13
|
+
def is_authorized?(authorization_header)
|
14
|
+
basic_auth(authorization_header, "My Application") do |username, password|
|
15
|
+
@user = User.find_by_username(username)
|
16
|
+
!@user.nil? && @user.auth?(password)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
```
|
23
|
+
|
24
|
+
# Authorization
|
25
|
+
|
26
|
+
Once the client is authenticated (that is, you believe they are who they say they are), override `forbidden?` to return true if the client does not have permission to perform the given method this resource.
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
|
30
|
+
class MySecureResource < Webmachine::Resource
|
31
|
+
|
32
|
+
def forbidden?
|
33
|
+
MySecureResourcePolicy.new(@user, my_secure_domain_model).forbidden?(request.method)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
```
|
@@ -0,0 +1,19 @@
|
|
1
|
+
### Application/Configurator
|
2
|
+
|
3
|
+
A call to `Webmachine::Application#configure` returns a `Webmachine::Application` instance,
|
4
|
+
so you could chain other method calls if you like. If you don't want to create your own separate
|
5
|
+
application object `Webmachine.application` will return a global one.
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
require 'webmachine'
|
9
|
+
require 'my_resource'
|
10
|
+
|
11
|
+
Webmachine.application.configure do |config|
|
12
|
+
config.ip = '127.0.0.1'
|
13
|
+
config.port = 3000
|
14
|
+
config.adapter = :WEBrick
|
15
|
+
end
|
16
|
+
|
17
|
+
# Start a web server to serve requests via localhost
|
18
|
+
Webmachine.application.run
|
19
|
+
```
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# Error handling
|
2
|
+
|
3
|
+
## Handling runtime errors
|
4
|
+
|
5
|
+
Runtime errors should happen infrequently when using Webmachine, as many of the potential causes of "error" will have already been checked in the appropriate callback, and handled with a meaningful HTTP response code (eg. `resource_exists?` or `is_authorized?`).
|
6
|
+
|
7
|
+
To return a custom error response, override `handle_exception` and modify the response body and headers as desired.
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
|
11
|
+
class MyResource < Webmachine::Resource
|
12
|
+
|
13
|
+
def handle_exception e
|
14
|
+
response.headers['Content-Type'] = 'application/json'
|
15
|
+
response.body = {:message => e.message, :backtrace => e.backtrace }.to_json
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
```
|
21
|
+
|
22
|
+
Given that this should be a genuine "Server Error", the response code is set to 500, and cannot be overridden in `handle_exception`. If you must set a custom error response code, but were unable to use one of the previous callbacks to set it, use `finish_request` to set the response code as desired.
|
23
|
+
|
24
|
+
## Customising the error response
|
25
|
+
|
26
|
+
You can modify the response headers and body in any callback.
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
|
30
|
+
class MyResource < Webmachine::Resource
|
31
|
+
|
32
|
+
def resource_exists?
|
33
|
+
@droid = Droid.find(request.path_info[:droid_id]).tap do | droid |
|
34
|
+
unless droid
|
35
|
+
response.headers['Content-Type'] = "text/plain"
|
36
|
+
response.body = "These aren't the droids you're looking for."
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
```
|
44
|
+
|
45
|
+
## Returning a custom error code
|
46
|
+
|
47
|
+
If your response code cannot be determined in an appropriate callback, returning an integer response code from most of the callbacks will cause the response to be returned immediately. You generally only want to do this when new information comes to light, requiring a modification of the response.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
|
51
|
+
class MyResource < Webmachine::Resource
|
52
|
+
|
53
|
+
def content_types_accepted
|
54
|
+
[
|
55
|
+
["application/json", :from_json],
|
56
|
+
["application/xml", :from_xml]
|
57
|
+
]
|
58
|
+
end
|
59
|
+
|
60
|
+
def malformed_request?
|
61
|
+
# Is this JSON or XML? Don't know without a messy if statement.
|
62
|
+
# Maybe cleaner to decide in the response handler for the appropriate Content-Type?
|
63
|
+
false
|
64
|
+
end
|
65
|
+
|
66
|
+
def from_json
|
67
|
+
return 400 if invalid_json?
|
68
|
+
...
|
69
|
+
end
|
70
|
+
|
71
|
+
def from_xml
|
72
|
+
return 400 if invalid_xml?
|
73
|
+
...
|
74
|
+
end
|
75
|
+
|
76
|
+
def invalid_json?
|
77
|
+
...
|
78
|
+
end
|
79
|
+
|
80
|
+
def invalid_xml?
|
81
|
+
...
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
```
|