Create custom GO module with Examples [Step-by-Step]

In this article, we are going to create a simple module in Go.

 

What is a Go Module?

A module is a collection of Go packages stored in a file tree. It has several Go code files implementing the functionality of a package, but it also has two specific and important files in the root: the go.mod file and the go.sum file. These files contain information the go tool uses to keep track of your module’s configuration and are commonly maintained by the tool so you don’t need to. The go.sum file is autogenerated dependencies lock file.

Advertisement

Modules allow us to define precise dependency requirements and design reproducible builds for multiple environments.

Go has a very flexible module system that enables third-party modules to be downloaded from respective repositories into a cache which is located by default in the go subdirectory of the home directory. All Golang versions from 1.11 support the use of modules.

 

Go module Commands

The go tool provides several commands that are related to modules.

  • go mod init - initializes new module in the current directory
  • go mod tidy - adds missing and removes unused modules
  • go mod download - downloads modules to the local cache
  • go mod vendor - makes vendored copy of dependencies
  • go mod graph - prints module requirement graph
  • go mod verify - verifies dependencies have expected content
  • go mod why - explains why packages or modules are needed
  • go list -m - list all available modules.
  • go get -u - used to install dependencies and update the go.mod file.
  • go build - command to compile the code into an executable binary file.
  • go test - command executes test functions (whose names begin with Test) in test files (whose names end with _test.go). You can add the -v flag to get verbose output that lists all of the tests and their results

 

Creating a custom Go Module

Now, we will create an example Go module. We will call it GoLinuxCloud. First, we need to create a folder inside the GOPATH src directory. Now, we need to have a go.mod file in that directory that will allow us to manage dependency for this module.

 

Step-1: Define GOPATH Environment Variable

The Go path is used to resolve import statements. The GOPATH environment variable lists places to look for Go code. On Unix, the value is a colon-separated string. On Windows, the value is a semicolon-separated string.

GOPATH is a variable that defines the root of your workspace. By default, the workspace directory is a directory that is named go within your user home directory (~/go for Linux and MacOS, %USERPROFILE%/go for Windows). GOPATH stores your code base and all the files that are necessary for your development. Learn more about GOPATH Configuration

Advertisement

Execute "go env GOPATH" to see the current GOPATH. In most cases, GOPATH is the root of your workspace and contains the following folders:-

  • src/:- location of Go source code (for example, .go, .c, .g, .s).
  • pkg/:- location of compiled package code (for example, .a).
  • bin/:- location of compiled executable programs built by Go.

 

Step-2: Configuring GOPATH for different scopes

You can configure GOPATH for the following scopes:

  • Global GOPATH:-settings apply to all projects of a specific installation of GoLang.
  • Project GOPATH:-settings apply only to the current project.
  • Module GOPATH:-settings apply only to one module. A module can have an SDK that is different from those configured for a project. They can also carry a specific technology or a framework.

 

Step-3: Create directory structure for custom module

Create a directory called golinuxcloud for our Go module source code. This is where we all our code will be held and called and create a directory for greeting this will be inside the main directory golinuxcloud

$ mkdir golinuxcloud
$ cd golinuxcloud
$ mkdir greeting

Following is our directory structure

/
|-- golinuxcloud/
|--|-- greeting/

Create all files required for our module

$ cd golinuxcloud
$ mkdir greeting && touch main.go
$ cd greeting && touch greeting.go && touch greeting_test.go

 

Here, we have created all required files and folders, our structure looks like

Go module structure

 

Step-4: Initializing our custom go module

To do it, run this command.

go mod init golinuxcloud

After running this command we will get a go.mod file. Now, currently, we don’t have dependencies. But in any case, if we add it the mod file will get updated.

This is how modules simplify the package and dependency management in Go. Now, to get all the dependencies my package has, we run the following command:-

go list -m all

The output is for my case as follows:

$ go list -m all
golinuxcloud

Whenever we update its dependencies and run the test it will automatically fetch those packages without anything from our side. This is what makes modularization a very powerful tool in GoLang.

Get go.mod file content

$ cat go.mod 
module golinuxcloud
go 1.18

These are the contents of the go.mod file. We have the module path for the Go version.

 

Step-5: Create some sample Go module code

Then for simplicity’s sake add two files in the greeting folder namely greeting.go file and greating_test.go. One is general go code and the other is a testing file. main.go file is located at the root of the project golinuxcloud folder

Example at the greeting folder

// greeting.go
package greeting

import (
	"errors"
	"fmt"
)

