Class: Gitlab::GrapeOpenapi::NormalizedPath

Inherits:
Object
  • Object
show all
Defined in:
lib/gitlab/grape_openapi/normalized_path.rb

Overview

A Grape route pattern rendered as an OpenAPI path template.

Grape spells path placeholders two ways: :name matches a single segment, and *name (a splat) matches one or more segments, so its value may contain slashes. OpenAPI 3.0 has no splat syntax, so both collapse to {name}.

The splat mapping is lossy - {name} implies a single segment - but the endpoint is documented, which is strictly better than omitting it. Do not "fix" this by dropping splat routes: that is the bug in issue #22, which silently removed the entire package registry surface from the spec.

Constant Summary collapse

FORMAT_SUFFIX =

Grape appends the format suffix to route.path, not to route.pattern.origin, so this only strips a suffix an author wrote into the pattern by hand. Without it, a declared format param would be mistaken for a path parameter.

/\(\.:format\)$/
PLACEHOLDER =
/[:*](\w+)/
NORMALIZED_PLACEHOLDER =
/\{(\w+)\}/
API_VERSION_PLACEHOLDER =

The API version is substituted away with the configured value before a path is emitted, so it never surfaces as a path parameter.

'version'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(origin) ⇒ NormalizedPath

Takes a route.pattern.origin - the pattern as the author declared it. Do not pass route.path: Grape rewrites that one, appending the format suffix and turning a trailing *path into ?*path.



33
34
35
# File 'lib/gitlab/grape_openapi/normalized_path.rb', line 33

def initialize(origin)
  @origin = origin
end

Instance Attribute Details

#originObject (readonly)

Returns the value of attribute origin.



28
29
30
# File 'lib/gitlab/grape_openapi/normalized_path.rb', line 28

def origin
  @origin
end

Instance Method Details

#path_parameter_namesObject



51
52
53
# File 'lib/gitlab/grape_openapi/normalized_path.rb', line 51

def path_parameter_names
  placeholder_names - [API_VERSION_PLACEHOLDER]
end

#placeholder_namesObject



43
44
45
46
47
48
49
# File 'lib/gitlab/grape_openapi/normalized_path.rb', line 43

def placeholder_names
  # Scanning whole `{name}` placeholders sidesteps the boundary problem a regex
  # over the raw pattern has: real routes introduce a placeholder after `/`,
  # `(`, `)` and `'` - `(*path`, `):file_name`, `Id='*package_name'` - so there
  # is no single delimiter to anchor on.
  @placeholder_names ||= to_s.scan(NORMALIZED_PLACEHOLDER).flatten
end

#to_sObject



37
38
39
40
41
# File 'lib/gitlab/grape_openapi/normalized_path.rb', line 37

def to_s
  @to_s ||= origin
    .sub(FORMAT_SUFFIX, '')
    .gsub(PLACEHOLDER) { "{#{Regexp.last_match(1)}}" }
end