Class: Jets::Router::Route

Inherits:
Object
  • Object
show all
Extended by:
Memoist
Includes:
AfterInitialize, As, Authorizer, Compat, Path, Util
Defined in:
lib/jets/router/route.rb,
lib/jets/router/route/as.rb,
lib/jets/router/route/info.rb,
lib/jets/router/route/node.rb,
lib/jets/router/route/path.rb,
lib/jets/router/route/compat.rb,
lib/jets/router/route/authorizer.rb,
lib/jets/router/route/after_initialize.rb

Defined Under Namespace

Modules: AfterInitialize, As, Authorizer, Compat, Path Classes: Info, Node

Constant Summary collapse

CAPTURE_REGEX =

as string

"([^/]*)"

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Util

#underscore

Methods included from Path

#add_path_suffix, #format_path, #path, #path_option, #path_prefixes, #path_suffixes

Methods included from Authorizer

#api_key_required, #authorization_scopes, #authorization_type, #authorizer, #authorizer_id, #authorizer_metadata

Methods included from Authorizer::ModuleMethods

#logical_id, #metadata

Methods included from As

#add_action, #add_root, #add_underscore_path, #as, #scoped_as, #underscore_path_before_param

Methods included from AfterInitialize

#after_initialize, #check_on_option!, #escape_path, #normalize_id_constraint!, #normalize_path_option!, #normalize_to_option!

Methods included from Compat

#app, #internal, #name, #verb

Constructor Details

#initialize(options, scope = Scope.new) ⇒ Route

Returns a new instance of Route.



20
21
22
23
24
25
26
# File 'lib/jets/router/route.rb', line 20

def initialize(options, scope=Scope.new)
  @options = options
  @scope = scope
  @info = Info.new(@options, @scope) # @info.action and @info.controller
  after_initialize
  @path_names = {}
end

Instance Attribute Details

#defaultsObject (readonly)

Returns the value of attribute defaults.



18
19
20
# File 'lib/jets/router/route.rb', line 18

def defaults
  @defaults
end

#infoObject (readonly)

Returns the value of attribute info.



18
19
20
# File 'lib/jets/router/route.rb', line 18

def info
  @info
end

#optionsObject (readonly)

Returns the value of attribute options.



18
19
20
# File 'lib/jets/router/route.rb', line 18

def options
  @options
end

#original_engineObject

Returns the value of attribute original_engine.



19
20
21
# File 'lib/jets/router/route.rb', line 19

def original_engine
  @original_engine
end

#scopeObject (readonly)

Returns the value of attribute scope.



18
19
20
# File 'lib/jets/router/route.rb', line 18

def scope
  @scope
end

Instance Method Details

#as_json(options = nil) ⇒ Object

Prevents infinite loop when calling route.to_json for state.save(“routes”, …)



175
176
177
178
179
180
181
182
183
184
# File 'lib/jets/router/route.rb', line 175

def as_json(options= nil)
  data = {
    path: path,
    http_method: http_method,
    to: to,
  }
  data[:engine] = engine if engine
  data[:internal] = internal if internal
  data
end

#constraintsObject



54
55
56
# File 'lib/jets/router/route.rb', line 54

def constraints
  @options[:constraints] || @scope.resolved_constraints
end

#controller_nameObject

IE: PostsController Different from @info.action



73
74
75
# File 'lib/jets/router/route.rb', line 73

def controller_name
  "#{controller.camelize}Controller" if controller
end

#endpointObject



41
42
43
# File 'lib/jets/router/route.rb', line 41

def endpoint
  engine.to_s if engine
end

#engineObject Also known as: rack_app



32
33
34
# File 'lib/jets/router/route.rb', line 32

def engine
  @options[:engine]
end

#engine?Boolean

Returns:

  • (Boolean)


37
38
39
# File 'lib/jets/router/route.rb', line 37

def engine?
  !!engine
end

#extract_parameters(request_path) ⇒ Object

Extracts the path parameters from the actual path Only supports extracting 1 parameter. So:

request_path: posts/tung/edit
route.path: posts/:id/edit

Returns:

{ id: "tung" }


108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/jets/router/route.rb', line 108

def extract_parameters(request_path)
  request_path = "/#{request_path}" unless request_path.starts_with?('/') # be more forgiving if / accidentally not included
  request_path = remove_engine_mount_at_path(request_path)
  if path.include?(':')
    extract_parameters_capture(request_path)
  elsif path.include?('*')
    extract_parameters_proxy(request_path)
  else
    # Lambda AWS_PROXY sets null to the input request when there are no path parmeters
    nil
  end
end

#extract_parameters_capture(request_path) ⇒ Object



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/jets/router/route.rb', line 152

