module Krikri::LDP::Resource
Implements basic LDP
CRUD operations. Requires an implementation of `#rdf_subject` returning an `RDF::URI`. The resource idenitified by the URI must conform to LDP
Resource's interaction patterns.
@example implementing a resource
class MyResource include Krikri::LDP::Resource def rdf_subject @rdf_subject ||= RDF::URI('http://example.com/ldp/a/resource/path') end end
@note Ideally, this is a general purpose LDP
resource. However some HTTP
PUT creation behavior may be specific to Marmotta. This avoids the need to interact directly with the owning container, but is a less generalized implementation.
@see www.w3.org/TR/ldp/#h-ldpr-resource LDP
Resource
interaction
patterns.
@see wiki.apache.org/marmotta/LDPImplementationReport for
information about Marmotta's PUT.
Public Instance Methods
Sends DELETE request to the resource's rdf_subject via ldp_connection
. Headers can be passed in. Default HTTP headers are:
If-Match: "#{etag}" (uses idempotent put if an Entity Tag is cached)
# File lib/krikri/ldp/resource.rb, line 132 def delete!(headers = {}) raise "Cannot delete #{rdf_subject}, does not exist." unless exist? headers['If-Match'] ||= etag response = make_request(:delete, nil, headers) @http_headers = nil response end
@return [String] the current cached HTTP ETag for the resource
# File lib/krikri/ldp/resource.rb, line 50 def etag http_head['etag'] if exists? end
@return [Boolean] true if the LDP
server already knows about the resource,
otherwise false.
# File lib/krikri/ldp/resource.rb, line 94 def exists? return true if http_head false rescue Faraday::ResourceNotFound false rescue Faraday::ClientError => e return false if !e.response.nil? && e.response[:status] == 410 raise e end
Sends a GET request to rdf_subject and caches the headers and body. Executes lazily unless `force` parameter is `true`, using cached values if present.
@param headers [Hash<String, String>] a hash of HTTP headers;
e.g. {'Content-Type' => 'text/plain'}.
@param force [Boolean] force request if true
@raise (see make_request
) @return [Faraday::Response] the server's response
# File lib/krikri/ldp/resource.rb, line 84 def get(headers = {}, force = false) return @http_cache if @http_cache && !force response = make_request(:get, nil, headers) @http_headers = response.env['response_headers'] @http_cache = response end
Sends a HEAD request to rdf_subject and caches the headers. Executes lazily unless `force` parameter is `true`, using cached values if present.
@param force [Boolean] force request if true
@raise (see make_request
) @return [Hash<String, String>] a hash of HTTP headers
# File lib/krikri/ldp/resource.rb, line 68 def http_head(force = false) return @http_headers if @http_headers && !force @http_headers = make_request(:head).env['response_headers'] end
@return [Faraday::Connection] a connection to the configured LDP
endpoint
# File lib/krikri/ldp/resource.rb, line 33 def ldp_connection @ldp_conn ||= Faraday.new(ldp_ns) do |conn| conn.request :retry, max: 4, interval: 0.025, interval_randomness: 0.5, backoff_factor: 2, exceptions: [Faraday::ConnectionFailed, 'Errno::ETIMEDOUT', 'Timeout::Error', 'Error::TimeoutError', Faraday::TimeoutError] conn.use Faraday::Response::RaiseError conn.use FaradayMiddleware::FollowRedirects, limit: 3 conn.adapter Faraday.default_adapter end end
@return [String] the current cached Last-Modified date for the resource
# File lib/krikri/ldp/resource.rb, line 56 def modified_date http_head['last-modified'] if exists? end
Sends PUT request to the resource's rdf_subject via ldp_connection
. A body and headers can be passed in. Default HTTP headers are:
Content-Type: 'text/turtle' (i.e. creates an LDP-RS) If-Match: "#{etag}" (uses idempotent put if an Entity Tag is cached)
@param body [#to_s] the request body. @param headers [Hash<String, String>] a hash of HTTP headers;
e.g. {'Content-Type' => 'text/plain'}.
@raise (see make_request
) @return [Faraday::Response] the server's response
# File lib/krikri/ldp/resource.rb, line 118 def save(body = nil, headers = {}) headers['Content-Type'] ||= default_content_type headers['If-Match'] ||= etag if exists? response = make_request(:put, body, headers) @http_headers = response.env['response_headers'] response end
Private Instance Methods
# File lib/krikri/ldp/resource.rb, line 163 def default_content_type 'text/turtle' end
# File lib/krikri/ldp/resource.rb, line 169 def ldp_ns Krikri::Settings['marmotta']['ldp'] end
Lightly wraps Faraday to manage requests of various types, their bodies and headers.
@param method [Symbol] HTTP method/verb. @param body [#to_s] the request body. @param headers [Hash<String, String>] a hash of HTTP headers;
e.g. {'Content-Type' => 'text/plain'}.
@raise [Faraday::ClientError] if the server responds with an error status.
Faraday::ClientError#response contains the full response.
@return [Faraday::Response] the server's response
# File lib/krikri/ldp/resource.rb, line 154 def make_request(method, body = nil, headers = {}) validate_subject ldp_connection.send(method) do |request| request.url rdf_subject request.headers = headers if headers request.body = body end end
# File lib/krikri/ldp/resource.rb, line 190 def validate_namespace raise "#{self.class} requires an rdf_subject in #{ldp_ns}, but "\ "got #{rdf_subject}." unless rdf_subject.to_s.starts_with? ldp_ns end
# File lib/krikri/ldp/resource.rb, line 180 def validate_not_nil raise "#{self.class} requires a URI rdf_subject, but got nil." if rdf_subject.nil? end
# File lib/krikri/ldp/resource.rb, line 185 def validate_not_node raise "#{self.class} requires a URI rdf_subject, but got a node." if rdf_subject.respond_to?(:node?) && rdf_subject.node? end
# File lib/krikri/ldp/resource.rb, line 173 def validate_subject validate_not_nil validate_not_node validate_namespace true end