mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Example app structure. round 1.
This commit is contained in:
@@ -79,7 +79,8 @@ func FromRequest(appName, path string, req *http.Request) CallOpt {
|
|||||||
|
|
||||||
baseVars["FN_FORMAT"] = route.Format
|
baseVars["FN_FORMAT"] = route.Format
|
||||||
baseVars["FN_APP_NAME"] = appName
|
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_MEMORY"] = fmt.Sprintf("%d", route.Memory)
|
||||||
baseVars["FN_TYPE"] = route.Type
|
baseVars["FN_TYPE"] = route.Type
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
// with the provided status code and error message body
|
||||||
type APIError interface {
|
type APIError interface {
|
||||||
Code() int
|
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} }
|
func NewAPIError(code int, e error) APIError { return err{code, e} }
|
||||||
|
|
||||||
// uniform error output
|
// Error uniform error output
|
||||||
type Error struct {
|
type Error struct {
|
||||||
Error *ErrorBody `json:"error,omitempty"`
|
Error *ErrorBody `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
7
examples/app/README.md
Normal file
7
examples/app/README.md
Normal file
@@ -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?
|
||||||
7
examples/app/footer/func.rb
Normal file
7
examples/app/footer/func.rb
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
puts %{
|
||||||
|
<div style="margin-top: 20px; border-top: 1px solid gray;">
|
||||||
|
<div><a href="/r/helloapp/ruby">Ruby</a></div><div><a href="/r/helloapp/node">Node</a></div><div><a href="/r/helloapp/python">Python</a></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
}
|
||||||
7
examples/app/footer/func.yaml
Normal file
7
examples/app/footer/func.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
name: footer
|
||||||
|
version: 0.0.10
|
||||||
|
runtime: ruby
|
||||||
|
entrypoint: ruby func.rb
|
||||||
|
headers:
|
||||||
|
content-type:
|
||||||
|
- text/html
|
||||||
58
examples/app/func.go
Normal file
58
examples/app/func.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Link struct {
|
||||||
|
Text string
|
||||||
|
Href string
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
const tpl = `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>{{.Title}}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>{{.Title}}</h1>
|
||||||
|
<p>{{.Body}}</p>
|
||||||
|
<div>
|
||||||
|
{{range .Items}}<div><a href="{{.Href}}">{{ .Text }}</a></div>{{else}}<div><strong>no rows</strong></div>{{end}}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>`
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
4
examples/app/func.yaml
Normal file
4
examples/app/func.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
name: app
|
||||||
|
version: 0.0.68
|
||||||
|
runtime: go
|
||||||
|
entrypoint: ./func
|
||||||
9
examples/app/header/func.rb
Normal file
9
examples/app/header/func.rb
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
puts %{
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>My App</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
}
|
||||||
7
examples/app/header/func.yaml
Normal file
7
examples/app/header/func.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
name: header
|
||||||
|
version: 0.0.9
|
||||||
|
runtime: ruby
|
||||||
|
entrypoint: ruby func.rb
|
||||||
|
headers:
|
||||||
|
content-type:
|
||||||
|
- text/html
|
||||||
2
examples/app/node/.gitignore
vendored
Normal file
2
examples/app/node/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
node_modules/
|
||||||
|
Dockerfile
|
||||||
1
examples/app/node/README.md
Normal file
1
examples/app/node/README.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Node function
|
||||||
10
examples/app/node/func.js
Normal file
10
examples/app/node/func.js
Normal file
@@ -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);
|
||||||
4
examples/app/node/func.yaml
Normal file
4
examples/app/node/func.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
name: node
|
||||||
|
version: 0.0.11
|
||||||
|
runtime: node
|
||||||
|
entrypoint: node func.js
|
||||||
7
examples/app/node/package.json
Normal file
7
examples/app/node/package.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "my-awesome-func",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"is-positive": "^3.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
1
examples/app/python/.gitignore
vendored
Normal file
1
examples/app/python/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
packages/
|
||||||
1
examples/app/python/README.md
Normal file
1
examples/app/python/README.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Python function
|
||||||
21
examples/app/python/func.py
Normal file
21
examples/app/python/func.py
Normal file
@@ -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 + "!"
|
||||||
4
examples/app/python/func.yaml
Normal file
4
examples/app/python/func.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
name: python
|
||||||
|
version: 0.0.9
|
||||||
|
runtime: python
|
||||||
|
entrypoint: python2 func.py
|
||||||
3
examples/app/ruby/.gitignore
vendored
Normal file
3
examples/app/ruby/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
bundle/
|
||||||
|
.bundle/
|
||||||
|
Dockerfile
|
||||||
3
examples/app/ruby/Gemfile
Normal file
3
examples/app/ruby/Gemfile
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
|
gem 'json', '> 1.8.2'
|
||||||
1
examples/app/ruby/README.md
Normal file
1
examples/app/ruby/README.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Ruby function
|
||||||
25
examples/app/ruby/func.rb
Normal file
25
examples/app/ruby/func.rb
Normal file
@@ -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
|
||||||
7
examples/app/ruby/func.yaml
Normal file
7
examples/app/ruby/func.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
name: ruby
|
||||||
|
version: 0.0.21
|
||||||
|
runtime: ruby
|
||||||
|
entrypoint: ruby func.rb
|
||||||
|
headers:
|
||||||
|
content-type:
|
||||||
|
- text/html
|
||||||
@@ -18,6 +18,7 @@ func main() {
|
|||||||
mapB, _ := json.Marshal(mapD)
|
mapB, _ := json.Marshal(mapD)
|
||||||
fmt.Println(string(mapB))
|
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("---> stderr goes to the server logs.")
|
||||||
log.Println("---> LINE 2")
|
log.Println("---> LINE 2")
|
||||||
log.Println("---> LINE 3 with a break right here\nand LINE 4")
|
log.Println("---> LINE 3 with a break right here\nand LINE 4")
|
||||||
|
|||||||
Reference in New Issue
Block a user