def extract_parameters_capture(request_path)
  # changes path to a string used for a regexp
  # posts/:id/edit => posts\/(.*)\/edit
  labels = []
  regexp_string = path.split('/').map do |s|
                    if s.start_with?(':')
                      labels << s.delete_prefix(':')
                      CAPTURE_REGEX
                    else
                      s
                    end
                  end.join('\/')
  # make sure beginning and end of the string matches
  regexp_string = "^#{regexp_string}$"
  regexp = Regexp.new(regexp_string)

  values = regexp.match(request_path).captures
  labels.map do |next_label|
    [next_label, values.delete_at(0)]
  end.to_h
end

#extract_parameters_proxy(request_path) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/jets/router/route.rb', line 130

def extract_parameters_proxy(request_path)
  # changes path to a string used for a regexp
  # others/*proxy => others\/(.*)
  # nested/others/*proxy => nested/others\/(.*)
  if path.include?('/')
    leading_path = path.split('/')[0..-2].join('/') # drop last segment
    # leading_path: nested/others
    # capture everything after the leading_path as the value
    regexp = Regexp.new("#{leading_path}/(.*)")
    value = request_path.match(regexp)[1]
  else
    value = request_path
  end

  # the last segment without the '*' is the key
  proxy_segment = path.split('/').last # last segment is the proxy segment
  # proxy_segment: *proxy
  key = proxy_segment.sub('*','')

  { key => value }
end

#homepage?Boolean

Returns:

  • (Boolean)


62
63
64
# File 'lib/jets/router/route.rb', line 62

def homepage?
  path == '/'
end

#http_methodObject



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

def http_method
  @options[:http_method].to_s.upcase
end

#internal?Boolean

Returns:

  • (Boolean)


58
59
60
# File 'lib/jets/router/route.rb', line 58

def internal?
  !!@options[:internal]
end

#mount_classObject

Old notes: For Grape apps, calling ActiveSupport to_json on a Grape class used to cause an infinite loop. Believe Grape fixed this issue. A GrapeApp.to_json now produces a string. No longer need to coerce to a string and back to a class.

This is important because Sprocket::Environment.new cannot be coerced into a string or mounting wont work. This is used in sprockets-jets/lib/sprockets/jets/engine.rb

Related PR: smarter apigw routes paging calculation #635 github.com/boltops-tools/jets/pull/635 Debugging notes: gist.github.com/tongueroo/c9baa7e98d5ad68bbdd770fde4651963



203
204
205
# File 'lib/jets/router/route.rb', line 203

def mount_class
  @options[:mount_class]
end

#mount_class_nameObject

For jets routes help table of routes



208
209
210
211
# File 'lib/jets/router/route.rb', line 208

def mount_class_name
  return unless mount_class
  mount_class.class == Class ? mount_class : "#{mount_class.class}.new"
end

#rebuild_path_parameters(event) ⇒ Object

For Jets.config.cfn.build.routes == “one_apigw_method_for_all_routes” Need to build the pathParameters for the API Gateway event.



90
91
92
93
94
95
96
97
98
# File 'lib/jets/router/route.rb', line 90

def rebuild_path_parameters(event)
  extracted = extract_parameters(event["path"])
  if extracted
    params = event["pathParameters"] || {}
    params.merge(extracted)
  else
    event["pathParameters"] # pass through
  end
end

#remove_engine_mount_at_path(request_path) ⇒ Object



121
122
123
124
125
126
127
128
# File 'lib/jets/router/route.rb', line 121

def remove_engine_mount_at_path(request_path)
  return request_path unless original_engine

  mount = Jets::Router::EngineMount.find_by(engine: original_engine)
  return request_path unless mount

  request_path.sub(mount.at, '')
end

#resolved_defaultsObject



45
46
47
48
# File 'lib/jets/router/route.rb', line 45

def resolved_defaults
  defaults = @options[:defaults] || {}
  @scope.resolved_defaults.merge(defaults)
end

#toObject



28
29
30
# File 'lib/jets/router/route.rb', line 28

def to
  engine || "#{@info.controller}##{@info.action}" # IE: posts#index
end

#to_sObject

To keep “self #self” more concise and helpful Use “self #Jets::Router::Route.selfself.inspect” more verbose info



188
189
190
# File 'lib/jets/router/route.rb', line 188

def to_s
  "#<Jets::Router::Route:#{object_id} @options=#{@options}>"
end

#valid?Boolean

Checks to see if the corresponding controller exists. Useful to validate routes before deploying to CloudFormation and then rolling back.

Returns:

  • (Boolean)


79
80
81
82
83
84
85
86
# File 'lib/jets/router/route.rb', line 79

def valid?
  controller_class = begin
    controller_name.constantize
  rescue NameError => e
    return false
  end
  controller_class.lambda_functions.include?(action_name.to_sym)
end