diff --git a/api/agent/call.go b/api/agent/call.go index 3b811c919..2df2f95ba 100644 --- a/api/agent/call.go +++ b/api/agent/call.go @@ -79,7 +79,8 @@ func FromRequest(appName, path string, req *http.Request) CallOpt { baseVars["FN_FORMAT"] = route.Format baseVars["FN_APP_NAME"] = appName - baseVars["FN_ROUTE"] = route.Path + baseVars["FN_PATH"] = route.Path + // TODO: might be a good idea to pass in: envVars["FN_BASE_PATH"] = fmt.Sprintf("/r/%s", appName) || "/" if using DNS entries per app baseVars["FN_MEMORY"] = fmt.Sprintf("%d", route.Memory) baseVars["FN_TYPE"] = route.Type diff --git a/api/models/error.go b/api/models/error.go index c6a27a4dc..eb9b40350 100644 --- a/api/models/error.go +++ b/api/models/error.go @@ -154,7 +154,7 @@ var ( } ) -// any error that implements this interface will return an API response +// APIError any error that implements this interface will return an API response // with the provided status code and error message body type APIError interface { Code() int @@ -170,7 +170,7 @@ func (e err) Code() int { return e.code } func NewAPIError(code int, e error) APIError { return err{code, e} } -// uniform error output +// Error uniform error output type Error struct { Error *ErrorBody `json:"error,omitempty"` } diff --git a/examples/app/README.md b/examples/app/README.md new file mode 100644 index 000000000..4e823b5a6 --- /dev/null +++ b/examples/app/README.md @@ -0,0 +1,7 @@ +# App Example + +This shows you how to organize functions into a full application and deploy them easily with one command. + +## TODOs + +* [ ] Use a header/footer endpoint and pull them into the functions? diff --git a/examples/tutorial/hello/app.yaml b/examples/app/app.yaml similarity index 100% rename from examples/tutorial/hello/app.yaml rename to examples/app/app.yaml diff --git a/examples/app/footer/func.rb b/examples/app/footer/func.rb new file mode 100644 index 000000000..1e9f72581 --- /dev/null +++ b/examples/app/footer/func.rb @@ -0,0 +1,7 @@ +puts %{ +
+
Ruby
Node
Python
+
+ + +} \ No newline at end of file diff --git a/examples/app/footer/func.yaml b/examples/app/footer/func.yaml new file mode 100644 index 000000000..db40b391b --- /dev/null +++ b/examples/app/footer/func.yaml @@ -0,0 +1,7 @@ +name: footer +version: 0.0.10 +runtime: ruby +entrypoint: ruby func.rb +headers: + content-type: + - text/html diff --git a/examples/app/func.go b/examples/app/func.go new file mode 100644 index 000000000..722fa2ff5 --- /dev/null +++ b/examples/app/func.go @@ -0,0 +1,58 @@ +package main + +import ( + "fmt" + "html/template" + "log" + "os" +) + +type Link struct { + Text string + Href string +} + +func main() { + const tpl = ` + + + + + {{.Title}} + + +

{{.Title}}

+

{{.Body}}

+
+ {{range .Items}}
{{ .Text }}
{{else}}
no rows
{{end}} +
+ + ` + + check := func(err error) { + if err != nil { + log.Fatal(err) + } + } + t, err := template.New("webpage").Parse(tpl) + check(err) + + appName := os.Getenv("FN_APP_NAME") + + data := struct { + Title string + Body string + Items []Link + }{ + Title: "My App", + Body: "This is my app. It may not be the best app, but it's my app. And it's multilingual!", + Items: []Link{ + Link{"Ruby", fmt.Sprintf("/r/%s/ruby", appName)}, + Link{"Node", fmt.Sprintf("/r/%s/node", appName)}, + Link{"Python", fmt.Sprintf("/r/%s/python", appName)}, + }, + } + + err = t.Execute(os.Stdout, data) + check(err) +} diff --git a/examples/app/func.yaml b/examples/app/func.yaml new file mode 100644 index 000000000..29629e116 --- /dev/null +++ b/examples/app/func.yaml @@ -0,0 +1,4 @@ +name: app +version: 0.0.68 +runtime: go +entrypoint: ./func diff --git a/examples/app/header/func.rb b/examples/app/header/func.rb new file mode 100644 index 000000000..edca7db3c --- /dev/null +++ b/examples/app/header/func.rb @@ -0,0 +1,9 @@ +puts %{ + + + + + My App + + +} diff --git a/examples/app/header/func.yaml b/examples/app/header/func.yaml new file mode 100644 index 000000000..16546943a --- /dev/null +++ b/examples/app/header/func.yaml @@ -0,0 +1,7 @@ +name: header +version: 0.0.9 +runtime: ruby +entrypoint: ruby func.rb +headers: + content-type: + - text/html diff --git a/examples/app/node/.gitignore b/examples/app/node/.gitignore new file mode 100644 index 000000000..c5757e699 --- /dev/null +++ b/examples/app/node/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +Dockerfile diff --git a/examples/app/node/README.md b/examples/app/node/README.md new file mode 100644 index 000000000..3902e3b80 --- /dev/null +++ b/examples/app/node/README.md @@ -0,0 +1 @@ +# Node function diff --git a/examples/app/node/func.js b/examples/app/node/func.js new file mode 100644 index 000000000..465c6b427 --- /dev/null +++ b/examples/app/node/func.js @@ -0,0 +1,10 @@ +fs = require('fs'); + +name = "do you speak node?"; +try { + obj = JSON.parse(fs.readFileSync('/dev/stdin').toString()) + if (obj.name != "") { + name = obj.name + } +} catch(e) {} +console.log("Hello, " + name); diff --git a/examples/app/node/func.yaml b/examples/app/node/func.yaml new file mode 100644 index 000000000..371884b79 --- /dev/null +++ b/examples/app/node/func.yaml @@ -0,0 +1,4 @@ +name: node +version: 0.0.11 +runtime: node +entrypoint: node func.js diff --git a/examples/app/node/package.json b/examples/app/node/package.json new file mode 100644 index 000000000..cca3d6e1c --- /dev/null +++ b/examples/app/node/package.json @@ -0,0 +1,7 @@ +{ + "name": "my-awesome-func", + "version": "1.0.0", + "dependencies": { + "is-positive": "^3.1.0" + } +} \ No newline at end of file diff --git a/examples/app/python/.gitignore b/examples/app/python/.gitignore new file mode 100644 index 000000000..23053de09 --- /dev/null +++ b/examples/app/python/.gitignore @@ -0,0 +1 @@ +packages/ diff --git a/examples/app/python/README.md b/examples/app/python/README.md new file mode 100644 index 000000000..53f99497a --- /dev/null +++ b/examples/app/python/README.md @@ -0,0 +1 @@ +# Python function diff --git a/examples/app/python/func.py b/examples/app/python/func.py new file mode 100644 index 000000000..3638de866 --- /dev/null +++ b/examples/app/python/func.py @@ -0,0 +1,21 @@ +import sys +import os +import json + +sys.stderr.write("Starting Python Function\n") + +name = "I speak Python too" + +try: + if not os.isatty(sys.stdin.fileno()): + try: + obj = json.loads(sys.stdin.read()) + if obj["name"] != "": + name = obj["name"] + except ValueError: + # ignore it + sys.stderr.write("no input, but that's ok\n") +except: + pass + +print "Hello, " + name + "!" diff --git a/examples/app/python/func.yaml b/examples/app/python/func.yaml new file mode 100644 index 000000000..e82c8926b --- /dev/null +++ b/examples/app/python/func.yaml @@ -0,0 +1,4 @@ +name: python +version: 0.0.9 +runtime: python +entrypoint: python2 func.py diff --git a/examples/app/ruby/.gitignore b/examples/app/ruby/.gitignore new file mode 100644 index 000000000..e8aaf2186 --- /dev/null +++ b/examples/app/ruby/.gitignore @@ -0,0 +1,3 @@ +bundle/ +.bundle/ +Dockerfile diff --git a/examples/app/ruby/Gemfile b/examples/app/ruby/Gemfile new file mode 100644 index 000000000..e05a90012 --- /dev/null +++ b/examples/app/ruby/Gemfile @@ -0,0 +1,3 @@ +source 'https://rubygems.org' + +gem 'json', '> 1.8.2' diff --git a/examples/app/ruby/README.md b/examples/app/ruby/README.md new file mode 100644 index 000000000..7e40910bf --- /dev/null +++ b/examples/app/ruby/README.md @@ -0,0 +1 @@ +# Ruby function diff --git a/examples/app/ruby/func.rb b/examples/app/ruby/func.rb new file mode 100644 index 000000000..2ed6da51c --- /dev/null +++ b/examples/app/ruby/func.rb @@ -0,0 +1,25 @@ +require 'uri' +require 'net/http' +require 'json' + +name = "I love rubies" + +payload = STDIN.read +if payload != "" + payload = JSON.parse(payload) + name = payload['name'] +end + + +def open(url) + Net::HTTP.get(URI.parse(url)) +end +h = "docker.for.mac.localhost" # ENV['HOSTNAME'] + +header = open("http://#{h}:8080/r/#{ENV['FN_APP_NAME']}/header") # todo: grab env vars to construct this +puts header + +puts "Hello, #{name}! YOOO" + +footer = open("http://#{h}:8080/r/#{ENV['FN_APP_NAME']}/footer") # todo: grab env vars to construct this +puts footer diff --git a/examples/app/ruby/func.yaml b/examples/app/ruby/func.yaml new file mode 100644 index 000000000..4c78e8da2 --- /dev/null +++ b/examples/app/ruby/func.yaml @@ -0,0 +1,7 @@ +name: ruby +version: 0.0.21 +runtime: ruby +entrypoint: ruby func.rb +headers: + content-type: + - text/html diff --git a/examples/tutorial/hello/go/func.go b/examples/tutorial/hello/go/func.go index c1f3f8401..51cc236a7 100644 --- a/examples/tutorial/hello/go/func.go +++ b/examples/tutorial/hello/go/func.go @@ -18,6 +18,7 @@ func main() { mapB, _ := json.Marshal(mapD) fmt.Println(string(mapB)) + // TODO: move these lines to a test, this was for testing log output issues log.Println("---> stderr goes to the server logs.") log.Println("---> LINE 2") log.Println("---> LINE 3 with a break right here\nand LINE 4")