Class: Rack::SPARQL::ContentNegotiation
- Defined in:
- lib/rack/sparql/conneg.rb
Overview
Rack middleware for SPARQL content negotiation.
Uses HTTP Content Negotiation to find an appropriate RDF
format to serialize any result with a body being RDF::Enumerable.
Override content negotiation by setting the :format option to #initialize.
This endpoint also serves the fuction of Rack::LinkedData, as it will serialize SPARQL results, which may be RDF Graphs
Constant Summary collapse
- VARY =
{'Vary' => 'Accept'}.freeze
Instance Attribute Summary collapse
- #app ⇒ #call readonly
- #options ⇒ Hash{Symbol => Object} readonly
Instance Method Summary collapse
-
#call(env) ⇒ Array(Integer, Hash, #each)
Handles a Rack protocol request.
-
#initialize(app, options = {}) ⇒ ContentNegotiation
constructor
A new instance of ContentNegotiation.
-
#serialize(env, status, headers, body) ⇒ Array(Integer, Hash, #each)
Serializes a SPARQL query result into a Rack protocol response using HTTP content negotiation rules or a specified Content-Type.
Constructor Details
#initialize(app, options = {}) ⇒ ContentNegotiation
Returns a new instance of ContentNegotiation.
32 33 34 |
# File 'lib/rack/sparql/conneg.rb', line 32 def initialize(app, = {}) @app, @options = app, end |
Instance Attribute Details
Instance Method Details
#call(env) ⇒ Array(Integer, Hash, #each)
Handles a Rack protocol request. Parses Accept header to find appropriate mime-type and sets content_type accordingly.
If result is RDF::Literal::Boolean, RDF::Query::Results, or RDF::Enumerable
The result is serialized using SPARQL::Results
Inserts ordered content types into the environment as ORDERED_CONTENT_TYPES if an Accept header is present.
Normalizes application/x-www-form-urlencoded to either application/sparql-query or application/sparql-update forms.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/rack/sparql/conneg.rb', line 49 def call(env) env['ORDERED_CONTENT_TYPES'] = parse_accept_header(env['HTTP_ACCEPT']) if env.has_key?('HTTP_ACCEPT') # Normalize application/x-www-form-urlencoded to application/sparql-query or application/sparql-update if env['REQUEST_METHOD'] == 'POST' && env.fetch('CONTENT_TYPE', 'application/x-www-form-urlencoded').to_s.start_with?('application/x-www-form-urlencoded') content = env['rack.input'].read params = Rack::Utils.parse_query(content) if query = params.delete('query') return [406, {"Content-Type" => "text/plain"}, ["Multiple query parameters"]] unless query.is_a?(String) env['rack.input'] = StringIO.new(query) env['CONTENT_TYPE'] = 'application/sparql-query' env['QUERY_STRING'] = Rack::Utils.build_query(params) elsif update = params.delete('update') return [406, {"Content-Type" => "text/plain"}, ["Multiple update parameters"]] unless update.is_a?(String) env['rack.input'] = StringIO.new(update) env['CONTENT_TYPE'] = 'application/sparql-update' env['QUERY_STRING'] = Rack::Utils.build_query(params) else env['rack.input'].rewind # never mind end end response = app.call(env) body = response[2].respond_to?(:body) ? response[2].body : response[2] body = body.first if body.is_a?(Array) && body.length == 1 && body.first.is_a?(RDF::Literal::Boolean) case body when RDF::Enumerable, RDF::Query::Solutions, RDF::Literal::Boolean response[2] = body # Put it back in the response, it might have been a proxy serialize(env, *response) else response end end |
#serialize(env, status, headers, body) ⇒ Array(Integer, Hash, #each)
Serializes a SPARQL query result into a Rack protocol response using HTTP content negotiation rules or a specified Content-Type.
90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/rack/sparql/conneg.rb', line 90 def serialize(env, status, headers, body) begin = {} [:content_types] = env['ORDERED_CONTENT_TYPES'] if env['ORDERED_CONTENT_TYPES'] .merge!(@options) results = ::SPARQL.serialize_results(body, **) raise RDF::WriterError, "can't serialize results" unless results headers = headers.merge(VARY).merge('Content-Type' => results.content_type) # FIXME: don't overwrite existing Vary headers [status, headers, [results]] rescue RDF::WriterError => e # Use this instead of not_acceptable so that headers are not lost. http_error(406, e., headers.merge(VARY)) end end |