[Webapp] Dart HTTP POST JSON Data to Go Server
This post shows how to write a web application which passes JSON-format data between browser (client side) and web server (server side) via HTTP POST. The code which runs on the browser is implemented with Dart, and the code which runs on web server is implemented with Go. I put explanation and references directly in the code for the convenience of fast lookup and tracing code.
To run the code, download the following files in the same directory. Modify the path in Makefile and type make to execute. (If you do not have Dartium, type make js before you type make). Then open your browser at http://localhost:8000/.
Development Environment: Ubuntu Linux 14.10, Dart 1.8, Go 1.4.
Server side (Go web server):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | // Google search keyword: golang http template // https://golang.org/doc/articles/wiki/ // http://golang.org/pkg/html/template/ // Google search keyword: go serve static file // http://stackoverflow.com/questions/17690230/go-web-page-static-file-serving // http://stackoverflow.com/questions/25945538/go-golang-to-serve-a-specific-html-file // Google search keyword: golang http minetype set // https://golang.org/src/net/http/pprof/pprof.go#L73 // http://stackoverflow.com/questions/12830095/setting-http-headers-in-golang // Handling JSON Post Request in Go // http://stackoverflow.com/questions/15672556/handling-json-post-request-in-go package main import ( "html/template" "net/http" "encoding/json" "fmt" ) type dataFromClient struct { Title string // cannot use title (lower case will case json decode failure) Url string // cannot use url (lower case will case json decode failure) } func handler(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/app.dart" { w.Header().Set("Content-Type", "application/dart; charset=utf-8") http.ServeFile(w, r, "./app.dart") return } if r.URL.Path == "/app.js" { w.Header().Set("Content-Type", "application/javascript; charset=utf-8") http.ServeFile(w, r, "./app.js") return } t, _ := template.ParseFiles("index.html") t.Execute(w, r.URL.Path) } func postHandler(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { return } if r.URL.Path != "/post" { return } decoder := json.NewDecoder(r.Body) var d dataFromClient // should handle error here decoder.Decode(&d) fmt.Fprintf(w, "<a href=\"%s\">%s</a>", d.Url, d.Title) } func main() { http.HandleFunc("/", handler) http.HandleFunc("/post", postHandler) http.ListenAndServe(":8000", nil) } |
Server side (HTML template for Go):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <!doctype html> <html> <head> <meta charset="utf-8"> <title>Dart HTTP POST JSON to Go Server</title> </head> <body> <div>URL Path: {{.}}</div> <button type="button" data-title="my blog" data-url="https://siongui.github.io/">My blog</button> <button type="button" data-title="Google" data-url="https://www.google.com/">Google</button> <button type="button" data-title="Facebook" data-url="https://www.facebook.com/">Facebook</button> <script type='text/javascript'> var script = document.createElement('script'); if (navigator.userAgent.indexOf('(Dart)') === -1) { // Browser doesn't support Dart script.setAttribute("type","text/javascript"); script.setAttribute("src", "app.js"); } else { script.setAttribute("type","application/dart"); script.setAttribute("src", "app.dart"); } document.getElementsByTagName("head")[0].appendChild(script); </script> </body> </html> |
Client side (Dart):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import 'dart:html'; // https://www.dartlang.org/articles/json-web-service/ import 'dart:convert'; void httpPostJSON(Event e) { ButtonElement elm = e.target as ButtonElement; HttpRequest request = new HttpRequest(); // create a new XHR // add an event handler that is called when the request finishes request.onReadyStateChange.listen((_) { if (request.readyState == HttpRequest.DONE && (request.status == 200 || request.status == 0)) { // data saved OK. // http://stackoverflow.com/questions/12177970/how-do-i-add-arbitrary-html-to-an-element-in-dart querySelector("body").appendHtml(request.responseText); } }); // POST the data to the server var url = "/post"; request.open("POST", url, async: false); request.send(JSON.encode(elm.dataset)); // perform the async POST } void main() { querySelectorAll("button").forEach((Element elm) { elm.onClick.listen(httpPostJSON); }); } |
Makefile for automating the development:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | # cannot use relative path in GOROOT, otherwise 6g not found. For example, # export GOROOT=../go (=> 6g not found) # it is also not allowed to use relative path in GOPATH export GOROOT=$(realpath ../../../../../go) export GOPATH=$(realpath .) export PATH := $(GOROOT)/bin:$(PATH) # path of Dart and utilities DART_DIR=../../../../../dart DART_SDK=$(DART_DIR)/dart-sdk DART_SDK_BIN=$(DART_SDK)/bin DARTVM=$(DART_SDK_BIN)/dart DART2JS=$(DART_SDK_BIN)/dart2js DARTPUB=$(DART_SDK_BIN)/pub DARTIUM=$(DART_DIR)/chromium/chrome devserver: go run server.go # Fix Dartium startup error: # http://askubuntu.com/questions/369310/how-to-fix-missing-libudev-so-0-for-chrome-to-start-again dartium: DART_FLAGS='--checked' $(DARTIUM) --user-data-dir=/tmp/data http://localhost:8000/ & js: app.dart $(DART2JS) --minify --out=app.js app.dart clean: [ -e app.js.deps ] && rm app.js.deps [ -e app.js.map ] && rm app.js.map [ -e app.js ] && rm app.js help: $(DARTVM) --print-flags go help |
References:
[1] | Writing Web Applications - The Go Programming Language |
[2] | Handling JSON Post Request in Go |
[3] | Using Dart with JSON Web Services |