Class: Rackful::Server
- Inherits:
-
Object
- Object
- Rackful::Server
- Defined in:
- lib/rackful/server.rb
Overview
Rack compliant server class for implementing RESTful web services.
Instance Method Summary (collapse)
-
- ((status_code, response_headers, response_body)) call(env)
As required by the Rack specification.
- - ((status_code, response_headers, response_body)) call!(env)
-
- (Server) initialize {|uri| ... }
constructor
Constructor.
-
- (Resource) resource_at(uri)
Calls the code block passed to the constructor.
Constructor Details
- (Server) initialize {|uri| ... }
Constructor.
This generic server class has no knowledge, and makes no presumptions,
about your URI namespace. It depends on the code block you provide here to
produce the Resource object which lives at a certain URI. This block will
be called with a normalized URI, and must return
a Resource, or nil
if there’s no resource at the given URI.
If there’s no resource at the given URI, but you’d still like to respond to
POST
or PUT
requests to this URI, you can return
an empty resource.
The provided code block must be thread-safe and reentrant.
24 25 26 |
# File 'lib/rackful/server.rb', line 24 def initialize( &resource_registry ) @resource_registry = resource_registry end |
Instance Method Details
- ((status_code, response_headers, response_body)) call(env)
As required by the Rack specification.
For thread safety, this method clones self
, which handles the
request in #call!. For reentrancy, the clone is stored in the
environment.
48 49 50 |
# File 'lib/rackful/server.rb', line 48 def call( env ) ( env['rackful.server'] ||= self.dup ).call!( env ) end |
- ((status_code, response_headers, response_body)) call!(env)
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/rackful/server.rb', line 55 def call!( env ) request = Request.new( env ) response = Rack::Response.new begin resource = resource_at( request.url ) request.canonical_uri = resource.uri if request.url != request.canonical_uri.to_s if %w{HEAD GET}.include?( request.request_method ) raise HTTP301MovedPermanently, request.canonical_uri end response.header['Content-Location'] = request.canonical_uri.to_s end request.assert_if_headers resource if %w{HEAD GET OPTIONS PUT DELETE}.include?( request.request_method ) resource.__send__( :http_#{request.request_method}", request, response ) else resource.http_method request, response end rescue HTTPStatus => e serializer = e.serializer(request) response = Rack::Response.new response['Content-Type'] = serializer.content_type response.status = e.status if serializer.respond_to? :headers response.headers.merge!( serializer.headers ) end response.body = serializer end # The next line fixes a small peculiarity in RFC2616: the response body of # a `HEAD` request _must_ be empty, even for responses outside 2xx. if request.head? response.body = [] end begin if 201 == response.status && ( location = response['Location'] ) && ( new_resource = resource_at( location ) ) && ! new_resource.empty? \ or ( (200...300) === response.status || 304 == response.status ) && ! response['Location'] && ( new_resource = resource_at( request.canonical_uri ) ) && ! new_resource.empty? response.headers.merge! new_resource.default_headers end rescue HTTP404NotFound => e end response.finish end |
- (Resource) resource_at(uri)
Calls the code block passed to the constructor.
33 34 35 36 37 38 |
# File 'lib/rackful/server.rb', line 33 def resource_at(uri) uri = URI(uri) unless uri.kind_of?( URI::Generic ) retval = @resource_registry.call( uri.normalize ) raise HTTP404NotFound unless retval retval end |