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.

Parameters:

  • app (#call)
  • options (Hash{Symbol => Object})

    Other options passed to writer.

  • :default (String)

    (DEFAULT_CONTENT_TYPE) Specific content type

Options Hash (options):

  • :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)

Returns:



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

def app
  @app
end

#optionsHash{Symbol => Object} (readonly)

Returns:

  • (Hash{Symbol => Object})


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

Parameters:

  • env (Hash{String => String})

Returns:

  • (Array(Integer, Hash, #each))

    Status, Headers and Body

See Also:



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.

Parameters:

  • env (Hash{String => String})
  • status (Integer)
  • headers (Hash{String => Object})
  • body (RDF::Enumerable)

Returns:

  • (Array(Integer, Hash, #each))

    Status, Headers and Body



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