lib/lurker/endpoint.rb in lurker-0.6.1 vs lib/lurker/endpoint.rb in lurker-0.6.2
- old
+ new
@@ -2,223 +2,168 @@
require 'erb'
require 'json-schema'
# Endpoints represent the schema for an API endpoint
# The #consume_* methods will raise exceptions if input differs from the schema
-class Lurker::Endpoint
+module Lurker
+ class Endpoint
+ include Lurker::Utils
- attr_reader :schema, :service, :endpoint_path, :current_scaffold, :extensions
- attr_accessor :errors
+ attr_reader :schema, :service, :endpoint_path, :extensions
+ attr_reader :request_parameters, :response_parameters, :response_codes
+ attr_accessor :errors
- def initialize(endpoint_path, extensions={}, service=Lurker::Service.default_service)
- @endpoint_path = endpoint_path
- @extensions = extensions
- @service = service
- @errors = []
- @persisted = false
- @schema = File.exist?(endpoint_path) ? load_schema : build_schema
- end
+ def initialize(endpoint_path, extensions = {}, service = Lurker::Service.default_service)
+ @endpoint_path = endpoint_path
+ @extensions = extensions
+ @service = service
+ @errors = []
+ @persisted = false
+ @schema = File.exist?(endpoint_path) ? load_schema : build_schema
- def persist!
- schema.ordered!.write_to(endpoint_path)
- @persisted = true
- end
+ initialize_schema_properties
+ end
- def indexed?
- prefix.present? && description.present?
- end
+ def persist!
+ schema.ordered! unless persisted?
+ schema.write_to(endpoint_path)
- def consume!(request_params, response_params, status_code, successful=true)
- consume_request(request_params, successful)
- consume_response(response_params, status_code, successful)
- raise_errors!
- end
+ @persisted = true
+ end
- def consume_request(params, successful=true)
- if successful
- Lurker::SchemaModifier.merge!(request_parameters, stringify_keys(params))
+ def indexed?
+ prefix.present? && description.present?
end
- end
- def consume_response(params, status_code, successful=true)
- return validate_response(params, status_code, successful) if persisted?
+ def consume!(request_params, response_params, status_code, successful = true)
+ consume_request(request_params, successful)
+ consume_response(response_params, status_code, successful)
- if successful
- Lurker::SchemaModifier.merge!(response_parameters, stringify_keys(params))
+ raise_errors!
end
- if !status_code_exists?(status_code, successful)
- response_code = {
- "status" => status_code,
- "successful" => successful,
- "description" => ""
- }
-
- Lurker::SchemaModifier.append!(response_codes, response_code)
+ def consume_request(params, successful = true)
+ request_parameters.validate(params) if persisted?
+ request_parameters.add(params) if successful
end
- end
- def verb
- @verb ||= endpoint_path.match(/([A-Z]*)\.json(\.yml)?(\.erb)?$/)[1]
- end
+ def consume_response(params, status_code, successful = true)
+ if persisted?
+ response_codes.validate!(status_code, successful)
+ response_parameters.validate(params) if successful
- def path
- @path ||= endpoint_path.
- gsub(service.service_dir, "").
- match(/\/?(.*)[-\/][A-Z]+\.json(\.yml)?(\.erb)?$/)[1]
- end
+ return
+ end
- # properties
+ response_parameters.add(params) if successful
+ response_codes.add(status_code, successful) unless response_codes.exists?(
+ status_code, successful)
+ end
- def deprecated?
- @schema["deprecated"]
- end
+ def verb
+ @verb ||= endpoint_path.match(/([A-Z]*)\.json(\.yml)?(\.erb)?$/)[1]
+ end
+ def path
+ @path ||= endpoint_path.
+ gsub(service.service_dir, "").
+ match(/\/?(.*)[-\/][A-Z]+\.json(\.yml)?(\.erb)?$/)[1]
+ end
- def prefix
- @schema["prefix"]
- end
+ # properties
- def description
- @schema["description"]
- end
+ def deprecated?
+ @schema["deprecated"]
+ end
- def url_params
- (schema.extensions['path_params'] || {}).reject { |k, _| ['action', 'controller', 'format'].include? k }
- end
+ def prefix
+ @schema["prefix"]
+ end
- def query_params
- (schema.extensions['query_params'] || {})
- end
+ def description
+ @schema["description"]
+ end
- def request_parameters
- @schema["requestParameters"] ||= {}
- end
+ def url_params
+ (schema.extensions['path_params'] || {}).reject { |k, _| %w(action controller format).include? k }
+ end
- def response_parameters
- @schema["responseParameters"] ||= {}
- end
+ def query_params
+ (schema.extensions['query_params'] || {})
+ end
- def response_codes
- @schema["responseCodes"] ||= []
- end
+ protected
- protected
+ def initialize_schema_properties
+ @response_codes = ResponseCodes.new(schema)
- def persisted?
- !!@persisted
- end
+ @response_parameters = HttpParameters.new(schema,
+ schema_key: 'responseParameters', schema_id: endpoint_path, human_name: 'Response')
- def load_schema
- @persisted = true
+ @request_parameters = HttpParameters.new(schema,
+ schema_key: 'requestParameters', schema_id: endpoint_path, human_name: 'Request')
+ end
- Lurker::Schema.new(
- load_file(endpoint_path),
- stringify_keys(extensions)
- )
- end
+ def persisted?
+ !!@persisted
+ end
- def build_schema
- @persisted = false
+ def load_schema
+ @persisted = true
- Lurker::Schema.new(
- {
- "prefix" => "",
- "description" => "",
- "responseCodes" => []
- },
- stringify_keys(extensions)
- )
- end
-
- def load_file(fname)
- if fname.match(/\.erb$/)
- context = Lurker::ErbSchemaContext.new
- erb = ERB.new(IO.read(fname)).result(context.get_binding)
- YAML.load(erb)
- else
- YAML.load_file(fname)
+ Lurker::Schema.new(
+ load_file(endpoint_path),
+ stringify_keys(extensions)
+ )
end
- end
- def validate(expected_params, given_params, prefix=nil)
- schema = set_additional_properties_false_on(expected_params.dup)
- schema['id'] = "file://#{endpoint_path}"
- unless (_errors = Lurker::Validator.new(schema, stringify_keys(given_params), record_errors: true).validate).empty?
- self.errors << prefix
- _errors.each { |e| self.errors << "- #{e}" }
- return false
- end
- true
- end
+ def build_schema
+ @persisted = false
- def validate_response(params, status_code, successful)
- if !status_code_exists?(status_code, successful)
- raise Lurker::UndocumentedResponseCode,
- 'Undocumented response: %s, successful: %s' % [
- status_code, successful
- ]
- elsif successful
- validate(response_parameters, params, 'Response')
- else
- true
+ Lurker::Schema.new(
+ {
+ "prefix" => "",
+ "description" => "",
+ "responseCodes" => []
+ },
+ stringify_keys(extensions)
+ )
end
- end
- def status_code_exists?(status_code, successful)
- !!response_codes.detect do |code|
- code["successful"] == successful &&
- (code["status"] == status_code || # 200
- code["status"].to_i == status_code) # "200 OK"
+ def load_file(fname)
+ if fname.match(/\.erb$/)
+ context = Lurker::ErbSchemaContext.new
+ erb = ERB.new(IO.read(fname)).result(context.get_binding)
+ YAML.load(erb)
+ else
+ YAML.load_file(fname)
+ end
end
- end
- def raise_errors!
- unless errors.empty?
- raise Lurker::ValidationError.new(word_wrap((
- # ['Schema', "- #{endpoint_path}"] +
- errors
- # + ['Diff', current_scaffold.schema.diff(schema)]
- ).join("\n")))
- end
- end
+ def raise_errors!
+ return if response_parameters.errors.empty?
- def word_wrap(text)
- text.gsub(/\s+in schema/m, "\n in schema")
- end
-
- # default additionalProperties on objects to false
- # create a copy, so we don't mutate the input
- def set_additional_properties_false_on(value)
- if value.kind_of? Hash
- copy = value.dup
- if value["type"] == "object" || value.has_key?("properties")
- copy["additionalProperties"] ||= false
+ errors = (request_parameters.errors | response_parameters.errors) * "\n"
+ exception = Lurker::ValidationError.new(word_wrap errors)
+ if (example = Lurker::Spy.current.block).respond_to?(:metadata) && (metadata = example.metadata).respond_to?(:location, true)
+ exception.set_backtrace [metadata.send(:location)]
end
- value.each do |key, hash_val|
- unless key == "additionalProperties"
- copy[key] = set_additional_properties_false_on(hash_val)
- end
- end
- copy
- elsif value.kind_of? Array
- copy = value.map do |arr_val|
- set_additional_properties_false_on(arr_val)
- end
- else
- value
+ raise exception
end
- end
- def stringify_keys(obj)
- case obj
- when Hash
- result = {}
- obj.each do |k, v|
- result[k.to_s] = stringify_keys(v)
+ def word_wrap(text)
+ # strip .json# | .json.yml# | .json.yml.erb#
+ text = text.reverse
+ text.gsub!(/(\n|^)#bre\./, "\nbre.")
+ text.gsub!(/(\n|^)#lmy\./, "\nlmy.")
+ text.gsub!(/(\n|^)#nosj\./, "\nnosj.")
+ text.strip!
+ text = text.reverse
+
+ text.gsub!(/\s+in schema/m, "\n in schema")
+ if defined?(Rails)
+ text.gsub!(/file:\/\/#{Rails.root}\//m, "")
end
- result
- when Array then obj.map { |v| stringify_keys(v) }
- else obj
+ text
end
end
end