image
Go API
Start course
Difficulty
Intermediate
Duration
50m
Students
3095
Ratings
4.3/5
Description

This course is designed to help you master the skills of designing and building cloud-native applications.

Observe first hand the end-to-end process of building a sample cloud-native application using React, Go, MongoDB, and Docker. By taking this course you'll not only get to see firsthand the skills required to create a robust, enterprise-grade, cloud-native application, but you'll also be able to apply them yourself as all code and deployment assets are available for you to perform your own deployment:

Source Code:
https://github.com/cloudacademy/voteapp-frontend-react
https://github.com/cloudacademy/voteapp-api-go

Full Install Script:
https://github.com/cloudacademy/language-vote-app

 

Learning Objectives

What you'll learn:

  • Understand the basic principles of building cloud-native applications
  • Understand the benefits of using React for frontend web development
  • Understand the benefits of using Go for backend API development
  • Understand the benefits of using MongoDB as a database system
  • And finally, you’ll learn how to package and run microservices as lightweight containers using Docker

Demonstration

This training course provides you with several hands-on demonstrations where you will observe first hand how to

  • Build a React-based web frontend
  • Build a Go-based API
  • Deploy and configure a MongoDB database
  • Deploy the full end-to-end application to Docker running locally

Prerequisites

  • A basic understanding of web-based software development
  • Previous exposure to containers and containerization - in particular, docker

Intended Audience

  • Anyone interested in learning how to architect cloud-native applications
  • Anyone interested in using modern development tools such as React, Go, MongoDB and Docker
  • Anyone interested in containerization
  • DevOps Practitioners
Transcript

Okay, welcome back. In this lecture, we'll provide a functional review of the API in terms of listing out its full set of API endpoints, and how the API endpoints are worked with in terms of their request and response data structures. We'll then provide a code review of the important code parts contained within the implementation.

Just a quick note to remind you that all of the source code that makes up the Go-based API is available for you to clone from the following location. 

http://github.com/cloudacademy/voteapp-api-go/

Before we continue, why'd we choose Go for developing the API in the first place? Well, when it comes to building APIs, the Go language provides some really cool features that make it super easy to do so. For example, Go provides a feature-rich HTTP library all packaged in Go spec, which can be used to build and develop API endpoints served over HTTP. Secondly, Go provides cross-compilation abilities, meaning that a final runtime binary can be compiled for various operating systems and hardware.

Additionally, Go compiles down to a single executable binary with all third-party libraries and all dependencies compiled into the binary itself. This makes it super simple to copy and set up the runtime requirements for the software that you develop within Go. Typically, all you need to do is copy and execute the single binary file. This makes it an excellent choice for building cloud-native back-end services or APIs. And it is for these reasons it was chosen to build the API. Okay, let's move on now and document each of the API endpoints. For starters, the full list of API endpoints are shown here:

GET /languages
GET /languages/{name}
GET /languages/{name}/vote
GET /ok
POST /languages/{name}
DELETE /languages/{name}

All API endpoints receive and respond with JSON encoded data. 

We'll now review each endpoint individually and give quick examples of how they are called and the data that is returned. The /languages API endpoint is called using a standard HTTP GET request. This is used to retrieve the current collection of programming languages maintained in the database. The /languages/{name} API endpoint is called using a standard HTTP GET request. This is used to retrieve a single named programming language stored in the database. This API call will return a JSON document containing a single programming language. The frontend uses the /languages/{name} API endpoint to retrieve and render the details for a named programming language. The /languages/{name}/vote API endpoint is called using a standard HTTP GET request. This is invoked by the frontend when the user clicks on the +1 voting button and it will result in a vote being applied to a single named ProgrammingLanguage document currently stored in the database. This API call will return a JSON document indicating successful failure for the vote being applied to the document in question within the database. The /ok API endpoint is called using a standard HTTP GET request. This API call will return the static string OK. This API endpoint is used for health checks. The /languages/{name} API endpoint can also be called using a standard HTTP POST request. This is used to create a new named programming language within the database. This API call will take the JSON document posted within the body of the request and write it into the MongoDB database together with the name. The response for this call will be a JSON document representing the success outcome of this action. 

The /languages/{name} API endpoint can also be called using a standard HTTP DELETE request. This is used to delete an existing named programming language from the database. This API call will return a JSON document containing a count of the number of documents with the matching name that were then deleted from the database successfully. Okay, next we'll review and examine the Go code that has been used to implement the create, read, update, delete, RESTful styled API. In particular, we'll review the following set of files: main.go and the Dockerfile.

Okay, the API that we have created for this sample application is implemented within the single main.go source file. This file contains the entire create, read, update, delete API implementation written using the Go language. We won't go through it line by line, but instead we'll call out each of the key features.

