Class: Rack::RDF::ContentNegotiation

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/rdf/conneg.rb

Overview

Rack middleware for Linked Data 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.

Add a :default option to set a content type to use when nothing else is found.

Examples:

use Rack::RDF::ContentNegotation, :format => :ttl
use Rack::RDF::ContentNegotiation, :format => RDF::NTriples::Format
use Rack::RDF::ContentNegotiation, :default => 'application/rdf+xml'

See Also:

Constant Summary collapse

DEFAULT_CONTENT_TYPE =

N-Triples

"application/n-triples"
VARY =
{'Vary' => 'Accept'}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, options) ⇒ ContentNegotiation

Returns a new instance of ContentNegotiation.

Options Hash (options):

  • :default (String) — default: DEFAULT_CONTENT_TYPE

    Specific content type

  • :format (RDF::Format, #to_sym)

    Specific RDF writer format to use



37
38
39
40
# File 'lib/rack/rdf/conneg.rb', line 37

def initialize(app, options)
  @app, @options = app, options
  @options[:default] = (@options[:default] || DEFAULT_CONTENT_TYPE).to_s
end

Instance Attribute Details

#app#call (readonly)



26
27
28
# File 'lib/rack/rdf/conneg.rb', line 26

def app
  @app
end

#optionsHash{Symbol => Object} (readonly)



29
30
31
# File 'lib/rack/rdf/conneg.rb', line 29

def options
  @options
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.

Inserts ordered content types into the environment as ‘ORDERED_CONTENT_TYPES` if an Accept header is present



51
52
53
54
55
56
57
58
59
60
61
# File 'lib/rack/rdf/conneg.rb', line 51

def call(env)
  env['ORDERED_CONTENT_TYPES'] = parse_accept_header(env['HTTP_ACCEPT']) if env.has_key?('HTTP_ACCEPT')
  response = app.call(env)
  body = response[2].respond_to?(:body) ? response[2].body : response[2]
  case body
    when ::RDF::Enumerable
      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 an ‘RDF::Enumerable` response into a Rack protocol response using HTTP content negotiation rules or a specified Content-Type.

Passes parameters from Accept header, and Link header to writer.



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
# File 'lib/rack/rdf/conneg.rb', line 74

def serialize(env, status, headers, body)
  result, content_type = nil, nil
  find_writer(env, headers) do |writer, ct, accept_params = {}|
    begin
      # Passes content_type as writer option to allow parameters to be extracted.
      writer_options = @options.merge(
        accept_params: accept_params,
        link: env['HTTP_LINK']
      )
      result, content_type = writer.dump(body, nil, **writer_options), ct.split(';').first
      break
    rescue ::RDF::WriterError
      # Continue to next writer
      ct
    rescue
      ct
    end
  end

  if result
    headers = headers.merge(VARY).merge('Content-Type' => content_type)
    [status, headers, [result]]
  else
    not_acceptable
  end
end