Class: GrapeOpenapi3::Builders::OperationIdBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/grape_openapi3/builders/operation_id_builder.rb

Overview

Derives a camelCase operationId from an HTTP method + normalized path.

Rules:

GET    /products            → listProducts
GET    /products/{id}       → getProduct
POST   /products            → createProduct
PUT    /products/{id}       → updateProduct
PATCH  /products/{id}       → updateProduct
DELETE /products/{id}       → deleteProduct

Nested resources:

GET    /products/{id}/images        → listProductImages
POST   /products/{id}/images        → createProductImage
GET    /products/{id}/images/{id}   → getProductImage

Constant Summary collapse

ACTIONS =
{
  "get"    => ->(trailing_param) { trailing_param ? "get"    : "list"   },
  "post"   => ->(_)              { "create"  },
  "put"    => ->(_)              { "update"  },
  "patch"  => ->(_)              { "update"  },
  "delete" => ->(_)              { "delete"  },
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(http_method, path) ⇒ OperationIdBuilder

Returns a new instance of OperationIdBuilder.



32
33
34
35
# File 'lib/grape_openapi3/builders/operation_id_builder.rb', line 32

def initialize(http_method, path)
  @method = http_method.downcase
  @path   = path
end

Class Method Details

.call(http_method, path) ⇒ Object



28
29
30
# File 'lib/grape_openapi3/builders/operation_id_builder.rb', line 28

def self.call(http_method, path)
  new(http_method, path).call
end

Instance Method Details

#callObject



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/grape_openapi3/builders/operation_id_builder.rb', line 37

def call
  segments = @path.split("/").reject(&:empty?)
  trailing_param = segments.last&.match?(/\A\{.+\}\z/)

  # Keep only real resource name segments (skip {params}, vN, "api")
  resources = segments.reject do |s|
    s.match?(/\A\{.+\}\z/) ||
    s.match?(/\Av\d+\z/)   ||
    s == "api"
  end

  return fallback if resources.empty?

  action     = ACTIONS.fetch(@method, ->(_) { @method }).call(trailing_param)
  # For known verbs, "list" signals a collection. For unknown verbs (HEAD, OPTIONS…),
  # infer from path: no trailing param means collection → keep last segment plural.
  collection = action == "list" || (!ACTIONS.key?(@method) && !trailing_param)

  # Intermediate segments always singularized; last segment only for item actions.
  named = resources.map.with_index do |seg, i|
    last = i == resources.length - 1
    word = (!last || !collection) ? singularize(seg) : seg
    word.capitalize
  end

  "#{action}#{named.join}"
end