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, = app, end |
Instance Attribute Details
#app ⇒ #call (readonly)
21 22 23 |
# File 'lib/rack/sparql/conneg.rb', line 21 def app @app end |
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!() 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 |