For starters, at the top of the file, we import several third-party packages. We leverage the gorilla mux library to manage the incoming API requests and map them to corresponding functions. The gorilla mux package implements a request router and dispatcher for matching incoming requests to their respective handlers. Handlers are created for each of the API endpoints. The gorilla handlers package implements, amongst other things, CORS, or Cross-Origin Resource Sharing management. 

The API uses this to manage and authenticate incoming AJAX requests sent from the web frontend. The go.mongodb.org/mongo-driver-related packages are used to provide connectivity to read and write data to the back-end MongoDB database. The net/http package implements HTTP connectivity and is used by the API to provide an HTTP interface. Within the main.go source file, we define a number of constants which hold default values for the connectivity to the back-end MongoDB database. In particular, we track the following values:

  • MONGO_DB. This is the name of the MongoDB database that is used by the sample application.
  • MONGO_COLLECTION. This is the name of the MongoDB collection that is used within the database by the sample application.
  • MONGO_DEFAULT_CONN_STR defines the default connection string used to connect to a MongoDB database. By default, this holds the connection string for a replicaSet deployment, which we'll undertake in the Kubernetes cluster within the next course.
  • MONGO_DEFAULT_USERNAME and _PASSWORD are the default authentication credentials used if authentication is enabled within the MongoDB service. Two custom struct types are declared near the top of the main.go file. 

As seen here, the first custom struct type is named codedetail. This is used to store all of the related attributes for a single programming language. For example, it contains fields for usecase, rank, compiled, homepage, download, and additionally, votes, which tracks the number of votes submitted. The second custom type is named language. This is merely just a wrapper over the previous codedetail struct and includes an extra field named name to track the programming language name. 

Both custom structs are tagged using string literal tags for JSON and BSON. This is used at runtime and tells the code how to marshall and unmarshall JSON and BSON. JSON is used on the wire to transport the data to and from the API endpoints. MongoDB represents JSON documents in a binary-encoded format called BSON. BSON extends the JSON model to provide additional datatypes, ordered fields, and to be efficient for encoding and decoding with different languages such as Go. 

Together, both structs work in unison to provide the overall document structure as used internally within the API. A variable c is declared and used to represent a pointer to the mongo.Client datatype. This mongo.Client is later configured within the init function which is called first, automatically at runtime. As just mentioned, the init function is called automatically by Go, right at the start of execution. The init function calls the getClient function and assigns the response to c. 

The getClient function is responsible for establishing a MongoDB connection and does so using the official MongoDB driver as implemented within the go.mongodb.org/mongo-driver related packages. A check is made within the function to see if knowingly named environment variables have been set within the shell that launches the API executable. If so, these values are retrieved and are used in place of their defaults. The only other point of interest in this function is the check to see whether the MongoDB servers that we are connecting has been configured with authentication in place and is therefore expecting the client to authenticate. The main function is responsible for matching incoming requests to their respective function handlers using gorilla mux. 

Handlers are created for each of the API endpoints. Additionally, some CORS or Cross-Origin Resource Sharing management is done to allow incoming AJAX requests from the frontend. The main function finally launches the internal HTTP servers and is configured to listen for incoming requests on port 8080. The remainder of the API functions, as declared within the main.go file, come in pairs, a pair per API endpoint. They are fairly self-explanatory and it is left for you to review. Note, the voteonlanguage and voteChannel functions as used by the last API endpoint seen here, implement a simple Go channel to pass data between themselves. Using a Go channel for the vote API is done so this way for no other reason than to demonstrate how Go channels can be used. 

Let's take a look at these two functions closer. The voteonlanguage function calls the voteChannel function which returns a Go channel. The programming language name string is then put into the channel. The name string is then processed by an anonymous Go routine declared within the voteChannel function. This function places a votesUpdated count back into the channel which is then read back off the channel and finally, JSON encoded and transmitted back on the wire as a response for the corresponding API call. The Dockerfile now shown here will be used to build the API microservice container image.

The Docker image will contain the Go API executable as per the copy instruction. At runtime, the API container will launch the API executable and expose port 8080, which maps to the listening port implemented within the API binary. Again, the key takeaway from this Dockerfile is its simplicity by design. 

Okay, that completes this lecture on a brief functional and code review of the API component.

Go ahead and close this lecture and we'll see you shortly in the next one where we'll perform a quick configuration review of the MongoDB setup.

About the Author
Students
143181
Labs
69
Courses
109
Learning Paths
209

Jeremy is a Content Lead Architect and DevOps SME here at Cloud Academy where he specializes in developing DevOps technical training documentation.

He has a strong background in software engineering, and has been coding with various languages, frameworks, and systems for the past 25+ years. In recent times, Jeremy has been focused on DevOps, Cloud (AWS, Azure, GCP), Security, Kubernetes, and Machine Learning.

Jeremy holds professional certifications for AWS, Azure, GCP, Terraform, Kubernetes (CKA, CKAD, CKS).