From 06b56941257864c365198a1c73ff6581947e43dc Mon Sep 17 00:00:00 2001 From: Tom Wright Date: Wed, 15 Apr 2020 17:44:17 +0100 Subject: [PATCH] Add GET handler for diagram generation --- README.md | 7 ++++- internal/http.go | 75 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 839ac8f..33862c8 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Start the HTTP server: go run cmd/app/main.go --mermaid=./mermaidcli/node_modules/.bin/mmdc --in=./in --out=./out ``` -Send CURL request to generate a diagram: +Send CURL request to generate a diagram via `POST`: ``` curl --location --request POST 'http://localhost:80/generate' \ --header 'Content-Type: text/plain' \ @@ -24,5 +24,10 @@ curl --location --request POST 'http://localhost:80/generate' \ ' ``` +Or send CURL request to generate a diagram via `GET`... send in url encoded data under the `data` query param: +``` +curl --location --request GET 'http://localhost:80/generate?data=graph%20LR%0A%0A%20%20%20%20A--%3EB%0A%20%20%20%20B--%3EC%0A%20%20%20%20C--%3ED%0A%20%20%20%20C--%3EF%0A' +``` + Inline-style: ![Example request in Postman](example.png "Example request in Postman") \ No newline at end of file diff --git a/internal/http.go b/internal/http.go index 0176c7d..4cb1611 100644 --- a/internal/http.go +++ b/internal/http.go @@ -5,6 +5,8 @@ import ( "fmt" "io/ioutil" "net/http" + "net/url" + "strings" ) func writeJSON(rw http.ResponseWriter, value interface{}, status int) { @@ -33,31 +35,76 @@ func writeErr(rw http.ResponseWriter, err error, status int) { }, status) } +// URLParam is the URL parameter getDiagramFromGET uses to look for data. +const URLParam = "data" + +func getDiagramFromGET(rw http.ResponseWriter, r *http.Request) *Diagram { + if r.Method != http.MethodGet { + writeErr(rw, fmt.Errorf("expected HTTP method GET"), http.StatusBadRequest) + return nil + } + + queryVal := strings.TrimSpace(r.URL.Query().Get(URLParam)) + if queryVal == "" { + writeErr(rw, fmt.Errorf("missing data"), http.StatusBadRequest) + return nil + } + data, err := url.QueryUnescape(queryVal) + if err != nil { + writeErr(rw, fmt.Errorf("could not read query param: %s", err), http.StatusBadRequest) + return nil + } + + // Create a diagram from the description + d := NewDiagram([]byte(data)) + return d +} + +func getDiagramFromPOST(rw http.ResponseWriter, r *http.Request) *Diagram { + if r.Method != http.MethodPost { + writeErr(rw, fmt.Errorf("expected HTTP method POST"), http.StatusBadRequest) + return nil + } + // Get description from request body + bytes, err := ioutil.ReadAll(r.Body) + if err != nil { + writeErr(rw, fmt.Errorf("could not read body: %s", err), http.StatusInternalServerError) + return nil + } + + // Create a diagram from the description + d := NewDiagram(bytes) + return d +} + +// GenerateHTTPHandler returns a HTTP handler used to generate a diagram. func GenerateHTTPHandler(generator Generator) func(rw http.ResponseWriter, r *http.Request) { return func(rw http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodPost { - writeErr(rw, fmt.Errorf("expected HTTP method POST"), http.StatusBadRequest) - return - } - // Get description from request body - bytes, err := ioutil.ReadAll(r.Body) - if err != nil { - writeErr(rw, fmt.Errorf("could not read body: %s", err), http.StatusInternalServerError) - return - } + var diagram *Diagram - // Create a diagram from the description - d := NewDiagram(bytes) + switch r.Method { + case http.MethodGet: + diagram = getDiagramFromGET(rw, r) + case http.MethodPost: + diagram = getDiagramFromPOST(rw, r) + default: + writeErr(rw, fmt.Errorf("unexpected HTTP method %s", r.Method), http.StatusBadRequest) + return + } + if diagram == nil { + writeErr(rw, fmt.Errorf("could not create diagram"), http.StatusInternalServerError) + return + } // Generate the diagram - if err := generator.Generate(d); err != nil { + if err := generator.Generate(diagram); err != nil { writeErr(rw, fmt.Errorf("could not generate diagram: %s", err), http.StatusInternalServerError) return } // Output the diagram as an SVG. // We assume generate always generates an SVG at this point in time. - diagramBytes, err := ioutil.ReadFile(d.Output) + diagramBytes, err := ioutil.ReadFile(diagram.Output) if err != nil { writeErr(rw, fmt.Errorf("could not read diagram bytes: %s", err), http.StatusInternalServerError) return