diff --git a/lib/openapi_first/router.rb b/lib/openapi_first/router.rb index 9f04ec8a..5f7189fc 100644 --- a/lib/openapi_first/router.rb +++ b/lib/openapi_first/router.rb @@ -97,10 +97,15 @@ def find_path_item(request_path) found = @static[request_path] return [found, {}] if found - @dynamic.find do |_path, path_item| + matches = @dynamic.filter_map do |_path, path_item| params = path_item[:template].match(request_path) - return [path_item, params] if params + next unless params + + [path_item, params] end + return matches.first if matches.length == 1 + + matches&.min_by { |match| match[1].values.sum(&:length) } end end end diff --git a/spec/router_spec.rb b/spec/router_spec.rb index 4ebd5c4f..6546d121 100644 --- a/spec/router_spec.rb +++ b/spec/router_spec.rb @@ -8,7 +8,8 @@ [ double(path: '/{id}', request_method: 'get'), double(path: '/{id}', request_method: 'patch'), - double(path: '/a', request_method: 'get') + double(path: '/a', request_method: 'get'), + double(path: '/a{format}', request_method: 'get') ] end @@ -30,6 +31,12 @@ expect(router.match('GET', '/c/d').error).to have_attributes(type: :not_found) end + it 'can match a path fragment with a variable' do + match = router.match('GET', '/a.json') + expect(match.request_definition.path).to eq('/a{format}') + expect(match.request_definition).to be(requests[3]) + end + it 'returns an incomplete match for unknown request method' do expect(router.match('DELETE', '/b').error).to have_attributes(type: :method_not_allowed) end