rackful 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES.md +30 -0
- data/RACKFUL.md +159 -0
- data/rackful.gemspec +3 -3
- metadata +8 -6
data/CHANGES.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
0.1.x
|
2
|
+
=====
|
3
|
+
The 0.1.x series is a major revision, not backward compatible with 0.0.x.
|
4
|
+
|
5
|
+
0.1.1
|
6
|
+
-----
|
7
|
+
* Fixed the gemspec file. Not everything new was properly included (including
|
8
|
+
this changelog!).
|
9
|
+
|
10
|
+
0.1.0
|
11
|
+
-----
|
12
|
+
* Complete revision of the {Rackful::HTTPStatus} exception class. From now on,
|
13
|
+
there's
|
14
|
+
a separate class for each HTTP status code, e.g. {Rackful::HTTP404NotFound}.
|
15
|
+
* {Rackful::Path}, a subclass of `String`, is used for HTTP paths. This allows
|
16
|
+
serializers, especially for hypermedia, to distinguish paths from "ordinary"
|
17
|
+
strings, and render them accordingly.
|
18
|
+
* The concept of {Rackful::Serializer Serializers} was introduced. A serializer
|
19
|
+
is an object that knows how to serialize an object to a certain media type.
|
20
|
+
* The mechanism for content negotiation has changed completely. See
|
21
|
+
{Rackful::Resource#serializer} and {Rackful::Resource::ClassMethods#best_content_type}.
|
22
|
+
* The mechanism for implementing HTTP method handlers has changed. See
|
23
|
+
{Rackful::Resource#do_METHOD} and {Rackful::Resource::ClassMethods#add_parser}.
|
24
|
+
|
25
|
+
0.0.x
|
26
|
+
=====
|
27
|
+
|
28
|
+
0.0.2
|
29
|
+
-----
|
30
|
+
* Improved documentation
|
data/RACKFUL.md
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
Rackful
|
2
|
+
=======
|
3
|
+
|
4
|
+
Library for creating Rackful web services
|
5
|
+
|
6
|
+
The latest documentation is always available
|
7
|
+
[here, as GitHub pages](http://pieterb.github.com/Rackful/).
|
8
|
+
|
9
|
+
Rationale
|
10
|
+
---------
|
11
|
+
|
12
|
+
Confronted with the task of implementing a Rackful web service in Ruby, I
|
13
|
+
checked out a number of existing libraries and frameworks, including
|
14
|
+
Ruby-on-Rails, and then decided to brew my own, the reason being that I couldn't
|
15
|
+
find a library or framework with all of the following properties:
|
16
|
+
|
17
|
+
* **Small** Some of these frameworks are really big. I need to get a job done in
|
18
|
+
time. If understanding the framework takes more time than writing my own, I
|
19
|
+
must at least feel confident that the framework I'm learning is more powerful
|
20
|
+
that what I can come up with by myself. Ruby-on-Rails is probably the biggest
|
21
|
+
framework out there, and it still lacks many features that are essential to
|
22
|
+
Rackful web service programming.
|
23
|
+
|
24
|
+
This library is small. You could read _all_ the source code in less than an
|
25
|
+
hour, and understand every detail.
|
26
|
+
|
27
|
+
* **No extensive tooling or code generation** Code generation has been the
|
28
|
+
subject of more than one flame-war over the years. Not much I can add to the
|
29
|
+
debate...
|
30
|
+
|
31
|
+
_...but,_ with Ruby, you shouldn't _need_ code generation!
|
32
|
+
Unless, of course, you're an ex-Java programmer and/or don't understand
|
33
|
+
meta-programming.
|
34
|
+
|
35
|
+
* **Full support for conditional requests** using `If-*:` request headers. Most
|
36
|
+
libraries' support is limited to `If-None-Match:` and `If-Modified-Since:`
|
37
|
+
headers, and only for `GET` and `HEAD` requests. For Rackful web services,
|
38
|
+
the `If-Match:` and `If-Unmodified-Since:` headers are at least as important,
|
39
|
+
particularly for unsafe methods like `PUT`, `POST`, `PATCH`, and `DELETE`.
|
40
|
+
|
41
|
+
This library fully supports the `ETag:` and `Last-Modified:` headers, and all
|
42
|
+
`If-*:` headers.
|
43
|
+
|
44
|
+
* **Resource centered** Some libraries claim Rackfulness, but at the same
|
45
|
+
time have a servet-like interface, which requires you to implement method
|
46
|
+
handles such as `doPOST(url)`. In these method handlers you have to find out
|
47
|
+
what resource is posted to, depending on the URL.
|
48
|
+
|
49
|
+
This library requires that you implement a Resource Factory which maps URIs
|
50
|
+
to resource Objects. These objects will then receive HTTP requests.
|
51
|
+
|
52
|
+
Hello World!
|
53
|
+
------------
|
54
|
+
|
55
|
+
Here's a working example of a simple Rackful server:
|
56
|
+
|
57
|
+
{include:file:example/config.ru}
|
58
|
+
|
59
|
+
This file is included in the distribution as `example/config.ru`.
|
60
|
+
If you go to the `example` directory and run `rackup`, you should see
|
61
|
+
something like this:
|
62
|
+
|
63
|
+
$> rackup
|
64
|
+
[2012-07-10 11:45:32] INFO WEBrick 1.3.1
|
65
|
+
[2012-07-10 11:45:32] INFO ruby 1.9.2 (2011-12-27) [java]
|
66
|
+
[2012-07-10 11:45:32] INFO WEBrick::HTTPServer#start: pid=5994 port=9292
|
67
|
+
|
68
|
+
Go with your browser to {http://localhost:9292/} and be greeted.
|
69
|
+
|
70
|
+
In this example, we implement `GET` and `PUT` requests for the resource at '/'. but
|
71
|
+
we get a few things for free:
|
72
|
+
|
73
|
+
### Free `OPTIONS` response:
|
74
|
+
|
75
|
+
Request:
|
76
|
+
|
77
|
+
OPTIONS / HTTP/1.1
|
78
|
+
Host: localhost:9292
|
79
|
+
|
80
|
+
Response:
|
81
|
+
|
82
|
+
HTTP/1.1 204 No Content
|
83
|
+
Allow: PUT, GET, HEAD, OPTIONS
|
84
|
+
Date: Tue, 10 Jul 2012 10:22:52 GMT
|
85
|
+
|
86
|
+
As you can see, the server accurately reports all available methods for the
|
87
|
+
resource. Notice the availability of the `HEAD` method; if you implement the
|
88
|
+
`GET` method, you'll get `HEAD` for free. It's still a good idea to explicitly
|
89
|
+
implement your own `HEAD` request handler, especially for expensive resources,
|
90
|
+
when responding to a `HEAD` request should be much more efficient than generating
|
91
|
+
a full `GET` response, and strip off the response body.
|
92
|
+
|
93
|
+
### Free conditional request handling:
|
94
|
+
|
95
|
+
Let's first get the current state of the resource, with this request:
|
96
|
+
|
97
|
+
GET / HTTP/1.1
|
98
|
+
Host: localhost:9292
|
99
|
+
|
100
|
+
Response:
|
101
|
+
|
102
|
+
HTTP/1.1 200 OK
|
103
|
+
Content-Type: text/plain
|
104
|
+
Content-Length: 12
|
105
|
+
ETag: "86fb269d190d2c85f6e0468ceca42a20"
|
106
|
+
Date: Tue, 10 Jul 2012 10:34:36 GMT
|
107
|
+
|
108
|
+
Hello world!
|
109
|
+
|
110
|
+
Now, we'd like to change the state of the resource, but only if it's still in
|
111
|
+
the state we last saw, to avoid the "lost update problem". To do that, we
|
112
|
+
produce an `If-Match:` header, with the entity tag of our last version:
|
113
|
+
|
114
|
+
PUT / HTTP/1.1
|
115
|
+
Host: localhost:9292
|
116
|
+
Content-Type: text/plain
|
117
|
+
Content-Length: 31
|
118
|
+
If-Match: "86fb269d190d2c85f6e0468ceca42a20"
|
119
|
+
|
120
|
+
All your base are belong to us.
|
121
|
+
|
122
|
+
Response:
|
123
|
+
|
124
|
+
HTTP/1.1 204 No Content
|
125
|
+
ETag: "920c1e9267f923c62b55a471c1d8a528"
|
126
|
+
Date: Tue, 10 Jul 2012 10:58:57 GMT
|
127
|
+
|
128
|
+
The response contains an `ETag:` header, with the _new_ entity tag of this
|
129
|
+
resource. When we replay this request, we get the following response:
|
130
|
+
|
131
|
+
HTTP/1.1 412 Precondition Failed
|
132
|
+
Content-Type: text/html; charset="UTF-8"
|
133
|
+
Date: Tue, 10 Jul 2012 11:06:54 GMT
|
134
|
+
|
135
|
+
[...]
|
136
|
+
<h1>HTTP/1.1 412 Precondition Failed</h1>
|
137
|
+
<p>If-Match: "86fb269d190d2c85f6e0468ceca42a20"</p>
|
138
|
+
[...]
|
139
|
+
|
140
|
+
The server returns with status <tt>412 Precondition Failed</tt>. In the HTML
|
141
|
+
response body, the server kindly points out exactly which precondition.
|
142
|
+
|
143
|
+
Further reading
|
144
|
+
---------------
|
145
|
+
* {Rackful::Server#initialize} for more information about your Resource Factory.
|
146
|
+
* {Rackful::Resource#get_etag} and {Rackful::Resource#get_last_modified} for more information on
|
147
|
+
conditional requests.
|
148
|
+
* {Rackful::Resource#do_METHOD} for more information about writing your own request
|
149
|
+
handlers.
|
150
|
+
* {Rackful::RelativeLocation} for more information about this piece of Rack middleware
|
151
|
+
which allows you to return relative and absolute paths in the `Location:`
|
152
|
+
response header, and why you'd want that.
|
153
|
+
|
154
|
+
Licensing
|
155
|
+
---------
|
156
|
+
Copyright ©2011-2012 Pieter van Beek <pieterb@sara.nl>
|
157
|
+
|
158
|
+
Licensed under the Apache License 2.0. You should have received a copy of the
|
159
|
+
license as part of this distribution.
|
data/rackful.gemspec
CHANGED
@@ -2,7 +2,7 @@ Gem::Specification.new do |s|
|
|
2
2
|
|
3
3
|
# Required properties:
|
4
4
|
s.name = 'rackful'
|
5
|
-
s.version = '0.1.
|
5
|
+
s.version = '0.1.1'
|
6
6
|
s.summary = "Library for building ReSTful web services with Rack"
|
7
7
|
s.description = <<EOS
|
8
8
|
Rackful provides a minimal interface for developing ReSTful web services with
|
@@ -11,8 +11,8 @@ resource objects, which expose their state at URLs.
|
|
11
11
|
|
12
12
|
This version is NOT backward compatible with versions 0.0.x.
|
13
13
|
EOS
|
14
|
-
s.files = Dir[ '{example/*,lib/**/*}' ] +
|
15
|
-
%w( rackful.gemspec
|
14
|
+
s.files = Dir[ '{*.md,example/*,lib/**/*}' ] +
|
15
|
+
%w( rackful.gemspec mkdoc.sh )
|
16
16
|
|
17
17
|
# Optional properties:
|
18
18
|
s.author = 'Pieter van Beek'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rackful
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-08-
|
12
|
+
date: 2012-08-05 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
16
|
-
requirement: &
|
16
|
+
requirement: &70177120280540 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: '1.4'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70177120280540
|
25
25
|
description: ! 'Rackful provides a minimal interface for developing ReSTful web services
|
26
26
|
with
|
27
27
|
|
@@ -38,6 +38,10 @@ executables: []
|
|
38
38
|
extensions: []
|
39
39
|
extra_rdoc_files: []
|
40
40
|
files:
|
41
|
+
- CHANGES.md
|
42
|
+
- LICENSE.md
|
43
|
+
- RACKFUL.md
|
44
|
+
- README.md
|
41
45
|
- example/config.ru
|
42
46
|
- example/config2.ru
|
43
47
|
- lib/rackful/header_spoofing.rb
|
@@ -51,8 +55,6 @@ files:
|
|
51
55
|
- lib/rackful_serializer.rb
|
52
56
|
- lib/rackful_server.rb
|
53
57
|
- rackful.gemspec
|
54
|
-
- README.md
|
55
|
-
- LICENSE.md
|
56
58
|
- mkdoc.sh
|
57
59
|
homepage: http://pieterb.github.com/Rackful/
|
58
60
|
licenses:
|