class JSONAPI::Middleware

The middleware of the gem and also the contact point between the the gem and the rack application using it

Public Class Methods

new(app, &block) click to toggle source

@param app The Rack Application

# File lib/easy/jsonapi/middleware.rb, line 13
def initialize(app, &block)
  @app = app
  return unless block_given?

  @config_manager = JSONAPI::ConfigManager.new
  block.call(@config_manager)
end

Public Instance Methods

call(env) click to toggle source

If not in maintenance_mode and the request is intended to be JSONAPI,

it checks headers, params, and body it for compliance and raises
and error if any section is found to be non-compliant.

@param env The rack envirornment hash

# File lib/easy/jsonapi/middleware.rb, line 25
def call(env)
  if in_maintenance_mode?
    return maintenance_response
  end

  if jsonapi_request?(env)
    error_response = check_compliance(env, @config_manager)
    return error_response unless error_response.nil?
  end

  @app.call(env)
end

Private Instance Methods

accept_header_jsonapi?(env) click to toggle source

Determines whether the request is JSONAPI or not by looking at

the ACCEPT header.

@env (see call) @return [TrueClass | FalseClass] Whether or not the request is JSONAPI

# File lib/easy/jsonapi/middleware.rb, line 67
def accept_header_jsonapi?(env)
  return true if env['HTTP_ACCEPT'].nil? # no header means assume any

  env['HTTP_ACCEPT'].split(',').any? do |hdr|
    ['application/vnd.api+json', '*/*', 'application/*'].include?(hdr.split(';').first)
  end
end
check_body_compliance(body, config_manager, opts) click to toggle source

@param env (see call) @param req (see check_query_param_compliance) @raise If the document body is not JSONAPI compliant

# File lib/easy/jsonapi/middleware.rb, line 132
def check_body_compliance(body, config_manager, opts)
  JSONAPI::Exceptions::DocumentExceptions.check_compliance(body, config_manager, opts)
rescue JSONAPI::Exceptions::DocumentExceptions::InvalidDocument, JSONAPI::Exceptions::UserDefinedExceptions::InvalidDocument => e
  raise if environment_development?

  [e.status_code, {}, []]
rescue JSONAPI::Exceptions::JSONParseError
  raise if environment_development?

  [400, {}, []]
end
check_compliance(env, config_manager) click to toggle source

Checks whether the request is JSON:API compliant and raises an error if not. @param env (see call) @param config_manager [JSONAPI::ConfigManager::Config] The config object to use modify compliance checking @return [NilClass | Array] Nil meaning no error or a 400 level http response

# File lib/easy/jsonapi/middleware.rb, line 88
def check_compliance(env, config_manager)
  # Store separately so you can rewind for next middleware or app
  body = env['rack.input'].read
  env['rack.input'].rewind
  opts = { http_method: env['REQUEST_METHOD'], path: env['PATH_INFO'], contains_body: body != "" }

  header_error = check_headers_compliance(env, config_manager, opts)
  return header_error unless header_error.nil?

  req = Rack::Request.new(env)
  param_error = check_query_param_compliance(req.GET, config_manager, opts)
  return param_error unless param_error.nil?
  
  return unless env['CONTENT_TYPE']

  body_error = check_body_compliance(body, config_manager, opts)
  return body_error unless body_error.nil?
end
check_headers_compliance(env, config_manager, opts) click to toggle source

Checks whether the http headers are jsonapi compliant @param (see call) @return [NilClass | Array] Nil meaning no error or a 400 level http response

# File lib/easy/jsonapi/middleware.rb, line 110
def check_headers_compliance(env, config_manager, opts)
  JSONAPI::Exceptions::HeadersExceptions.check_request(env, config_manager, opts)
rescue JSONAPI::Exceptions::HeadersExceptions::InvalidHeader, JSONAPI::Exceptions::UserDefinedExceptions::InvalidHeader => e
  raise if environment_development?

  [e.status_code, {}, []]
end
check_query_param_compliance(query_params, config_manager, opts) click to toggle source

@param query_params [Hash] The rack request query_param hash @raise If the query parameters are not JSONAPI compliant @return [NilClass | Array] Nil meaning no error or a 400 level http response

# File lib/easy/jsonapi/middleware.rb, line 121
def check_query_param_compliance(query_params, config_manager, opts)
  JSONAPI::Exceptions::QueryParamsExceptions.check_compliance(query_params, config_manager, opts)
rescue JSONAPI::Exceptions::QueryParamsExceptions::InvalidQueryParameter, JSONAPI::Exceptions::UserDefinedExceptions::InvalidQueryParam => e
  raise if environment_development?
  
  [e.status_code, {}, []]
end
content_type_header_jsonapi?(env) click to toggle source

Determines whether there is a request body, and whether the Content-Type is jsonapi compliant. @param (see call) @return [TrueClass | FalseClass] Whether the document body is supposed to be jsonapi

# File lib/easy/jsonapi/middleware.rb, line 78
def content_type_header_jsonapi?(env)
  return false unless env['CONTENT_TYPE']

  env['CONTENT_TYPE'].include? 'application/vnd.api+json'
end
environment_development?() click to toggle source

@param (see call)

# File lib/easy/jsonapi/middleware.rb, line 152
def environment_development?
  ENV['RACK_ENV'].to_s.downcase == 'development' || ENV['RACK_ENV'].nil?
end
in_maintenance_mode?() click to toggle source

Checks the 'MAINTENANCE' environment variable @return [TrueClass | FalseClass]

# File lib/easy/jsonapi/middleware.rb, line 42
def in_maintenance_mode?
  !ENV['MAINTENANCE'].nil?
end
jsonapi_request?(env) click to toggle source

If the Content-type or Accept header values include the JSON:API media type without media

parameters, then it is a jsonapi request.

@param (see call)

# File lib/easy/jsonapi/middleware.rb, line 59
def jsonapi_request?(env)
  accept_header_jsonapi?(env) || content_type_header_jsonapi?(env)
end
maintenance_response() click to toggle source

Return 503 with or without msg depending on environment @return [Array] Http Error Responses

# File lib/easy/jsonapi/middleware.rb, line 48
def maintenance_response
  if environment_development?
    [503, {}, ['MAINTENANCE envirornment variable set']]
  else
    [503, {}, []]
  end
end
post_put_or_patch?(env) click to toggle source

@param (see call)

# File lib/easy/jsonapi/middleware.rb, line 145
def post_put_or_patch?(env)
  env['REQUEST_METHOD'] == 'POST' ||
    env['REQUEST_METHOD'] == 'PATCH' ||
    env['REQUEST_METHOD'] == 'PUT'
end