From c2ee67fb21f7354563c39320ae098d6d7a6fc22e Mon Sep 17 00:00:00 2001 From: Denis Makogon Date: Sun, 1 Oct 2017 14:12:38 +0300 Subject: [PATCH] Revisiting request body processing --- api/agent/protocol/json.go | 22 ++++++- examples/formats/http/go/Dockerfile | 8 +++ .../http/go/README.md | 0 examples/formats/http/python/Dockerfile | 3 +- examples/formats/json/go/.gitignore | 6 -- examples/formats/json/go/Dockerfile | 8 +++ examples/formats/json/go/func.go | 59 ++++++++++--------- examples/formats/json/go/func.yaml | 7 +++ examples/formats/json/go/sample.payload.json | 2 +- examples/formats/json/python/Dockerfile | 8 +++ examples/formats/json/python/func.yaml | 2 +- .../tutorial/hotfunctions/http/go/func.yaml | 6 -- 12 files changed, 86 insertions(+), 45 deletions(-) create mode 100644 examples/formats/http/go/Dockerfile rename examples/{tutorial/hotfunctions => formats}/http/go/README.md (100%) delete mode 100644 examples/formats/json/go/.gitignore create mode 100644 examples/formats/json/go/Dockerfile create mode 100644 examples/formats/json/go/func.yaml create mode 100644 examples/formats/json/python/Dockerfile delete mode 100644 examples/tutorial/hotfunctions/http/go/func.yaml diff --git a/api/agent/protocol/json.go b/api/agent/protocol/json.go index b1465cf56..72e0a65ce 100644 --- a/api/agent/protocol/json.go +++ b/api/agent/protocol/json.go @@ -1,6 +1,7 @@ package protocol import ( + "bytes" "encoding/json" "fmt" "io" @@ -25,6 +26,23 @@ func (p *JSONProtocol) IsStreamable() bool { return true } +type RequestEncoder struct { + *json.Encoder +} + +func (re *RequestEncoder) EncodeRequest(rq *http.Request) error { + bb := new(bytes.Buffer) + _, err := bb.ReadFrom(rq.Body) + if err != nil { + return err + } + defer bb.Reset() + return re.Encode(JSONIO{ + Headers: rq.Header, + Body: bb.String(), + }) +} + func (h *JSONProtocol) DumpJSON(w io.Writer, req *http.Request) error { _, err := io.WriteString(h.in, `{`) if err != nil { @@ -68,7 +86,9 @@ func (h *JSONProtocol) DumpJSON(w io.Writer, req *http.Request) error { } func (h *JSONProtocol) Dispatch(w io.Writer, req *http.Request) error { - err := h.DumpJSON(w, req) + ce := RequestEncoder{json.NewEncoder(h.in)} + err := ce.EncodeRequest(req) + //err := h.DumpJSON(w, req) if err != nil { return respondWithError( w, fmt.Errorf("unable to write JSON into STDIN: %s", err.Error())) diff --git a/examples/formats/http/go/Dockerfile b/examples/formats/http/go/Dockerfile new file mode 100644 index 000000000..1c1b324fd --- /dev/null +++ b/examples/formats/http/go/Dockerfile @@ -0,0 +1,8 @@ +FROM fnproject/go:dev as build-stage +WORKDIR /function +ADD . /src +RUN cd /src && go build -o func +FROM fnproject/go +WORKDIR /function +COPY --from=build-stage /src/func /function/ +ENTRYPOINT ["./func"] diff --git a/examples/tutorial/hotfunctions/http/go/README.md b/examples/formats/http/go/README.md similarity index 100% rename from examples/tutorial/hotfunctions/http/go/README.md rename to examples/formats/http/go/README.md diff --git a/examples/formats/http/python/Dockerfile b/examples/formats/http/python/Dockerfile index c0b70b919..9819cadfa 100644 --- a/examples/formats/http/python/Dockerfile +++ b/examples/formats/http/python/Dockerfile @@ -1,9 +1,8 @@ -FROM jjanzic/docker-python3-opencv +FROM python:3.6.2 RUN mkdir /code ADD . /code/ WORKDIR /code RUN pip3 install -r requirements.txt -WORKDIR /code/ ENTRYPOINT ["python3", "func.py"] diff --git a/examples/formats/json/go/.gitignore b/examples/formats/json/go/.gitignore deleted file mode 100644 index d450e309c..000000000 --- a/examples/formats/json/go/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -vendor/ -/go -/app -/__uberscript__ - -func.yaml diff --git a/examples/formats/json/go/Dockerfile b/examples/formats/json/go/Dockerfile new file mode 100644 index 000000000..1c1b324fd --- /dev/null +++ b/examples/formats/json/go/Dockerfile @@ -0,0 +1,8 @@ +FROM fnproject/go:dev as build-stage +WORKDIR /function +ADD . /src +RUN cd /src && go build -o func +FROM fnproject/go +WORKDIR /function +COPY --from=build-stage /src/func /function/ +ENTRYPOINT ["./func"] diff --git a/examples/formats/json/go/func.go b/examples/formats/json/go/func.go index 8a7e066b2..b17661c17 100644 --- a/examples/formats/json/go/func.go +++ b/examples/formats/json/go/func.go @@ -1,12 +1,11 @@ package main import ( - "bufio" "bytes" "encoding/json" "fmt" - "io" "log" + "net/http" "os" ) @@ -14,36 +13,32 @@ type Person struct { Name string `json:"name"` } -type JSONInput struct { - Body string `json:"body"` -} - -type JSONOutput struct { - StatusCode int `json:"status"` - Body string `json:"body"` +type JSON struct { + Headers http.Header `json:"headers"` + Body string `json:"body,omitempty"` + StatusCode int `json:"status,omitempty"` } func main() { - enc := json.NewEncoder(os.Stdout) - r := bufio.NewReader(os.Stdin) + stdin := json.NewDecoder(os.Stdin) + stdout := json.NewEncoder(os.Stdout) + stderr := json.NewEncoder(os.Stderr) for { - var buf bytes.Buffer - in := &JSONInput{} - _, err := io.Copy(&buf, r) - if err != nil { - log.Fatalln(err) - } + in := &JSON{} - err = json.Unmarshal(buf.Bytes(), in) + err := stdin.Decode(in) if err != nil { - log.Fatalln(err) + log.Fatalf("Unable to decode incoming data: %s", err.Error()) + fmt.Fprintf(os.Stderr, err.Error()) } - person := Person{} - if in.Body != "" { - if err := json.Unmarshal([]byte(in.Body), &person); err != nil { - log.Fatalln(err) + stderr.Encode(in.Body) + stderr.Encode(fmt.Sprintf(in.Body)) + if len(in.Body) != 0 { + if err := json.NewDecoder(bytes.NewReader([]byte(in.Body))).Decode(&person); err != nil { + log.Fatalf("Unable to decode Person object data: %s", err.Error()) + fmt.Fprintf(os.Stderr, err.Error()) } } if person.Name == "" { @@ -51,11 +46,19 @@ func main() { } mapResult := map[string]string{"message": fmt.Sprintf("Hello %s", person.Name)} - out := &JSONOutput{StatusCode: 200} - b, _ := json.Marshal(mapResult) - out.Body = string(b) - if err := enc.Encode(out); err != nil { - log.Fatalln(err) + b, err := json.Marshal(mapResult) + if err != nil { + log.Fatalf("Unable to marshal JSON response body: %s", err.Error()) + fmt.Fprintf(os.Stderr, err.Error()) + } + out := &JSON{ + StatusCode: http.StatusOK, + Body: string(b), + } + stderr.Encode(out) + if err := stdout.Encode(out); err != nil { + log.Fatalf("Unable to encode JSON response: %s", err.Error()) + fmt.Fprintf(os.Stderr, err.Error()) } } } diff --git a/examples/formats/json/go/func.yaml b/examples/formats/json/go/func.yaml new file mode 100644 index 000000000..8b25cef4a --- /dev/null +++ b/examples/formats/json/go/func.yaml @@ -0,0 +1,7 @@ +name: fnproject/hot-json-go +version: 0.0.1 +runtime: docker +type: sync +memory: 256 +format: json +path: /hot-json-go diff --git a/examples/formats/json/go/sample.payload.json b/examples/formats/json/go/sample.payload.json index 0a3c281da..97e136b69 100644 --- a/examples/formats/json/go/sample.payload.json +++ b/examples/formats/json/go/sample.payload.json @@ -1,3 +1,3 @@ { - "Name": "Johnny" + "name": "Johnny" } diff --git a/examples/formats/json/python/Dockerfile b/examples/formats/json/python/Dockerfile new file mode 100644 index 000000000..9819cadfa --- /dev/null +++ b/examples/formats/json/python/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3.6.2 + +RUN mkdir /code +ADD . /code/ +WORKDIR /code +RUN pip3 install -r requirements.txt + +ENTRYPOINT ["python3", "func.py"] diff --git a/examples/formats/json/python/func.yaml b/examples/formats/json/python/func.yaml index 1fa4b933d..4dce1ef9f 100644 --- a/examples/formats/json/python/func.yaml +++ b/examples/formats/json/python/func.yaml @@ -3,5 +3,5 @@ version: 0.0.1 runtime: docker type: sync memory: 256 -format: http +format: json path: /hot-json-python diff --git a/examples/tutorial/hotfunctions/http/go/func.yaml b/examples/tutorial/hotfunctions/http/go/func.yaml deleted file mode 100644 index c443b570e..000000000 --- a/examples/tutorial/hotfunctions/http/go/func.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: hotfunction-http -version: 0.0.10 -runtime: go -entrypoint: ./func -format: http -path: /hotfn-go