functions_framework 0.1.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,142 @@
1
+ <!--
2
+ # @title Functions Framework Overview
3
+ -->
4
+
5
+ # Functions Framework for Ruby
6
+
7
+ The Functions Framework is an open source framework for writing lightweight,
8
+ portable Ruby functions that run in a serverless environment. Functions written
9
+ to this Framework will run in many different environments, including:
10
+
11
+ * [Google Cloud Functions](https://cloud.google.com/functions) *(in preview)*
12
+ * [Cloud Run or Cloud Run for Anthos](https://cloud.google.com/run)
13
+ * Any other [Knative](https://github.com/knative)-based environment
14
+ * Your local development machine
15
+
16
+ The framework allows you to go from:
17
+
18
+ ```ruby
19
+ FunctionsFramework.http("hello") do |request|
20
+ "Hello, world!\n"
21
+ end
22
+ ```
23
+
24
+ To:
25
+
26
+ ```sh
27
+ curl http://my-url
28
+ # Output: Hello, world!
29
+ ```
30
+
31
+ Running on a fully-managed or self-managed serverless environment, without
32
+ requiring an HTTP server or complicated request handling logic.
33
+
34
+ ## Features
35
+
36
+ * Define named functions using normal Ruby constructs.
37
+ * Invoke functions in response to requests.
38
+ * Automatically unmarshal events conforming to the
39
+ [CloudEvents](https://cloudevents.io) spec.
40
+ * Automatically convert most legacy events from Google Cloud services such
41
+ as Cloud Pub/Sub and Cloud Storage, to CloudEvents.
42
+ * Spin up a local development server for quick testing.
43
+ * Integrate with standard Ruby libraries such as Rack and Minitest.
44
+ * Portable between serverless platforms.
45
+ * Supports all non-end-of-life versions of Ruby.
46
+
47
+ ## Supported Ruby versions
48
+
49
+ This library is supported on Ruby 2.4+.
50
+
51
+ Google provides official support for Ruby versions that are actively supported
52
+ by Ruby Core—that is, Ruby versions that are either in normal maintenance or
53
+ in security maintenance, and not end of life. Currently, this means Ruby 2.4
54
+ and later. Older versions of Ruby _may_ still work, but are unsupported and not
55
+ recommended. See https://www.ruby-lang.org/en/downloads/branches/ for details
56
+ about the Ruby support schedule.
57
+
58
+ ## Quickstart
59
+
60
+ Here is how to run a Hello World function on your local machine.
61
+
62
+ Create a `Gemfile` listing the Functions Framework as a dependency:
63
+
64
+ ```ruby
65
+ # Gemfile
66
+ source "https://rubygems.org"
67
+ gem "functions_framework", "~> 0.4"
68
+ ```
69
+
70
+ Create a file called `app.rb` and include the following code. This defines a
71
+ simple function called "hello".
72
+
73
+ ```ruby
74
+ # app.rb
75
+ require "functions_framework"
76
+
77
+ FunctionsFramework.http("hello") do |request|
78
+ "Hello, world!\n"
79
+ end
80
+ ```
81
+
82
+ Install the bundle, and start the framework. This spins up a local web server
83
+ running your "hello" function:
84
+
85
+ ```sh
86
+ bundle install
87
+ # ...installs the functions_framework gem and other dependencies
88
+ bundle exec functions-framework-ruby --target hello
89
+ # ...starts the functions server in the foreground
90
+ ```
91
+
92
+ In a separate shell, you can send requests to this function using curl:
93
+
94
+ ```sh
95
+ curl http://localhost:8080
96
+ # Output: Hello, world!
97
+ ```
98
+
99
+ Stop the server with `CTRL+C`.
100
+
101
+ ## Documentation
102
+
103
+ These guides provide additional getting-started information.
104
+
105
+ * **{file:docs/writing-functions.md Writing Functions}** :
106
+ How to write functions that respond to HTTP requests, industry-standard
107
+ [CloudEvents](https://cloudevents.io), as well as events sent from Google
108
+ Cloud services such as [Pub/Sub](https://cloud.google.com/pubsub) and
109
+ [Storage](https://cloud.google.com/storage).
110
+ * **{file:docs/testing-functions.md Testing Functions}** :
111
+ How to use the testing features of the Functions Framework to write local
112
+ unit tests for your functions using standard Ruby testing frameworks such
113
+ as [Minitest](https://github.com/seattlerb/minitest) and
114
+ [RSpec](https://rspec.info/).
115
+ * **{file:docs/running-a-functions-server.md Running a Functions Server}** :
116
+ How to use the `functions-framework-ruby` executable to run a local
117
+ functions server.
118
+ * **{file:docs/deploying-functions.md Deploying Functions}** :
119
+ How to deploy functions to
120
+ [Google Cloud Functions](https://cloud.google.com/functions) or
121
+ [Google Cloud Run](https://cloud.google.com/run).
122
+
123
+ The library reference documentation can be found at:
124
+ https://rubydoc.info/gems/functions_framework
125
+
126
+ Additional examples are available in the GitHub repository:
127
+ https://github.com/GoogleCloudPlatform/functions-framework-ruby/blob/master/examples/
128
+
129
+ ## Development
130
+
131
+ The source for the Ruby Functions Framework is available on GitHub at
132
+ https://github.com/GoogleCloudPlatform/functions-framework-ruby. For more
133
+ information on the Functions Framework contract implemented by this framework,
134
+ as well as links to Functions Frameworks for other languages, see
135
+ https://github.com/GoogleCloudPlatform/functions-framework.
136
+
137
+ The Functions Framework is open source under the Apache 2.0 license.
138
+ Contributions are welcome. Please see the contributing guide at
139
+ https://github.com/GoogleCloudPlatform/functions-framework-ruby/blob/master/.github/CONTRIBUTING.md.
140
+
141
+ Report issues at
142
+ https://github.com/GoogleCloudPlatform/functions-framework-ruby/issues.
@@ -0,0 +1,122 @@
1
+ <!--
2
+ # @title Running a Functions Server
3
+ -->
4
+
5
+ # Running a Functions Server
6
+
7
+ This guide covers how to use the `functions-framework-ruby` executable to launch
8
+ a functions server hosting Ruby functions written for the Functions Framework.
9
+ For more information about the Framework as a whole, see the
10
+ {file:docs/overview.md Overview Guide}.
11
+
12
+ ## Running functions locally
13
+
14
+ The `functions-framework-ruby` command-line executable is used to run a
15
+ functions server. This executable is installed with the `functions_framework`
16
+ gem, and can be run with `bundle exec`. It wraps your function in a web server
17
+ request handler, and runs it in the [Puma](https://puma.io/) web server.
18
+
19
+ Pass the name of the function to run in the `--target` option. By default,
20
+ `functions-framework-ruby` will load functions from the file `app.rb` in the
21
+ current directory. If you want to load functions from a different file, use the
22
+ `--source` option.
23
+
24
+ ```sh
25
+ bundle install
26
+ bundle exec functions-framework-ruby --source=foo.rb --target=hello
27
+ ```
28
+
29
+ You can now send requests to your function. e.g.
30
+
31
+ ```sh
32
+ curl http://localhost:8080/
33
+ ```
34
+
35
+ The executable will write logs to the standard error stream while it is running.
36
+ To stop the server, hit `CTRL+C` or otherwise send it an appropriate signal.
37
+ The executable has no "background" or "daemon" mode. To run it in the background
38
+ from a shell, use the shell's background syntax (such as appending `&` to the
39
+ command).
40
+
41
+ By default, the executable will listen on the port specified by the `$PORT`
42
+ environment variable, or port 8080 if the variable is not set. You can also
43
+ override this by passing the `--port` option. A number of other options are
44
+ also available. See the section below on configuring the server, or pass
45
+ `--help` to the executable to display online help.
46
+
47
+ ## Running functions in Docker
48
+
49
+ The `functions-framework-ruby` executable is designed to be run in a Docker
50
+ container. This is how it is run in some container-based hosting services such
51
+ as Google Cloud Run, but you can also run it in Docker locally.
52
+
53
+ First, write a Dockerfile for your project. Following is a simple starting
54
+ point; feel free to adjust it to the needs of your project:
55
+
56
+ ```
57
+ FROM ruby:2.6
58
+ WORKDIR /app
59
+ COPY . .
60
+ RUN gem install --no-document bundler \
61
+ && bundle config --local frozen true \
62
+ && bundle config --local without "development test" \
63
+ && bundle install
64
+ ENV PORT=8080
65
+ ENTRYPOINT ["bundle", "exec", "functions-framework-ruby"]
66
+ ```
67
+
68
+ Build an image for your project using the Dockerfile.
69
+
70
+ ```sh
71
+ docker build --tag my-image .
72
+ ```
73
+
74
+ Then, you can run the Docker container locally as follows:
75
+
76
+ ```sh
77
+ docker run --rm -it -p 8080:8080 my-image --source=foo.rb --target=hello
78
+ ```
79
+
80
+ The arguments after the image name (e.g. `--source` and `--target` in the above
81
+ example) are passed to the `functions-framework-ruby` executable.
82
+
83
+ Because the docker container above maps port 8080 internally to port 8080
84
+ externally, you can use that port to send requests to your function. e.g.
85
+
86
+ ```sh
87
+ curl http://localhost:8080/
88
+ ```
89
+
90
+ You can stop the running Docker container with `CTRL+C` or by sending an
91
+ appropriate signal.
92
+
93
+ ## Configuring the server
94
+
95
+ The Ruby Functions Framework recognizes the following command line arguments to
96
+ the `functions-framework-ruby` executable. Each argument also corresponds to an
97
+ environment variable. If you specify both, the flag takes precedence.
98
+
99
+ Command-line flag | Environment variable | Description
100
+ ----------------- | -------------------- | -----------
101
+ `--port` | `PORT` | The port on which the Functions Framework listens for requests. Default: `8080`.
102
+ `--target` | `FUNCTION_TARGET` | The name of the exported function to be invoked in response to requests. Default: `function`.
103
+ `--source` | `FUNCTION_SOURCE` | The path to the file containing your function. Default: `app.rb` (in the current working directory).
104
+ `--signature-type` | `FUNCTION_SIGNATURE_TYPE` | Verifies that the function has the expected signature. Allowed values: `http`, `event`, or `cloudevent`.
105
+ `--environment` | `RACK_ENV` | Sets the Rack environment.
106
+ `--bind` | `FUNCTION_BIND_ADDR` | Binds to the given address. Default: `0.0.0.0`.
107
+ `--min-threads` | `FUNCTION_MIN_THREADS` | Sets the minimum thread pool size, overriding Puma's default.
108
+ `--max-threads` | `FUNCTION_MAX_THREADS` | Sets the maximum thread pool size, overriding Puma's default.
109
+ `--detailed-errors` | `FUNCTION_DETAILED_ERRORS` | No value. If present, shows exception details in exception responses. Defaults to false.
110
+ `--verbose` | `FUNCTION_LOGGING_LEVEL` | No value. Increases log verbosity (e.g. from INFO to DEBUG). Can be given more than once.
111
+ `--quiet` | `FUNCTION_LOGGING_LEVEL` | No value. Decreases log verbosity (e.g. from INFO to WARN). Can be given more than once.
112
+
113
+ Detailed errors are enabled by default if the `FUNCTION_DETAILED_ERRORS`
114
+ environment variable is set to a _non-empty_ string. The exact value does not
115
+ matter. Detailed errors are disabled if the variable is unset or empty.
116
+
117
+ The logging level defaults to the value of the `FUNCTION_LOGGING_LEVEL`
118
+ environment variable, which can be one of the following values: `DEBUG`, `INFO`,
119
+ `WARN`, `ERROR`, `FATAL`, or `UNKNOWN`, corresponding to Ruby's
120
+ [Logger::Severity](https://ruby-doc.org/stdlib/libdoc/logger/rdoc/Logger/Severity.html)
121
+ constants. If `FUNCTION_LOGGING_LEVEL` is not set to one of those values, it
122
+ defaults to `INFO`.
@@ -0,0 +1,169 @@
1
+ <!--
2
+ # @title Testing Functions
3
+ -->
4
+
5
+ # Testing Functions
6
+
7
+ This guide covers writing unit tests for functions using the Functions Framework
8
+ for Ruby. For more information about the Framework, see the
9
+ {file:docs/overview.md Overview Guide}.
10
+
11
+ ## Overview of function testing
12
+
13
+ One of the benefits of the functions-as-a-service paradigm is that functions are
14
+ easy to test. In many cases, you can simply call a function with input, and test
15
+ the output. You do not need to set up (or mock) an actual server.
16
+
17
+ The Functions Framework provides utility methods that streamline the process of
18
+ setting up functions and the environment for testing, constructing input
19
+ parameters, and interpreting results. These are available in the
20
+ [Testing module](https://rubydoc.info/gems/functions_framework/FunctionsFramework/Testing).
21
+ Generally, you can include this module in your Minitest test class or RSpec
22
+ describe block.
23
+
24
+ ```ruby
25
+ require "minitest/autorun"
26
+ require "functions_framework/testing"
27
+
28
+ class MyTest < Minitest::Test
29
+ include FunctionsFramework::Testing
30
+ # define tests...
31
+ end
32
+ ```
33
+
34
+ ```ruby
35
+ require "rspec"
36
+ require "functions_framework/testing"
37
+
38
+ describe "My functions" do
39
+ include FunctionsFramework::Testing
40
+ # define examples...
41
+ end
42
+ ```
43
+
44
+ ## Loading functions for testing
45
+
46
+ To test a function, you'll need to load the Ruby file that defines the function,
47
+ and run the function to test its results. The Testing module provides a method
48
+ [load_temporary](https://rubydoc.info/gems/functions_framework/FunctionsFramework/Testing#load_temporary-instance_method),
49
+ which loads a Ruby file, defining functions but only for the scope of your test.
50
+ This allows your test to coexist with tests for other functions, even functions
51
+ with the same name from a different Ruby file.
52
+
53
+ ```ruby
54
+ require "minitest/autorun"
55
+ require "functions_framework/testing"
56
+
57
+ class MyTest < Minitest::Test
58
+ include FunctionsFramework::Testing
59
+
60
+ def test_a_function
61
+ load_temporary "foo.rb" do
62
+ # Test a function defined in foo.rb
63
+ end
64
+ end
65
+
66
+ def test_another_function
67
+ load_temporary "bar.rb" do
68
+ # Test a function defined in bar.rb
69
+ end
70
+ end
71
+ end
72
+ ```
73
+
74
+ When running a test suite, you'll typically need to load all the Ruby files
75
+ that define your functions. While `load_temporary` can ensure that the function
76
+ definitions do not conflict, it cannot do the same for classes, methods, and
77
+ other Ruby constructs. So, for testability, it is generally good practice to
78
+ include only functions in one of these files. If you need to write supporting
79
+ helper methods, classes, constants, or other code, include them in separate
80
+ ruby files that you `require`.
81
+
82
+ ## Testing HTTP functions
83
+
84
+ Testing an HTTP function is generally as simple as generating a request, calling
85
+ the function, and asserting against the response.
86
+
87
+ The input to an HTTP function is a
88
+ [Rack::Request](https://rubydoc.info/gems/rack/Rack/Request) object. It is
89
+ usually not hard to construct one of these objects, but the `Testing` module
90
+ includes helper methods that you can use to create simple requests for many
91
+ basic cases.
92
+
93
+ When you have constructed an input request, use
94
+ [call_http](https://rubydoc.info/gems/functions_framework/FunctionsFramework/Testing#call_http-instance_method)
95
+ to call a named function, passing the request object. This method returns a
96
+ [Rack::Response](https://rubydoc.info/gems/rack/Rack/Response) that you can
97
+ assert against.
98
+
99
+ ```ruby
100
+ require "minitest/autorun"
101
+ require "functions_framework/testing"
102
+
103
+ class MyTest < Minitest::Test
104
+ include FunctionsFramework::Testing
105
+
106
+ def test_http_function
107
+ load_temporary "app.rb" do
108
+ request = make_post_request "https://example.com/foo", "{\"name\":\"Ruby\"}",
109
+ ["Content-Type: application/json"]
110
+ response = call_http "my_function", request
111
+ assert_equal 200, response.status
112
+ assert_equal "Hello, Ruby!", response.body.join
113
+ end
114
+ end
115
+ end
116
+ ```
117
+
118
+ If the function raises an exception, the exception will be converted to a 500
119
+ response object. So if you are testing an error case, you should still check the
120
+ response object rather than looking for a raised exception.
121
+
122
+ ```ruby
123
+ require "minitest/autorun"
124
+ require "functions_framework/testing"
125
+
126
+ class MyTest < Minitest::Test
127
+ include FunctionsFramework::Testing
128
+
129
+ def test_erroring_http_function
130
+ load_temporary "app.rb" do
131
+ request = make_post_request "https://example.com/foo", "{\"name\":\"Ruby\"}",
132
+ ["Content-Type: application/json"]
133
+ response = call_http "error_function", request
134
+ assert_equal 500, response.status
135
+ assert_match(/ArgumentError/, response.body.join)
136
+ end
137
+ end
138
+ end
139
+ ```
140
+
141
+ ## Testing CloudEvent functions
142
+
143
+ Testing a CloudEvent function works similarly. The `Testing` module provides
144
+ methods to help construct example CloudEvent objects, which can then be passed
145
+ to the method
146
+ [call_event](https://rubydoc.info/gems/functions_framework/FunctionsFramework/Testing#call_event-instance_method).
147
+
148
+ Unlike HTTP functions, event functions do not have a return value. Instead, you
149
+ will need to test side effects. A common approach is to test logs by capturing
150
+ the standard error output.
151
+
152
+ ```ruby
153
+ require "minitest/autorun"
154
+ require "functions_framework/testing"
155
+
156
+ class MyTest < Minitest::Test
157
+ include FunctionsFramework::Testing
158
+
159
+ def test_event_function
160
+ load_temporary "app.rb" do
161
+ event = make_cloud_event "Hello, world!", type: "my-type"
162
+ _out, err = capture_subprocess_io do
163
+ call_event "my_function", event
164
+ end
165
+ assert_match(/Received: "Hello, world!"/, err)
166
+ end
167
+ end
168
+ end
169
+ ```
@@ -0,0 +1,275 @@
1
+ <!--
2
+ # @title Writing Functions
3
+ -->
4
+
5
+ # Writing Functions
6
+
7
+ This guide covers writing functions using the Functions Framework for Ruby. For
8
+ more information about the Framework, see the
9
+ {file:docs/overview.md Overview Guide}.
10
+
11
+ ## About functions
12
+
13
+ Functions are Ruby blocks that are run when an input is received. Those inputs
14
+ can be HTTP requests or events in a recognized format. Functions that receive
15
+ HTTP requests return an HTTP response, but event functions have no return value.
16
+
17
+ When you define a function, you must provide an identifying name. The Functions
18
+ Framework allows you to use any string as a function name; however, many
19
+ deployment environments restrict the characters that can be used in a name. For
20
+ maximum portability, it is recommended that you use names that are allowed for
21
+ Ruby methods, i.e. beginning with a letter, and containing only letters,
22
+ numbers, and underscores.
23
+
24
+ ## Defining an HTTP function
25
+
26
+ An HTTP function is a simple web service that takes an HTTP request and returns
27
+ an HTTP response. The following example defines an HTTP function named "hello"
28
+ that returns a simple message in the HTTP response body:
29
+
30
+ ```ruby
31
+ require "functions_framework"
32
+
33
+ FunctionsFramework.http "hello" do |request|
34
+ # Return the response body.
35
+ "Hello, world!\n"
36
+ end
37
+ ```
38
+
39
+ HTTP functions take a Rack Request object and return an HTTP response. We'll
40
+ now cover these in a bit more detail.
41
+
42
+ ### Using the Request object
43
+
44
+ An HTTP function is passed a request, which is an object of type
45
+ [Rack::Request](https://rubydoc.info/gems/rack/Rack/Request). This object
46
+ provides methods for obtaining request information such as the method,
47
+ path, query parameters, body content, and headers. You can also obtain the raw
48
+ Rack environment using the `env` method. The following example includes some
49
+ request information in the response:
50
+
51
+ ```ruby
52
+ require "functions_framework"
53
+
54
+ FunctionsFramework.http "request_info_example" do |request|
55
+ # Include some request info in the response body.
56
+ "Received #{request.method} from #{request.url}!\n"
57
+ end
58
+ ```
59
+
60
+ The Functions Framework sets up a logger in the Rack environment, so you can
61
+ use the `logger` method on the request object if you want to emit logs. These
62
+ logs will be written to the standard error stream, and will appear in the
63
+ Google Cloud Logs if your function is running on a Google Cloud serverless
64
+ hosting environment.
65
+
66
+ ```ruby
67
+ require "functions_framework"
68
+
69
+ FunctionsFramework.http "logging_example" do |request|
70
+ # Log some request info.
71
+ request.logger.info "I received #{request.method} from #{request.url}!"
72
+ # A simple response body.
73
+ "ok"
74
+ end
75
+ ```
76
+
77
+ ### Response types
78
+
79
+ The above examples return simple strings as the response body. Often, however,
80
+ you will need to return more complex responses such as JSON, binary data, or
81
+ even rendered HTML. The Functions Framework recognizes a variety of return
82
+ types from an HTTP function:
83
+
84
+ * **String** : If you return a string, the framework will use it as the
85
+ response body in with a 200 (success) HTTP status code. It will set the
86
+ `Content-Type` header to `text/plain`.
87
+ * **Array** : If you return an array, the framework will assume it is a
88
+ standard three-element Rack response array, as defined in the
89
+ [Rack spec](https://github.com/rack/rack/blob/master/SPEC.rdoc).
90
+ * **Rack::Response** : You can return a
91
+ [Rack::Response](https://rubydoc.info/gems/rack/Rack/Response) object. The
92
+ Framework will call `#finish` on this object and retrieve the contents.
93
+ * **Hash** : If you return a Hash, the Framework will attempt to encode it as
94
+ JSON, and return it in the response body with a 200 (success) HTTP status
95
+ code. The `Content-Type` will be set to `application/json`.
96
+ * **StandardError** : If you return an exception object, the Framework will
97
+ return a 500 (server error) response. See the section below on
98
+ Error Handling.
99
+
100
+ ### Using Sinatra
101
+
102
+ The Functions Framework, and the functions-as-a-service (FaaS) solutions it
103
+ targets, are optimized for relatively simple HTTP requests such as webhooks and
104
+ simple APIs. If you want to deploy a large application or use a monolithic
105
+ framework such as Ruby on Rails, you may want to consider a solution such as
106
+ Google Cloud Run that is tailored to larger applications. However, a lightweight
107
+ framework such as Sinatra is sometimes useful when writing HTTP functions.
108
+
109
+ It is easy to connect an HTTP function to a Sinatra app. First, declare the
110
+ dependency on Sinatra in your `Gemfile`:
111
+
112
+ ```ruby
113
+ # Gemfile
114
+ source "https://rubygems.org"
115
+ gem "functions_framework", "~> 0.4"
116
+ gem "sinatra", "~> 2.0"
117
+ ```
118
+
119
+ Write the Sinatra app using the "modular" Sinatra interface (i.e. subclass
120
+ `Sinatra::Base`), and then run the Sinatra app directly as a Rack handler from
121
+ the function. Here is a basic example:
122
+
123
+ ```ruby
124
+ require "functions_framework"
125
+ require "sinatra/base"
126
+
127
+ class App < Sinatra::Base
128
+ get "/hello/:name" do
129
+ "Hello, #{params[:name]}!"
130
+ end
131
+ end
132
+
133
+ FunctionsFramework.http "sinatra_example" do |request|
134
+ App.call request.env
135
+ end
136
+ ```
137
+
138
+ This technique gives you access to pretty much any feature of the Sinatra web
139
+ framework, including routes, templates, and even custom middleware.
140
+
141
+ ## Defining an Event function
142
+
143
+ An event function is a handler for a standard cloud event. It can receive
144
+ industry-standard [CloudEvents](https://cloudevents.io), as well as events sent
145
+ by Google Cloud services such as [Pub/Sub](https://cloud.google.com/pubsub) and
146
+ [Storage](https://cloud.google.com/storage). Event functions do not have a
147
+ return value.
148
+
149
+ The following is a simple event handler that receives an event and logs some
150
+ information about it:
151
+
152
+ ```ruby
153
+ require "functions_framework"
154
+
155
+ FunctionsFramework.cloud_event "hello" do |event|
156
+ FunctionsFramework.logger.info "I received an event of type #{event.type}!"
157
+ end
158
+ ```
159
+
160
+ The event parameter will be either a
161
+ [CloudEvents V0.3 Event](https://rubydoc.info/gems/functions_framework/FunctionsFramework/CloudEvents/Event/V0)
162
+ object ([see spec](https://github.com/cloudevents/spec/blob/v0.3/spec.md)) or a
163
+ [CloudEvents V1.0 Event](https://rubydoc.info/gems/functions_framework/FunctionsFramework/CloudEvents/Event/V1)
164
+ object ([see spec](https://github.com/cloudevents/spec/blob/v1.0/spec.md)).
165
+
166
+ Some Google Cloud services send events in a legacy event format that was defined
167
+ prior to CloudEvents. The Functions Framework will convert these legacy events
168
+ to an equivalent CloudEvents V1 type, so your function will always receive a
169
+ CloudEvent object when it is sent an event from Google Cloud. The precise
170
+ mapping between legacy events and CloudEvents is not specified in detail here,
171
+ but in general, the _data_ from the legacy event will be mapped to the `data`
172
+ field in the CloudEvent, and the _context_ from the legacy event will be mapped
173
+ to equivalent CloudEvent attributes.
174
+
175
+ ## Error handling
176
+
177
+ If your function encounters an error, it can raise an exception. The Functions
178
+ Framework will catch `StandardError` exceptions and handle them appropriately.
179
+
180
+ If you raise an exception in an HTTP function, the Functions Framework will
181
+ return a 500 (server error) response. You can control whether the exception
182
+ details (e.g. exception type, message, and backtrace) are sent with the
183
+ response by setting the detailed-errors configuration in the server. The
184
+ Framework will also log the error for you.
185
+
186
+ If you need more control over the error response, you can also construct the
187
+ HTTP response yourself. For example:
188
+
189
+ ```ruby
190
+ require "functions_framework"
191
+
192
+ FunctionsFramework.http "error_reporter" do |request|
193
+ begin
194
+ raise "whoops!"
195
+ rescue RuntimeError => e
196
+ [500, {}, ["Uh, oh, got an error message: #{e.message}."]]
197
+ end
198
+ end
199
+ ```
200
+
201
+ ## Structuring a project
202
+
203
+ A Functions Framework based "project" or "application" is a typical Ruby
204
+ application. It should include a `Gemfile` that specifies the gem dependencies
205
+ (including the `functions_framework` gem itself), and any other dependencies
206
+ needed by the function. It must include at least one Ruby source file that
207
+ defines functions, and can also include additional Ruby files defining classes
208
+ and methods that assist in the function implementation.
209
+
210
+ The "entrypoint" to the project, also called the "source", is a Ruby file. It
211
+ can define any number of functions (with distinct names), although it is often
212
+ good practice to create a separate Ruby file per function.
213
+
214
+ By convention, the source file is often called `app.rb`, but you can give it
215
+ any name. Projects can also have multiple source files that apply to different
216
+ cases.
217
+
218
+ A simple project might look like this:
219
+
220
+ ```
221
+ (project directory)
222
+ |
223
+ +- Gemfile
224
+ |
225
+ +- app.rb
226
+ |
227
+ +- lib/
228
+ | |
229
+ | +- hello.rb
230
+ |
231
+ +- test/
232
+ |
233
+ ...
234
+ ```
235
+
236
+ ```ruby
237
+ # Gemfile
238
+ source "https://rubygems.org"
239
+ gem "functions_framework", "~> 0.4"
240
+ ```
241
+
242
+ ```ruby
243
+ # app.rb
244
+ require "functions_framework"
245
+ require_relative "lib/hello"
246
+
247
+ FunctionsFramework.http "hello" do |request|
248
+ Hello.new(request).build_response
249
+ end
250
+ ```
251
+
252
+ ```ruby
253
+ # lib/hello.rb
254
+ class Hello
255
+ def initialize request
256
+ @request = request
257
+ end
258
+
259
+ def build_response
260
+ "Received request: #{request.method} #{request.url}\n"
261
+ end
262
+ end
263
+ ```
264
+
265
+ ## Next steps
266
+
267
+ To learn about writing unit tests for functions, see
268
+ {file:docs/testing-functions.md Testing Functions}.
269
+
270
+ To learn how to run your functions in a server, see
271
+ {file:docs/running-a-functions-server.md Running a Functions Server}.
272
+
273
+ To learn how to deploy your functions to Google Cloud Functions or Google Cloud
274
+ Run, see
275
+ {file:docs/deploying-functions.md Deploying Functions}.