Last year I blogged about creating a Lean Mean Vue Machine called Quotes on Demand. The application was a fully-featured CRUD application served from a NodeJS server and had a self-contained VueJS front end. Since then I’ve also added a Python version of the same API.
But wouldn’t it be a nice test to see if that same Vue application could switch over to another API – say, something like a Golang application server?
In this post, we will create a Go application server that will have 100% parity to an existing NodeJS web application. This will enable an existing VueJS front end to connect to the application with no additional code changes in the user interface code.
What is Go?
Golang, or simply Go, is a C-style language created by Google back in 2003. It’s a little simpler than that, though. The language is typed (meaning it has integers and strings), but it’s also a terse language with Structs and For Loops used exclusively instead of Classes and ForEach Loops. The language sounded challenging, so I decided to take it for a spin.
Application Goals
This application was created with these three goals in mind:
- To create a Go application server that has 100% parity of the original NodeJS server. All CRUD functionality would be the same using the same JSON data file as the original.
- To enable the VueJS application from Quotes on Demand to “just work” with the Go server. Basically, all front end functionality would be exactly the same with no changes to the existing application logic.
- To continue to allow the VueJS application stand alone outside of the Gong server.

Application Structure
The application structure is actually quite simple; it’s broken into two distinct sections: the UI and the API. Since we are building a new API for this application, we will focus on that section. For more information about the UI, please reference the Lean Mean Vue Machine blog entry.
The API folder is a fully self-contained Go application server that will load a selection of quotes up into an in-memory collection that will allow connecting parties to do the five main CRUD actives such as:
1 /quote | GET | returns all quotes 2 /quote/{id} | GET | returns a specific quote by 'id' 3 /quote | POST | adds a new quote 4 /quote/{id} | PUT | updates a quote 5 /quote/{id} | DELETE | deletes a quote
This server is CORS enabled, so all endpoints are open to public consumption, and there is no security on the endpoints for simplicity. The quotes API itself does support proper HTTP verb endpoints.
Application Building Process
Our application needed to have Go libraries installed to make the API server development easier to work with.
github.com/gorilla/handlers // used for CORS
github.com/gorilla/mux // used for routing
The first file created was named main.go
. Notice that all of the Go files are suffixed with the dot go
extension to designate them as a Go file.
api/main.go
package main import ( "fmt" "github.com/gorilla/handlers" "github.com/gorilla/mux" "log" "net/http" "quotes-on-demand-go/library" ) func HealthCheck(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "API is alive and ready") } func main() { library.LoadData() router := mux.NewRouter() router.HandleFunc("/quote/", library.GetQuote).Methods("GET") router.HandleFunc("/quote/{id}", library.GetQuoteById).Methods("GET") router.HandleFunc("/quote/", library.CreateQuote).Methods("POST") router.HandleFunc("/quote/", library.UpdateQuote).Methods("PUT") router.HandleFunc("/quote/{id}", library.DeleteQuote).Methods("DELETE") router.HandleFunc("/", HealthCheck).Methods("GET") var port = ":5000" print("Listening And Serving on " + port) log.Fatal(http.ListenAndServe(port, handlers.CORS( handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type", "Authorization"}), handlers.AllowedMethods([]string{"GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS"}), handlers.AllowedOrigins([]string{"*"}))(router))) }
Code Explanations
From top to bottom, I’ll explain the code.
First, we import mux
and handlers
from our included dependencies, along with several other standard library items. Then, we import a second Go package file, which was created to hold the actual CRUD functionality.
We then create a simple HealthCheck
function for the root route of the application so that later, we can easily see if the server is up and running.
Next, we create our main
function, which is the actual entry point to the application. Inside the main
function, six routes have been created. Five are CRUD routes: (1) a GET
all function, (2) a GET BY ID
function, (3) a POST
for creating a new quote, (4) a PUT
for updating a quote and a delete for removing a quote from the collection, and (5) a root
route function (created using our health check
function from earlier) to notify the calling applications that the API is up and running.
Notice, in our five CRUD routes, only functions from our imported library
package are referenced. This separation makes our actual routes much cleaner and easier to read.
Lastly, we have our log.Fatal
function which accepts our startup for the HTTP server on a given port, along with setting up the handlers
from our imported package from earlier. Handlers\
is used here to set headers
, origins
, and methods
for Cross Origin Requests (CORS)
.
Now, let’s take a look at the functionality held within crud.go
.
api/library/crud.go
package library import ( "encoding/json" "fmt" "github.com/gorilla/mux" "io/ioutil" "net/http" "strconv" ) // this is our data structure type Quote struct { Id int `json:"id"` Author string `json:"author"` Text string `json:"text"` } // our `splice` collection for the filled Quotes var data []Quote // this is a private function to this file because it is not Capitalized func findHighestId() int { maxId := data[0].Id for _, v := range data { if v.Id > maxId { maxId = v.Id } } return maxId } // load the JSON data file for usage. func LoadData() { var content, err = ioutil.ReadFile("data.json") if err != nil { fmt.Println(err.Error()) } json.Unmarshal(content, &data) } // the following are the actual CRUD endpoint functions func GetQuote(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(data) } func GetQuoteById(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") // Get our params from the URL using Mux params := mux.Vars(r) // using this atoi method to parses the string into an integer requestId, _ := strconv.Atoi(params["id"]) // Loop through collection of quotes and find one with the id from the params // the underscore is basically read as `for each item in the collection` for _, item := range data { if item.Id == requestId { json.NewEncoder(w).Encode(item) return } } json.NewEncoder(w).Encode(&Quote{}) } func CreateQuote(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") quote := Quote{} _ = json.NewDecoder(r.Body).Decode("e) quote.Id = findHighestId() + 1 data = append(data, quote) json.NewEncoder(w).Encode(quote) } func UpdateQuote(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") quote := Quote{} _ = json.NewDecoder(r.Body).Decode("e) // when you have the `index` defined, you have the actual index of the item from the splice for index, item := range data { if item.Id == quote.Id { // this is very similar to a splice in JavaScript (same idea) data = append(data[:index], data[index+1:]...) data = append(data, quote) json.NewEncoder(w).Encode(quote) return } } } func DeleteQuote(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") params := mux.Vars(r) requestId, _ := strconv.Atoi(params["id"]) for index, item := range data { if item.Id == requestId { data = append(data[:index], data[index+1:]...) break } } json.NewEncoder(w).Encode(data) }
The crud.go
file is pretty straight forward. We’re going to have five functions for each of the CRUD functions that exist in the main.go
file.
Code Explanations
Once again, from top to bottom, I’ll explain the code.
First, we import the JSON utilities from the Golang standard libraries so that we can work with our JSON data collection. Then, we open that JSON file, and we load it into a local variable called data
. This will be our in-memory database for everything we’re doing later.
You will notice that we have created an item called a struct
in Golang. This is used to demonstrate what a Quote will look like inside the application. We also have another function called findHighestId
. This is a simple utility function used to find the highest id
from the objects within the data collection. In Go, capitalization is very important. Because this function starts with a lowercase letter, the function is private to the package. A function that starts with an uppercase letter, on the other hand, is able to be accessed outside of the package. You will see this style used in the following crud
functions.
Our first crud
function is for our get quote
endpoint, and we perform a simple dump of all the data and send it back as JSON.
The next function is our get by id
function. Here, we’re looking for an id
to be passed in from the endpoint. We cast that variable into an integer, and then we compare it to all found id
s within the data collection. If one happens to be found, we’re sending that one back to the endpoint as JSON. Note that we use mux
here to access the parameters passed in on the URL.
Our third function is to create a new quote by utilizing the private function to find the highest ID of our quotes collection. Immediately after that, we use the returned max value function to increment that key one step up and assign that to the newly created quote. The newly-created quote passed in on the function is then appended to the data collection, and we return the data as JSON to the endpoint.
The fourth function is used for updating an item in the data collection. We create a For Loop here with two variables. The first variable is used for the indexer of the loop, and the second is the item in the loop. We use Go’s range
function and turn our data into a collection which can be iterated upon.
Now we compare the id
of each item in the collection to the quote’s id
. If they match, we delete the existing data from the collection. Then, we use the quote
variable and insert the updated item back into the data collection at the same point.
Our last function in this file is used to delete an item. The function is passing in an id
, we’re going to loop over the data collection and check each item’s id
against the passed-in one. If one matches, we use the append
function on the collection and delete that item. Once that’s complete, we return the modified collection back to the endpoint as JSON.
Finally, we now have the actual JSON file.
api/data.json
{ "id": 5, "author": "Stephen King", "text": "Get busy living or get busy dying." },
This is just a small snippet, but all of the rows follow in this same fashion by having an ID
, an AUTHOR
, and a TEXT
property.
Go to a Conclusion
And that’s all we need for a fully functional CRUD API built in Golang.
The goal of this project was to build a Go API with parity that matched with the original Quotes on Demand Node server. With just a little research on finding ways to use Mux for our routing and seeing how to manipulate collections, we were able to successfully complete our mission. Golang is a simple but powerful language and this project shows great potential for expansion.
For more information about the VueJS user interface used here, see Lean Mean Vue Machine found on the Keyhole Software blog. If you would like to read further about Go and it’s usage with a full scale application, or want to see how to connect it with a database, check out the Keyhole Software blog’s Go topic for more information.