functions_framework 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +1 -1
- data/lib/functions_framework/function.rb +24 -1
- data/lib/functions_framework/registry.rb +23 -0
- data/lib/functions_framework/server.rb +61 -6
- data/lib/functions_framework/testing.rb +49 -15
- data/lib/functions_framework/version.rb +1 -1
- data/lib/functions_framework.rb +33 -3
- metadata +15 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 57eed57ea92eee1e51f3285c883f0f757a87f8379b7316fe5cd1eed46e1782fc
|
4
|
+
data.tar.gz: c039b2139d3692727dffcbe715b390460445d4c8b5728e2c4fbe2c59db3030c8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d1369b3334e1605956829e6077fe7d76f5f49155985598d2098928cc6a54d4f58b1252f8e6971cfd3784e104ca15162ec1e37fc0e80f2d0eadf60ad5698d7657
|
7
|
+
data.tar.gz: 9fa3b2e12ff0ad195ad0dd808c147ad30adf9eeb8ac25a2990ebddb11ef8945f80b8091455415cb0462fbc334e3eacc77afeb55175a01a713bbc2f808a3018b8
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
### 1.4.0 (2023-06-16)
|
4
|
+
|
5
|
+
#### Features
|
6
|
+
|
7
|
+
* implement typed function signature ([#158](https://github.com/GoogleCloudPlatform/functions-framework-ruby/issues/158))
|
8
|
+
|
9
|
+
### 1.3.0 (2023-04-05)
|
10
|
+
|
11
|
+
#### Features
|
12
|
+
|
13
|
+
* Support for Puma 6 and Rack 3
|
14
|
+
|
3
15
|
### 1.2.0 (2022-08-25)
|
4
16
|
|
5
17
|
* Update minimum Ruby version to 2.6
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Functions Framework for Ruby [](https://googlecloudplatform.github.io/functions-framework-ruby/latest) [](https://badge.fury.io/rb/functions_framework)
|
1
|
+
# Functions Framework for Ruby [](https://googlecloudplatform.github.io/functions-framework-ruby/latest) [](https://badge.fury.io/rb/functions_framework) 
|
2
2
|
|
3
3
|
An open source framework for writing lightweight, portable Ruby functions that
|
4
4
|
run in a serverless environment. Functions written to this Framework will run
|
@@ -70,6 +70,23 @@ module FunctionsFramework
|
|
70
70
|
new name, :http, callable: callable, &block
|
71
71
|
end
|
72
72
|
|
73
|
+
##
|
74
|
+
# Create a new Typed function definition.
|
75
|
+
#
|
76
|
+
# @param name [String] The function name
|
77
|
+
# @param callable [Class,#call] A callable object or class.
|
78
|
+
# @param request_class [#decode_json] A class that can be read from JSON.
|
79
|
+
# @param block [Proc] The function code as a block.
|
80
|
+
# @return [FunctionsFramework::Function]
|
81
|
+
#
|
82
|
+
def self.typed name, request_class: nil, callable: nil, &block
|
83
|
+
if request_class && !(request_class.respond_to? :decode_json)
|
84
|
+
raise ::ArgumentError, "Type does not implement 'decode_json' class method"
|
85
|
+
end
|
86
|
+
|
87
|
+
new name, :typed, callable: callable, request_class: request_class, &block
|
88
|
+
end
|
89
|
+
|
73
90
|
##
|
74
91
|
# Create a new CloudEvents function definition.
|
75
92
|
#
|
@@ -102,9 +119,10 @@ module FunctionsFramework
|
|
102
119
|
# @param callable [Class,#call] A callable object or class.
|
103
120
|
# @param block [Proc] The function code as a block.
|
104
121
|
#
|
105
|
-
def initialize name, type, callable: nil, &block
|
122
|
+
def initialize name, type, callable: nil, request_class: nil, &block
|
106
123
|
@name = name
|
107
124
|
@type = type
|
125
|
+
@request_class = request_class
|
108
126
|
@callable = @callable_class = nil
|
109
127
|
if callable.respond_to? :call
|
110
128
|
@callable = callable
|
@@ -129,6 +147,11 @@ module FunctionsFramework
|
|
129
147
|
#
|
130
148
|
attr_reader :type
|
131
149
|
|
150
|
+
##
|
151
|
+
# @return [#decode_json] The class for the request parameter. Only used for typed functions.
|
152
|
+
#
|
153
|
+
attr_reader :request_class
|
154
|
+
|
132
155
|
##
|
133
156
|
# Populate the given globals hash with this function's info.
|
134
157
|
#
|
@@ -81,6 +81,29 @@ module FunctionsFramework
|
|
81
81
|
self
|
82
82
|
end
|
83
83
|
|
84
|
+
##
|
85
|
+
# Add a Typed function to the registry.
|
86
|
+
#
|
87
|
+
# You must provide a name for the function, and a block that implements the
|
88
|
+
# function. The block should take a single `Hash` argument which will be the
|
89
|
+
# JSON decoded request payload. It should return a `Hash` response which
|
90
|
+
# will be JSON encoded and written to the response.
|
91
|
+
#
|
92
|
+
# @param name [String] The function name.
|
93
|
+
# @param request_class [#decode_json] An optional class which will be used
|
94
|
+
# to decode the request.
|
95
|
+
# @param block [Proc] The function code as a proc
|
96
|
+
# @return [self]
|
97
|
+
#
|
98
|
+
def add_typed name, request_class: nil, &block
|
99
|
+
name = name.to_s
|
100
|
+
@mutex.synchronize do
|
101
|
+
raise ::ArgumentError, "Function already defined: #{name}" if @functions.key? name
|
102
|
+
@functions[name] = Function.typed name, request_class: request_class, &block
|
103
|
+
end
|
104
|
+
self
|
105
|
+
end
|
106
|
+
|
84
107
|
##
|
85
108
|
# Add a CloudEvent function to the registry.
|
86
109
|
#
|
@@ -54,6 +54,8 @@ module FunctionsFramework
|
|
54
54
|
HttpApp.new function, globals, @config
|
55
55
|
when :cloud_event
|
56
56
|
EventApp.new function, globals, @config
|
57
|
+
when :typed
|
58
|
+
TypedApp.new function, globals, @config
|
57
59
|
else
|
58
60
|
raise "Unrecognized function type: #{function.type}"
|
59
61
|
end
|
@@ -82,10 +84,21 @@ module FunctionsFramework
|
|
82
84
|
def start
|
83
85
|
synchronize do
|
84
86
|
unless running?
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
87
|
+
# Puma >= 6.0 interprets these settings from options
|
88
|
+
options = {
|
89
|
+
min_threads: @config.min_threads,
|
90
|
+
max_threads: @config.max_threads,
|
91
|
+
environment: @config.show_error_details? ? "development" : "production"
|
92
|
+
}
|
93
|
+
# Puma::Events.stdio for Puma < 6.0; otherwise nil for Puma >= 6.0
|
94
|
+
events = ::Puma::Events.stdio if ::Puma::Events.respond_to? :stdio
|
95
|
+
@server = ::Puma::Server.new @app, events, options
|
96
|
+
if @server.respond_to? :min_threads=
|
97
|
+
# Puma < 6.0 sets server attributes for these settings
|
98
|
+
@server.min_threads = @config.min_threads
|
99
|
+
@server.max_threads = @config.max_threads
|
100
|
+
@server.leak_stack_on_error = @config.show_error_details?
|
101
|
+
end
|
89
102
|
@server.binder.add_tcp_listener @config.bind_addr, @config.port
|
90
103
|
@config.logger.info "FunctionsFramework: Serving function #{@function.name.inspect} " \
|
91
104
|
"on port #{@config.port}..."
|
@@ -377,8 +390,8 @@ module FunctionsFramework
|
|
377
390
|
content_type = "#{content_type}; charset=#{string.encoding.name.downcase}"
|
378
391
|
end
|
379
392
|
headers = {
|
380
|
-
"
|
381
|
-
"
|
393
|
+
"content-type" => content_type,
|
394
|
+
"content-length" => string.bytesize
|
382
395
|
}
|
383
396
|
[status, headers, [string]]
|
384
397
|
end
|
@@ -394,6 +407,11 @@ module FunctionsFramework
|
|
394
407
|
string_response message, 500
|
395
408
|
end
|
396
409
|
|
410
|
+
def bad_request message
|
411
|
+
message = "Bad Request" unless @config.show_error_details?
|
412
|
+
string_response message, 400
|
413
|
+
end
|
414
|
+
|
397
415
|
def flush_streams
|
398
416
|
$stdout.flush
|
399
417
|
$stderr.flush
|
@@ -425,6 +443,43 @@ module FunctionsFramework
|
|
425
443
|
end
|
426
444
|
end
|
427
445
|
|
446
|
+
## @private
|
447
|
+
class TypedApp < AppBase
|
448
|
+
def initialize function, globals, config
|
449
|
+
super config
|
450
|
+
@function = function
|
451
|
+
@globals = globals
|
452
|
+
end
|
453
|
+
|
454
|
+
def call env
|
455
|
+
return notfound_response if excluded_path? env
|
456
|
+
begin
|
457
|
+
logger = env[::Rack::RACK_LOGGER] ||= @config.logger
|
458
|
+
request = ::Rack::Request.new env
|
459
|
+
logger.info "FunctionsFramework: Handling Typed #{request.request_method} request"
|
460
|
+
|
461
|
+
begin
|
462
|
+
req = if @function.request_class
|
463
|
+
request_class.decode_json request.body.read.to_s
|
464
|
+
else
|
465
|
+
JSON.parse request.body.read.to_s
|
466
|
+
end
|
467
|
+
rescue JSON::ParserError => e
|
468
|
+
return bad_request e.message
|
469
|
+
end
|
470
|
+
|
471
|
+
res = @function.call req, globals: @globals, logger: logger
|
472
|
+
return string_response res.to_json, 200, content_type: "application/json" if res
|
473
|
+
|
474
|
+
string_response "", 204
|
475
|
+
rescue ::StandardError => e
|
476
|
+
interpret_response e
|
477
|
+
end
|
478
|
+
ensure
|
479
|
+
flush_streams
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
428
483
|
## @private
|
429
484
|
class EventApp < AppBase
|
430
485
|
def initialize function, globals, config
|
@@ -134,16 +134,42 @@ module FunctionsFramework
|
|
134
134
|
#
|
135
135
|
def call_http name, request, globals: nil, logger: nil
|
136
136
|
globals ||= run_startup_tasks name, logger: logger, lenient: true
|
137
|
-
|
138
|
-
case function&.type
|
139
|
-
when :http
|
137
|
+
Testing.call :http, name, readable_name: "HTTP" do |function|
|
140
138
|
Testing.interpret_response do
|
141
139
|
function.call request, globals: globals, logger: logger
|
142
140
|
end
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
##
|
145
|
+
# Call the given Typed function for testing. The underlying function must
|
146
|
+
# be of type `:typed`. Returns the Rack response.
|
147
|
+
#
|
148
|
+
# By default, the startup tasks will be run for the given function if they
|
149
|
+
# have not already been run. You can, however, disable running startup
|
150
|
+
# tasks by providing an explicit globals hash.
|
151
|
+
#
|
152
|
+
# By default, the {FunctionsFramework.logger} will be used, but you can
|
153
|
+
# override that by providing your own logger. In particular, to disable
|
154
|
+
# logging, you can pass `Logger.new(nil)`.
|
155
|
+
#
|
156
|
+
# @param name [String] The name of the function to call
|
157
|
+
# @param request [Rack::Request] The Rack request to send
|
158
|
+
# @param globals [Hash] Do not run startup tasks, and instead provide the
|
159
|
+
# globals directly. Optional.
|
160
|
+
# @param logger [Logger] Use the given logger instead of the Functions
|
161
|
+
# Framework's global logger. Optional.
|
162
|
+
# @return [Rack::Response]
|
163
|
+
#
|
164
|
+
def call_typed name, request, globals: nil, logger: nil
|
165
|
+
globals ||= run_startup_tasks name, logger: logger, lenient: true
|
166
|
+
Testing.call :typed, name, readable_name: "Typed" do |function|
|
167
|
+
Testing.interpret_response do
|
168
|
+
config = FunctionsFramework::Server::Config.new
|
169
|
+
config.logger = logger
|
170
|
+
app = FunctionsFramework::Server::TypedApp.new function, globals, config
|
171
|
+
app.call request.env
|
172
|
+
end
|
147
173
|
end
|
148
174
|
end
|
149
175
|
|
@@ -169,15 +195,9 @@ module FunctionsFramework
|
|
169
195
|
#
|
170
196
|
def call_event name, event, globals: nil, logger: nil
|
171
197
|
globals ||= run_startup_tasks name, logger: logger, lenient: true
|
172
|
-
|
173
|
-
case function&.type
|
174
|
-
when :cloud_event
|
198
|
+
Testing.call :cloud_event, name, readable_name: "CloudEvent" do |function|
|
175
199
|
function.call event, globals: globals, logger: logger
|
176
200
|
nil
|
177
|
-
when nil
|
178
|
-
raise "Unknown function name #{name}"
|
179
|
-
else
|
180
|
-
raise "Function #{name} is not a CloudEvent function"
|
181
201
|
end
|
182
202
|
end
|
183
203
|
|
@@ -316,6 +336,20 @@ module FunctionsFramework
|
|
316
336
|
end
|
317
337
|
end
|
318
338
|
|
339
|
+
## @private
|
340
|
+
def call type, name, readable_name: nil
|
341
|
+
readable_name ||= type
|
342
|
+
function = Testing.current_registry[name]
|
343
|
+
case function&.type
|
344
|
+
when type
|
345
|
+
yield function
|
346
|
+
when nil
|
347
|
+
raise "Unknown function name #{name}"
|
348
|
+
else
|
349
|
+
raise "Function #{name} is not a #{readable_name} function"
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
319
353
|
## @private
|
320
354
|
def interpret_response
|
321
355
|
response =
|
@@ -367,8 +401,8 @@ module FunctionsFramework
|
|
367
401
|
::Rack::QUERY_STRING => url.query,
|
368
402
|
::Rack::SERVER_NAME => url.host,
|
369
403
|
::Rack::SERVER_PORT => url.port,
|
404
|
+
::Rack::SERVER_PROTOCOL => "HTTP/1.1",
|
370
405
|
::Rack::RACK_URL_SCHEME => url.scheme,
|
371
|
-
::Rack::RACK_VERSION => ::Rack::VERSION,
|
372
406
|
::Rack::RACK_LOGGER => ::FunctionsFramework.logger,
|
373
407
|
::Rack::RACK_INPUT => ::StringIO.new,
|
374
408
|
::Rack::RACK_ERRORS => ::StringIO.new
|
data/lib/functions_framework.rb
CHANGED
@@ -115,9 +115,9 @@ module FunctionsFramework
|
|
115
115
|
attr_accessor :logger
|
116
116
|
|
117
117
|
##
|
118
|
-
# Define a function that
|
118
|
+
# Define a function that responds to HTTP requests.
|
119
119
|
#
|
120
|
-
# You must provide a name for the function, and a block that
|
120
|
+
# You must provide a name for the function, and a block that implements the
|
121
121
|
# function. The block should take a single `Rack::Request` argument. It
|
122
122
|
# should return one of the following:
|
123
123
|
# * A standard 3-element Rack response array. See
|
@@ -142,10 +142,40 @@ module FunctionsFramework
|
|
142
142
|
self
|
143
143
|
end
|
144
144
|
|
145
|
+
## Define a Typed function that responds to HTTP requests.
|
146
|
+
#
|
147
|
+
# You must provide a name for the function, and a block that implements the
|
148
|
+
# function. The block should take a single argument representing the request
|
149
|
+
# payload. If a `request_type` is provided, the argument object will be of
|
150
|
+
# the given decoded type; otherwise, it will be a JSON hash. The block
|
151
|
+
# should return a JSON hash or an object that implements `#to_json`.
|
152
|
+
#
|
153
|
+
# ## Example
|
154
|
+
# FunctionsFramework.typed "my-sum-function" do |add_request|
|
155
|
+
# {sum: add_request["num1"] + add_response["num2"]}
|
156
|
+
# end
|
157
|
+
#
|
158
|
+
# ## Example with Type
|
159
|
+
# FunctionsFramework.typed "identity",
|
160
|
+
# request_class: MyCustomType do |custom_type|
|
161
|
+
# custom_type
|
162
|
+
# end
|
163
|
+
#
|
164
|
+
# @param name [String] The function name. Defaults to {DEFAULT_TARGET}
|
165
|
+
# @param request_class [#decode_json] An optional class which will be used to
|
166
|
+
# decode the request if it implements a `decode_json` static method.
|
167
|
+
# @param block [Proc] The function code as a proc @return [self]
|
168
|
+
# @return [self]
|
169
|
+
#
|
170
|
+
def typed name = DEFAULT_TARGET, request_class: nil, &block
|
171
|
+
global_registry.add_typed name, request_class: request_class, &block
|
172
|
+
self
|
173
|
+
end
|
174
|
+
|
145
175
|
##
|
146
176
|
# Define a function that responds to CloudEvents.
|
147
177
|
#
|
148
|
-
# You must provide a name for the function, and a block that
|
178
|
+
# You must provide a name for the function, and a block that implements the
|
149
179
|
# function. The block should take one argument: the event object of type
|
150
180
|
# [`CloudEvents::Event`](https://cloudevents.github.io/sdk-ruby/latest/CloudEvents/Event).
|
151
181
|
# Any return value is ignored.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: functions_framework
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Azuma
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-06-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cloud_events
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
version: 4.3.0
|
40
40
|
- - "<"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version:
|
42
|
+
version: 7.a
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -49,21 +49,27 @@ dependencies:
|
|
49
49
|
version: 4.3.0
|
50
50
|
- - "<"
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version:
|
52
|
+
version: 7.a
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: rack
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
56
56
|
requirements:
|
57
|
-
- - "
|
57
|
+
- - ">="
|
58
58
|
- !ruby/object:Gem::Version
|
59
59
|
version: '2.1'
|
60
|
+
- - "<"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 4.a
|
60
63
|
type: :runtime
|
61
64
|
prerelease: false
|
62
65
|
version_requirements: !ruby/object:Gem::Requirement
|
63
66
|
requirements:
|
64
|
-
- - "
|
67
|
+
- - ">="
|
65
68
|
- !ruby/object:Gem::Version
|
66
69
|
version: '2.1'
|
70
|
+
- - "<"
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 4.a
|
67
73
|
description: The Functions Framework is an open source framework for writing lightweight,
|
68
74
|
portable Ruby functions that run in a serverless environment. Functions written
|
69
75
|
to this Framework will run on Google Cloud Functions, Google Cloud Run, or any other
|
@@ -100,10 +106,10 @@ homepage: https://github.com/GoogleCloudPlatform/functions-framework-ruby
|
|
100
106
|
licenses:
|
101
107
|
- Apache-2.0
|
102
108
|
metadata:
|
103
|
-
changelog_uri: https://googlecloudplatform.github.io/functions-framework-ruby/v1.
|
109
|
+
changelog_uri: https://googlecloudplatform.github.io/functions-framework-ruby/v1.4.0/file.CHANGELOG.html
|
104
110
|
source_code_uri: https://github.com/GoogleCloudPlatform/functions-framework-ruby
|
105
111
|
bug_tracker_uri: https://github.com/GoogleCloudPlatform/functions-framework-ruby/issues
|
106
|
-
documentation_uri: https://googlecloudplatform.github.io/functions-framework-ruby/v1.
|
112
|
+
documentation_uri: https://googlecloudplatform.github.io/functions-framework-ruby/v1.4.0
|
107
113
|
post_install_message:
|
108
114
|
rdoc_options: []
|
109
115
|
require_paths:
|
@@ -119,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
125
|
- !ruby/object:Gem::Version
|
120
126
|
version: '0'
|
121
127
|
requirements: []
|
122
|
-
rubygems_version: 3.
|
128
|
+
rubygems_version: 3.4.2
|
123
129
|
signing_key:
|
124
130
|
specification_version: 4
|
125
131
|
summary: Functions Framework for Ruby
|