Class: OpenapiFirst::Router

Inherits:
Object
  • Object
show all
Defined in:
lib/openapi_first/router.rb,
lib/openapi_first/router/find_content.rb,
lib/openapi_first/router/find_response.rb,
lib/openapi_first/router/path_template.rb

Overview

Router can map requests / responses to their API definition

Constant Summary collapse

RequestMatch =

Returned by #match

Data.define(:request_definition, :params, :error, :responses) do
  def match_response(status:, content_type:)
    FindResponse.call(responses, status, content_type, request_method: request_definition.request_method,
                                                       path: request_definition.path)
  end
end
Route =

Returned by #routes to introspect all routes

Data.define(:path, :request_method, :requests, :responses)

Instance Method Summary collapse

Constructor Details

#initializeRouter

Returns a new instance of Router.



24
25
26
27
# File 'lib/openapi_first/router.rb', line 24

def initialize
  @static = {}
  @dynamic = {} # TODO: use a trie or similar
end

Instance Method Details

#add_request(request, request_method:, path:, content_type: nil, allow_empty_content: false) ⇒ Object

Add a request definition



42
43
44
45
46
47
# File 'lib/openapi_first/router.rb', line 42

def add_request(request, request_method:, path:, content_type: nil, allow_empty_content: false)
  route = route_at(path, request_method)
  requests = route[:requests]
  requests[content_type] = request
  requests[nil] = request if allow_empty_content
end

#add_response(response, request_method:, path:, status:, response_content_type: nil) ⇒ Object

Add a response definition



50
51
52
# File 'lib/openapi_first/router.rb', line 50

def add_response(response, request_method:, path:, status:, response_content_type: nil)
  (route_at(path, request_method)[:responses][status] ||= {})[response_content_type] = response
end

#match(request_method, path, content_type: nil) ⇒ Object

Return all request objects that match the given path and request method



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/openapi_first/router.rb', line 55

def match(request_method, path, content_type: nil)
  path_item, params = find_path_item(path)
  unless path_item
    message = "Request path #{path} is not defined in API description."
    return NOT_FOUND.with(error: Failure.new(:not_found, message:))
  end

  contents = path_item.dig(request_method, :requests)
  return NOT_FOUND.with(error: Failure.new(:method_not_allowed)) unless contents

  request_definition = FindContent.call(contents, content_type)
  unless request_definition
    message = "#{content_type_err(content_type)} Content-Type should be #{contents.keys.join(' or ')}."
    return NOT_FOUND.with(error: Failure.new(:unsupported_media_type, message:))
  end

  responses = path_item.dig(request_method, :responses)
  RequestMatch.new(request_definition:, params:, error: nil, responses:)
end

#routesObject

Returns an enumerator of all routes



30
31
32
33
34
35
36
37
38
39
# File 'lib/openapi_first/router.rb', line 30

def routes
  @static.chain(@dynamic).lazy.flat_map do |path, request_methods|
    request_methods.filter_map do |request_method, content|
      next if request_method == :template

      Route.new(path:, request_method:, requests: content[:requests].each_value.lazy.uniq,
                responses: content[:responses].each_value.lazy.flat_map(&:values))
    end
  end
end