// Greeting returns a greeting for the named person/organisation.
func Greeting(name string) (string, error) {
	// If no name was given, return an error with a message.
	if name == "" {
		return name, errors.New("The name is Empty ")
	}
	msg := fmt.Sprintf("Hello world from %s.", name)
	return msg, nil
}

Now, we run go main to see the result with a string input value

$ go run main.go "GoLinuxCloud"
Hello world from GoLinuxCloud.

Without an input string value/empty string

$ go run main.go ""          
The name is Empty

Explanation:-

Greeting():- It accepts string input value and return two outputs of type string and error. It checks if the input value is empty, then returns an error stating the name should not be empty, otherwise its returns a string containing a message of hello world from %name_passed.

Main():- We are using os package to pass a value without hardcoding value into our main function. The value is passed into Greeting() function and response stored in a res variable which is later printed on the screen using fmt package using println function.

// greeting_test.go
package greeting

import (
	"regexp"
	"testing"
)

// TestGreeting calls Greeting() with a name, checking for a valid return value.
func TestGreeting(t *testing.T) {
	name := "GoLinuxCloud"
	want := regexp.MustCompile(`\b` + name + `\b`)
	msg, err := Greeting("GoLinuxCloud")
	if !want.MatchString(msg) || err != nil {
		t.Fatalf(`Greeting("GoLinuxCloud") = %q, %v, want match for %#q, nil`, msg, err, want)
	}
}

// TestGreetingEmpty calls Greeting() with an empty string,checking for an error.
func TestGreetingEmpty(t *testing.T) {
	msg, err := Greeting("")
	if msg != "" || err == nil {
		t.Fatalf(`Greeting("") = %q, %v, want "", error`, msg, err)
	}
}

In this code above:-

  • Implement test functions in the same package as the code you're testing.
  • Create two test functions to test the Greeting function. Test function names have the form TestName, where the Name says something about the specific test. Also, test functions take a pointer to the testing package's testing. T type as a parameter. You use this parameter's methods for reporting and logging from your test.

Implement two tests:

  • TestGreeting calls the Greeting function, passing a name-value with which the function should be able to return a valid response message. If the call returns an error or an unexpected response message (one that doesn't include the name you passed in), you use the t parameter's Fatalf method to print a message to the console and end execution.
  • TestGreetingEmpty calls the Greeting function with an empty string. This test is designed to confirm that your error handling works. If the call returns a non-empty string or no error, you use the t parameter's Fatalf method to print a message to the console and end execution.

At the terminal in the golinuxcloud directory, run the go test command to execute the test.

  • The go test command executes test functions (whose names begin with Test) in test files (whose names end with _test.go). You can add the -v flag to get verbose output that lists all of the tests and their results.
  • The tests should pass.
$ go test
PASS
ok      golinuxcloud    0.005s

$ go test -v
=== RUN   TestGreeting
--- PASS: TestGreeting (0.00s)
=== RUN   TestGreetingEmpty
--- PASS: TestGreetingEmpty (0.00s)
PASS
ok      golinuxcloud    0.005s

main() function code

// main.go
package main

import (
	"golinuxcloud/greeting"
	"log"
	"os"
)

func main() {
	value := os.Args[1]
	res, err := greeting.Greeting(value)
	if err != nil {
		log.Println(err)
		os.Exit(0)
	}
	log.Println(res)
}

Explanation:-

  • Declare the main package. In Go, code executed as an application must be in the main package.
  • Import three packages: golinuxcloud/greeting, os and the log package. This gives your code access to functions in those packages. Importing golinuxcloud/greeting this package gives us access to the Greeting() function. We have imported log package, with functions for handling input and output text, i.e printing function to display either error message or results of the function being executed.
  • Get a greeting by calling the greetings package’s Greeting() function.
  • The os package enables us to exit from program once an error is encountered and reading of users inputs like the string being passed as argument into Greeting() function, we use os.Args[] function and os.Exit() function

 

Step-6: Compile code into executable binary file

At the root of the project, run go build command

$ go build

The above command will create an executable binary file same as the module name golinuxcloud. We execute the binary file by running as ./name_module

go run main.go "Golang study"

For Example

$./golinuxcloud ""
2022/06/22 14:41:32 The name is Empty

With string inputs, For Example

$./golinuxcloud "Golang study"
2022/06/22 14:42:05 Hello world from Golang study.

 

Summary

In this article, you’ve learned how to create a Go module, create tests and execute various go commands from version control systems, as well as build and cross-compile executables for different platforms.

 

References

How to create Go modules
modules in Go

 

Didn't find what you were looking for? Perform a quick search across GoLinuxCloud

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can either use the comments section or contact me form.

Thank You for your support!!

Leave a Comment

X