Google App Engine gives developers a NoOps (short for No Operations, indicating that developers and engineers have no work to do in order to have their code running and available) way of deploying their applications, and Go has been officially supported as a language option for some years now. Google's architecture runs some of the biggest applications in the world, such as Google Search, Google Maps, and Gmail, among others, so is a pretty safe bet when it comes to deploying our own code.
Google App Engine allows you to write a Go application, add a few special configuration files, and deploy it to Google's servers, where it will be hosted and made available in a highly available, scalable, and elastic environment. Instances will automatically spin up to meet demand and tear down gracefully when they are no longer needed with a healthy free quota and preapproved budgets.
Along with running application instances, Google App Engine makes available a myriad of useful services, such as fast and high-scale data stores, search, memcache, and task queues. Transparent load balancing means you don't need to build and maintain additional software or hardware to ensure servers don't get overloaded and that requests are fulfilled quickly.
In this chapter, we will build the API backend for a question and answer service similar to Stack Overflow or Quora and deploy it to Google App Engine. In the process, we'll explore techniques, patterns, and practices that can be applied to all such applications, as well as dive deep into some of the more useful services available to our application.
Specifically, in this chapter, you will learn:
app.yaml
to configure your applicationIn order to run and deploy Google App Engine applications, we must download and configure the Go SDK. Head over to https://cloud.google.com/appengine/downloads and download the latest Google App Engine SDK for Go for your computer. The ZIP file contains a folder called go_appengine
, which you should place in an appropriate folder outside of your GOPATH
, for example, in /Users/yourname/work/go_appengine
.
It is possible that the names of these SDKs will change in the future; if that happens, ensure that you consult the project home page for notes pointing you in the right direction at https://github.com/matryer/goblueprints.
Next, you will need to add the go_appengine
folder to your $PATH
environment variable, much like what you did with the go
folder when you first configured Go.
To test your installation, open a terminal and type this:
goapp version
You should see something like the following:
go version go1.6.1 (appengine-1.9.37) darwin/amd64
The goapp
command is a drop-in replacement for the go
command with a few additional subcommands; so you can do things like goapp test
and goapp vet
, for example.
In order to deploy an application to Google's servers, we must use the Google Cloud Platform Console to set it up. In a browser, go to https://console.cloud.google.com and sign in with your Google account. Look for the Create Project menu item, which often gets moved around as the console changes from time to time. If you already have some projects, click on a project name to open a submenu, and you'll find it in there.
When the New Project dialog box opens, you will be asked for a name for your application. You are free to call it whatever you like (for example, Answers), but note the Project ID that is generated for you; you will need to refer to this when you configure your app later. You can also click on Edit and specify your own ID, but know that the value must be globally unique, so you'll have to get creative when thinking one up. In this book, we will use answersapp
as the application ID, but you won't be able to use that one since it has already been taken.
You may need to wait a minute or two for your project to get created; there's no need to watch the page you can continue and check back later.
Now that the Google App Engine SDK for Go is configured and our application has been created, we can start building it.
In Google App Engine, an application is just a normal Go package with an init
function that registers handlers via the http.Handle
or http.HandleFunc
functions. It does not need to be the main
package like normal tools.
Create a new folder (somewhere inside your GOPATH
folder) called answersapp/api
and add the following main.go
file:
package api import ( "io" "net/http" ) func init() { http.HandleFunc("/", handleHello) } func handleHello(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "Hello from App Engine") }
You will be familiar with most of this by now, but note that there is no ListenAndServe
call, and the handlers are set inside the init
function rather than main
. We are going to handle every request with our simple handleHello
function, which will just write a welcoming string.
In order to turn our simple Go package into a Google App Engine application, we must add a special configuration file called app.yaml
. The file will go at the root of the application or module, so create it inside the answersapp/api
folder with the following contents:
application: YOUR_APPLICATION_ID_HERE version: 1 runtime: go api_version: go1 handlers: - url: /.* script: _go_app
The file is a simple human-(and machine) readable configuration file in YAML (Yet Another Markup Language format refer to yaml.org for more details). The following table describes each property:
Property |
Description |
|
The application ID (copied and pasted from when you created your project). |
|
Your application version number you can deploy multiple versions and even split traffic between them to test new features, among other things. We'll just stick with version 1 for now. |
|
The name of the runtime that will execute your application. Since this is a Go book and since we're building a Go application, we'll use |
|
The |
|
A selection of configured URL mappings. In our case, everything will be mapped to the special |
Before we deploy our application, it makes sense to test it locally. We can do this using the App Engine SDK we downloaded earlier.
Navigate to your answersapp/api
folder and run the following command in a terminal:
goapp serve
You should see the following output:
This indicates that an API server is running locally on port :56443
, an admin server is running on :8000
, and our application (the module default
) is now serving at localhost:8080
, so let's hit that one in a browser.
As you can see by the Hello from App Engine
response, our application is running locally. Navigate to the admin server by changing the port from :8080
to :8000
.
The preceding screenshot shows the web portal that we can use to interrogate the internals of our application, including viewing running instances, inspecting the data store, managing task queues, and more.
To truly understand the power of Google App Engine's NoOps promise, we are going to deploy this simple application to the cloud. Back in the terminal, stop the server by hitting Ctrl+C and run the following command:
goapp deploy
Your application will be packaged and uploaded to Google's servers. Once it's finished, you should see something like the following:
Completed update of app: theanswersapp, version: 1
It really is as simple as that.
You can prove this by navigating to the endpoint you get for free with every Google App Engine application, remembering to replace the application ID with your own: https://YOUR_APPLICATION_ID_HERE.appspot.com/
.
You will see the same output as earlier (the font may render differently since Google's servers will make assumptions about the content type that the local dev server doesn't).
A module is a Go package that can be versioned, updated, and managed independently. An app might have a single module, or it can be made up of many modules, each distinct but part of the same application with access to the same data and services. An application must have a default module even if it doesn't do much.
Our application will be made up of the following modules:
Description |
The module name |
The obligatory default module |
default |
An API package delivering RESTful JSON |
api |
A static website serving HTML, CSS, and JavaScript that makes AJAX calls to the API module |
web |
Each module will be a Go package and will, therefore, live inside its own folder.
Let's reorganize our project into modules by creating a new folder alongside the api
folder called default
.
We are not going to make our default module do anything other than use it for configuration, as we want our other modules to do all the meaningful work. But if we leave this folder empty, the Google App Engine SDK will complain that it has nothing to build.
Inside the default
folder, add the following placeholder main.go
file:
package defaultmodule func init() {}
This file does nothing except allow our default
module to exist
The other module in our application will be called web
, so create another folder alongside the api
and default
folders called web
. In this chapter, we are only going to build the API for our application and cheat by downloading the web module.
Head over to the project home page at https://github.com/matryer/goblueprints, access the content for Second Edition, and look for the download link for the web components for
Chapter 9, Building a Q&A Application for Google App Engine in the Downloads section of the README
file. The ZIP file contains the source files for the web component, which should be unzipped and placed inside the web
folder.
Now, our application structure should look like this:
/answersapp/api /answersapp/default /answersapp/web
To specify which module our api
package will become, we must add a property to the app.yaml
inside our api folder. Update it to include the module
property:
application: YOUR_APPLICATION_ID_HERE version: 1 runtime: go module: api api_version: go1 handlers: - url: /.* script: _go_app
Since our default module will need to be deployed as well, we also need to add an app.yaml
configuration file to it. Duplicate the api/app.yaml
file inside default/app.yaml
, changing the module to default
:
application: YOUR_APPLICATION_ID_HERE version: 1 runtime: go module: default api_version: go1 handlers: - url: /.* script: _go_app
In order to route traffic appropriately to our modules, we will create another configuration file called dispatch.yaml
, which will let us map URL patterns to the modules.
We want all traffic beginning with the /api/
path to be routed to the api
module and everything else to the web
module. As mentioned earlier, we won't expect our default
module to handle any traffic, but it will have more utility later.
In the answersapp
folder (alongside our module folders not inside any of the module folders), create a new file called dispatch.yaml
with the following contents:
application: YOUR_APPLICATION_ID_HERE dispatch: - url: "*/api/*" module: api - url: "*/*" module: web
The same application
property tells the Google App Engine SDK for Go which application we are referring to, and the dispatch
section routes URLs to modules.
18.226.172.200