In this chapter you will learn how to serve HTML pages on App Engine and how to make the HTML and JavaScript components communicate with your Go code.
For now let's start with a simple HTML page:
<!DOCTYPE html>
<html>
<head>
<title>Hello, App Engine</title>
</head>
<body>
<h1>Hello, App Engine</h1>
</body>
</html>
We can create a new app.yaml
to serve this static page:
runtime: go
api_version: go1
handlers:
- url: /hello
static_files: hello.html
upload: hello.html
As you can see we are handling the requests with path /hello
displaying
the contents of the hello.html
file.
Try running your application locally (you can find all the files here). This should fail, because the Go runtime requires having some Go code in it!
There's two solutions for this:
-
use the Python runtime which doesn't require any Python code
-
or add some Go code, something as simple as this
dummy.go
file:
package dummy
We will do the latter as we'll add more Go code later on.
Try running your application again:
$ dev_appserver.py .
Or deploying it:
$ gcloud app deploy app.yaml
And verify that the output matches your expectations:
Static content is often not enough and we need our web app frontend (HTML + JS) to communicate with our backend.
To do so we have two different options:
- use
app.yaml
to determine what requests are handled by which part, or - use multiple modules on possibly different runtimes.
You can learn more about Go modules on this documentation.
For this workshop we will go with the simple option and just enhance the
previous app.yaml
to match our requirements.
We will need three components:
- a Go program similar to the previous one,
- an HTML page with pure static content, and
- an
app.yaml
file to glue everything together.
The only part that changes here is the app.yaml
:
runtime: go
api_version: go1
handlers:
# requests with empty paths are shown the html page.
- url: /
static_files: hello.html
upload: hello.html
# requests with the /api/ path are handled by the Go app.
- url: /api/.*
script: _go_app
Try changing the /api/hello
url on the second handler to /api/backend
.
Why does it fail? Fix it.
This can be done in many ways, as many as JavaScript frameworks you can think of. For this simple example we will simply use jQuery.
<!DOCTYPE html>
<html>
<head>
<title>Hello, App Engine</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
<h1>Hello, App Engine</h1>
<p>The backend says: <span id="message"></span></p>
<script>
$(function() {
$("#message").load("/api/hello");
});
</script>
</body>
</html>
As you can imagine very soon you will want to serve many static files, some
HTML, JavaScript, CSS, etc. Rather than listing each of those on your app.yaml
there's a much simpler option once you put all of them in a single directory.
my_app
|- app.yaml
|- hello.go
\- static
|- index.html
|- style.css
\- script.js
Your app.yaml
in this case will look like this:
runtime: go
api_version: go1
handlers:
# requests starting with /api/ are handled by the Go app.
- url: /api/.*
script: _go_app
# if the path is empty show index.html.
- url: /
static_files: static/index.html
upload: static/index.html
# otherwise try to find it in the static directory.
- url: /
static_dir: static
This kind of structure provides a clear structure of the application.
OK, we know now enough stuff to build an application. So, let's do it! 🎉
Have a look at this introduction describing the application and implement ONLY step 0. Then come back for more.
You just created your first application where a web frontend communicates with your Go backend!
But, shouldn't the backend generate JSON rather than plain text? Let's learn about JSON encoding and decoding on the next section.