include path parameters in params hash for ruby environment (#249)

* include path parameters in params hash for ruby environment

* Improve code organization and documentation for ruby environment.

* Document Ruby examples
This commit is contained in:
S. Brent Faulkner
2017-07-04 23:44:18 -07:00
committed by Soam Vasani
parent ae87c0ea37
commit 0fd60eab3b
7 changed files with 208 additions and 52 deletions
+17 -3
View File
@@ -2,9 +2,19 @@
This is the Ruby environment for Fission. This is the Ruby environment for Fission.
It's a Docker image containing a Ruby 2.4.1 runtime, along with a It's a Docker image containing a Ruby 2.4.1 runtime. The image uses
dynamic loader. A few common dependencies are included in the Rack with WEBrick to host the internal web server.
Gemfile.
The environment works via convention where you create a Ruby method
called `handler` with a single optional argument, a `Fission::Context`
object.
The `Fission::Context` object gives access to the Rack env, and a
request object. Please see `fission/context.rb` for the public api.
The `Fission::Request` object is a subclass of `Rack::Request` and
provides access to parameters and headers. See `fission/request.rb`
for the public api.
## Customizing this image ## Customizing this image
@@ -39,3 +49,7 @@ Or, if you already have an environment, you can update its image:
After this, fission functions that have the env parameter set to the After this, fission functions that have the env parameter set to the
same environment name as this command will use this environment. same environment name as this command will use this environment.
## Creating functions to use this image
See the [examples README](examples/ruby/README.md).
+17
View File
@@ -0,0 +1,17 @@
# frozen_string_literal: true
require_relative 'request'
module Fission
class Context
attr_reader :env
def initialize(env)
@env = env
end
def request
@request ||= Request.new(env)
end
end
end
+19
View File
@@ -0,0 +1,19 @@
# frozen_string_literal: true
require_relative 'context'
module Fission
module Handler
def self.call(env)
response = if method(:handler).arity > 0
handler(Context.new(env))
else
handler
end
response.is_a?(Array) ? response : Rack::Response.new([response]).finish
rescue
Rack::Response.new(['500 Internal Server Error'], 500, {}).finish
end
end
end
+31
View File
@@ -0,0 +1,31 @@
# frozen_string_literal: true
module Fission
HEADER_PREFIX = 'HTTP_'
PARAM_HEADER_PREFIX = 'HTTP_X_FISSION_PARAMS_'
PARAMETERS_KEY = 'fission.request.parameters'
class Request < Rack::Request
def headers
Hash[
*env.select { |k,v| k.start_with?(HEADER_PREFIX) }
.map { |k,v| [k.sub(/\A#{HEADER_PREFIX}/, '').split('_').map(&:capitalize).join('-'), v] }
.sort
.flatten
]
end
def params
env[PARAMETERS_KEY] ||= super.merge(path_parameters)
end
def path_parameters
Hash[
*env.select { |k,v| k.start_with?(PARAM_HEADER_PREFIX) }
.map { |k,v| [k.sub(/\A#{PARAM_HEADER_PREFIX}/, '').downcase, v] }
.sort
.flatten
]
end
end
end
+14
View File
@@ -0,0 +1,14 @@
# frozen_string_literal: true
module Fission
CODE_PATH = '/userfunc/user'
module Specializer
def self.call(env)
load CODE_PATH
Rack::Response.new([], 201).finish
rescue
Rack::Response.new(['500 Internal Server Error'], 500, {}).finish
end
end
end
+3 -49
View File
@@ -1,55 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'rack' require 'rack'
CODEPATH = '/userfunc/user' require_relative 'fission/specializer'
require_relative 'fission/handler'
module Fission
class Request < Rack::Request
def headers
Hash[
*env.select { |k,v| k.start_with?('HTTP_') }
.map { |k,v| [k.sub(/\AHTTP_/, '').split('_').map(&:capitalize).join('-'), v] }
.sort
.flatten
]
end
end
class Context
attr_reader :env
def initialize(env)
@env = env
end
def request
@request ||= Request.new(env)
end
end
module Specializer
def self.call(env)
load CODEPATH
Rack::Response.new([], 201).finish
rescue
Rack::Response.new(['500 Internal Server Error'], 500, {}).finish
end
end
module Handler
def self.call(env)
response = if method(:handler).arity > 0
handler(Context.new(env))
else
handler
end
response.is_a?(Array) ? response : Rack::Response.new([response]).finish
rescue
Rack::Response.new(['500 Internal Server Error'], 500, {}).finish
end
end
end
app = Rack::Builder.new do app = Rack::Builder.new do
use Rack::CommonLogger, $stderr use Rack::CommonLogger, $stderr
+107
View File
@@ -0,0 +1,107 @@
# Ruby examples
This directory contains several examples to get you started using Ruby
with Fission.
Before running any of these functions, make sure you have created a
`ruby` Fission environment:
```
$ fission env create --name ruby --image USER/ruby-env
```
## Method signature
A standard Ruby function has the basic form:
```ruby
def handler(context)
return [200, {}, []]
end
```
If the fission context is not required, the function can be simplified:
```ruby
def handler
[200, {}, ["Hello, world!\n"]]
end
```
If a simple text response is to be returned, with a status of 200, this
can be further simplified.
```ruby
def handler
"Hello, world!\n"
end
```
## Hello example (`hello.rb`)
This example is the simplest possible Ruby function, as described above.
To run the example:
```
$ fission function create --name hello --env ruby --code examples/ruby/hello.rb
$ fission route create --method GET --url /hello --function hello
$ curl http://$FISSION_ROUTER/hello
Hello, world!
```
## Request data example (`request_data.rb`)
This example shows basic use of the `Fission::Context` and
`Fission::Request` objects.
To run the example:
```
$ fission function create --name request --env ruby --code examples/ruby/request_data.rb
$ fission route create --method GET --url /request/{id} --function request
$ curl http://$FISSION_ROUTER/request/123?key=abc
---ENV---
GATEWAY_INTERFACE=CGI/1.1
PATH_INFO=/
QUERY_STRING=key=abc
REMOTE_ADDR=172.17.0.8
REMOTE_HOST=172.17.0.8
REQUEST_METHOD=GET
REQUEST_URI=http://192.168.64.200:31314/?key=abc
SCRIPT_NAME=
SERVER_NAME=192.168.64.200
SERVER_PORT=31314
SERVER_PROTOCOL=HTTP/1.1
SERVER_SOFTWARE=WEBrick/1.3.1 (Ruby/2.4.1/2017-03-22)
HTTP_HOST=192.168.64.200:31314
HTTP_USER_AGENT=curl/7.52.1
HTTP_ACCEPT=*/*
HTTP_X_FISSION_PARAMS_ID=123
HTTP_X_FORWARDED_FOR=172.17.0.1
HTTP_ACCEPT_ENCODING=gzip
rack.version=1=3
...
HTTP_VERSION=HTTP/1.1
REQUEST_PATH=/
---HEADERS---
Accept: */*
Accept-Encoding: gzip
Host: 192.168.64.200:31314
User-Agent: curl/7.52.1
Version: HTTP/1.1
X-Fission-Params-Id: 123
X-Forwarded-For: 172.17.0.1
---PARAMS---
key=abc
id=123
--BODY--
```