Running Ionic With A Go Web Server

Ionic is an open source framework for building websites and mobile apps in one. With Ionic it is possible to code once and deploy to all. Go is the best language I have ever used. Go compares to C++ in speed and Java in readability. Go is cleaner, more precise, builds in seconds, seems to excel at every task, and has channels. Let’s not forget about Go channels. This article though is not about channels, it is about how to take advantage of both Ionic and Go in a single project. The best web app framework paired with the best programming language.

Getting started

For this tutorial you will need a development environment and a browser. I am using Brave because I enjoy my privacy and we will make use of Visual Studio Code which offers plugins for Go development: intelliSense, short cuts, etc.  Visual Studio Code is also significantly faster than the Community Edition, albeit serving a slightly different purpose. You will also need to install Go onto your machine. If you are unsure how to do this, I have written another article with installation instruction here. Go ahead and open up Visual Studio Code and install Go support.

Next, create a new file which we will save as “main.go” inside your Go workspace. For this example, I am going to save my main.go file to a folder named “IONIC_GO” inside my workspace. IONIC_GO will be my project folder. My folder and file structure now appears like this:

Setting Up Our Go Server

There are three parts we must have to make a Go server. We will need a package name, required imports and a main function which will serve any Http requests. We will name our package “main”, import three packages, and have a few functions to separate our logic inside our server application. The package we will make use of are:

  • net/http, “Package http provides HTTP client and server implementations.” – source
  • fmt, Package fmt implements formatted I/O with functions analogous to C’s printf and scanf. The format ‘verbs’ are derived from C’s but are simpler. – source
  • io/ioutil, “Package ioutil implements some I/O utility functions.” – source

Just to make sure you understand; the “net/http” package is required to take on the request and write out a response interacting with the Http protocol. The package “fmt” is used for writing, this can be writing text to a console, a web page, or writing out the contents of an html document. Last, “io/ioutil” is used for accessing files, reading and writing to them. Without this package we would not be able to access our ionic project.

When we write our package and imports listed above, our code should look like this:

package main    
import (
    "net/http"
    "fmt"
    "io/ioutil"
)

You’ll notice the imports are shown in red. This is because we have not made use of our imports and Go being very efficient doesn’t allow us to waste memory by calling unused imports. Let’s write our main function and a struct to organize. Go’s structs are akin to traditional OOP classes, like Java, except much more powerful. Our struct will have one type of byte array which will hold the contents our io reader takes in.

type Page struct {
    Body  []byte
}
func main() {
    //do something
}

Inside of our main function we will need to handle a request route and define our port. For this example, in keeping with my tradition we will use port 9090 and define only a single route. I will also define a single handler named “indexHandler” and let it return “Hello World” so we can see it is working. Our indexHandler will take in two parameters, one of our writer and another of our request. We must pass both our writer and text to Fprintf in order to write to the browser.

func main() {
    http.HandleFunc("/", indexHandler)    
    http.ListenAndServe(":9090", nil)
}
func indexHandler(w http.ResponseWriter, r *http.Request){
    fmt.Fprintf(w, "Hello World")
}

At this point we have a working web server. To see it running, comment out io/ioutil since we haven’t used this yet and open a command terminal. After navigating to your project run the commands:

$ go build main.go

$ main.exe

$ represents the go project workspace, IONIC_GO

Navigate to http://localhost:9090/ and you should see “Hello World” in the top left corner of the page. Great, it’s running, let’s start adding Ionic!

Building Ionic

You will need to install Ionic onto your machine. Ionic uses node to install, so although we aren’t using node for our project you will need it to get ionic. You can find the very simple instructions here. Once you have Ionic and Node installed, you are ready to start an Ionic project. We will put our Ionic project inside our IONIC_GO project folder. With our terminal run the command to install Ionic.

$ ionic start myApp tabs

$ represents the go project workspace, IONIC_GO

To make sure that ionic is installed properly, we can go ahead and use node to serve it to the browser. Navigate to our ionic directory.

cd myApp

. Run these commands to build, then serve our ionic project to ensure proper setup.

$ ionic build

$ ionic serve

When you are asked “Would you like to integrate your new app with Cordova to target native iOS and Android?” select “N”. The scope of this article does not include IOS or android. And then when asked “Install the free Ionic Pro SDK and connect your app?” also select “n”. While this is great, we aren’t covering it right now. Once Node is up, a browser window will open to http://localhost:8100/ and display our Ionic tabs application. We aren’t here for Node though, so shut it down Ctrl-c in the terminal and navigate back to our project folder, IONIC_GO. Next, we are going to add a function to read from our Ionic project and serve it. I will call this function “loadPage” and it will be directed to a specific initial file, in this case the ionic index.html found in the www folder. Our page loading function will also read that index file, handle errors and return the contents of the file to our browser. This function will require dependencies from our Page struct and built-in error type. This function will return our Page struct populated with the bytes of the index.html file. The & symbol in Go is a pointer to the struct. Our code will look like this.

func loadPage() (*Page, error) {
    filename := "./myApp/www/index.html"
    body, err := ioutil.ReadFile(filename)
    if err != nil {
        return nil, err
    }
    return &Page{Body: body}, nil
}

Now, we will need to modify our “indexHandler” to make use of this function. Call our “loadPage” function and write on the contents:

func indexHandler(w http.ResponseWriter, r *http.Request){
    p, _ := loadPage()
    fmt.Fprintf(w, "%s", p.Body)
}

The complete main.go code

package main    
import (
    "net/http"
    "fmt"
    "io/ioutil"
)
type Page struct {
    Body  []byte
}
func main() {
    http.HandleFunc("/", indexHandler)    
    http.ListenAndServe(":9090", nil)
}
func indexHandler(w http.ResponseWriter, r *http.Request){
    p, _ := loadPage()
    fmt.Fprintf(w, "%s", p.Body)
}
func loadPage() (*Page, error) {
    filename := "./myApp/www/index.html"
    body, err := ioutil.ReadFile(filename)
    if err != nil {
        return nil, err
    }
    return &Page{Body: body}, nil
}

The Last Important Step To Remember

Inside our index.html of our Ionic project you will normally see the relative paths as “build/[resource]”. We need these to known where our root Ionic folder is. To do this replace “build” with “./myApp/www/build”. If you do not do this, when the index.html file is loaded into the browser, it will have the correct page title, but the page contents will not load since the javascript resources could not be found to load into Ionics <ion-app> tag.

Also, whenever you rebuild your Ionic application $ ionic build you will need to perform this step again. The Ionic build process will reset these paths to the relative “build” path and they will not load again.
I will probably add a function to rewrite these paths and update this article shortly. One fix is so put the following code into the head to rewrite the base href.
<script>document.write('<base href="' + document.location + '" />');</script>
Now we can run our application and view it live in the browser.
$ go build main.go

$ main.exe
 
The complete project can be found here on GitHub.

A Web Developer by trade, find me on Github
A motorcycle enthusiast at heart.
Most days I’d rather be in the woods anywhere.