Sign In
Sign In

Using Interfaces in Go

Using Interfaces in Go
Hostman Team
Technical writer
Go
06.12.2024
Reading time: 10 min

In object-oriented programming (OOP), the concept of interfaces plays a key role and is closely associated with one of the foundational principles—encapsulation.

Interface as a Contract

Simply put, an interface is a contract that defines the expected behavior between system components, such as how they exchange information. A real-world analogy for this concept can be seen in the Unix philosophy of "Everything is a file." This principle represents access to various resources—documents, peripherals, internal processes, and even network communication—as byte streams within the file system namespace.

The advantage of this approach is that it allows a wide range of tools, utilities, and libraries to work uniformly with many types of resources. In OOP, an interface describes the structure of an object but leaves out implementation details.

Interfaces in OOP Languages and Go

Unlike languages like Java, C++, or PHP, Go is not a classically object-oriented language. When asked if Golang is OOP, the creators give an ambiguous answer: "Yes and no." While Go includes types and methods and supports an object-oriented programming style, it lacks class hierarchies (or even classes themselves), and the relationship between concrete and abstract (interface) types is implicit, unlike languages such as Java or C++.

In traditional OOP languages, implementing an interface involves explicitly declaring that a class conforms to it (e.g., public class MyClass implements MyInterface). The implementing class must also define all methods described in the interface, matching their declared signatures exactly.

In Go, there is no need for an explicit declaration that a type implements an interface. As long as a type provides definitions for all the methods specified in the interface, it is considered to implement that interface.

In the Java example below, the class Circle is not an implementation of the interface Shape if the class description does not explicitly declare that it implements the interface, even if it contains methods matching those in Shape. In contrast, the class Square would be recognized as a Shape implementation because it explicitly declares so.

// Shape.java

interface Shape {
    public double area();
    public double perimeter();
}
// Circle.java

public class Circle {
    private double radius;

    // constructor
    public Circle(double radius) {
        this.radius = radius;
    }

    public double area() {
        return this.radius * this.radius * Math.PI;
    }

    public double perimeter() {
        return 2 * this.radius * Math.PI;
    }
}
// Square.java

public class Square implements Shape {
    private double x;

    // constructor
    public Square(double x) {
        this.x = x;
    }

    public double area() {
        return this.x * this.x;
    }

    public double perimeter() {
        return 4 * this.x;
    }
}

We can easily verify this by creating a function calculate that accepts an object implementing the Shape interface as an argument:

// Calculator.java

public class Calculator {
    public static void calculate(Shape shape) {
        double area = shape.area();
        double perimeter = shape.area();

        System.out.printf("Area: %f,%nPerimeter: %f.");
    }

    public static void main() {
        Square s = new Square(20);
        Circle c = new Circle(10);

        calculate(s);
        calculate(c);
    }
}

If we try to compile such code, we will get an error:

javac Calculator.java
Calculator.java:16: error: incompatible types: Circle cannot be converted to Shape
        calculate(c);
                  ^
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error

In Golang, there is no requirement for a type to declare the interfaces it implements explicitly. It is sufficient to implement the methods described in the interface (the code below is adapted from Mihalis Tsoukalos's book "Mastering Go"):

package main

import (
    "fmt"
    "math"
)

type Shape interface {
    Area() float64
    Perimeter() float64
}

type Square struct {
    X float64
}

func (s Square) Area() float64 {
    return s.X * s.X
}

func (s Square) Perimeter() float64 {
    return 4 * s.X
}

type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return c.Radius * c.Radius * math.Pi
}

func (c Circle) Perimeter() float64 {
    return 2 * c.Radius * math.Pi
}

func Calculate(x Shape) {
    fmt.Printf("Area: %f,\nPerimeter: %f\n\n", x.Area(), x.Perimeter())
}

func main() {
    s := Square{X: 20}
    c := Circle{Radius: 10}

    Calculate(s)
    Calculate(c)
}

Area: 400.000000,
Perimeter: 80.000000

Area: 314.159265,
Perimeter: 62.831853

If we try to use a type that does not implement the Shape interface as an argument for the Calculate function, we will get a compilation error. It is shown in the following example, where the Rectangle type does not implement the Shape interface (the Perimeter method is missing):

package main

import "fmt"

type Shape interface {
    Area() float64
    Perimeter() float64
}

type Rectangle struct {
    W, H float64
}

func (r Rectangle) Area() float64 {
    return r.W * r.H
}

func Calculate(x Shape) {
    fmt.Printf("Area: %f,\nPerimeter: %f\n\n", x.Area(), x.Perimeter())
}

func main() {
    r := Rectangle{W: 10, H: 20}

    Calculate(r)
}

./main.go:25:12: cannot use r (variable of type Rectangle) as type Shape in argument to Calculate:
    Rectangle does not implement Shape (missing Perimeter method)

Notice how the Golang language compiler provides a more informative error message, unlike the Java language compiler.

Problems and Solutions

On the one hand, this approach to interface implementation simplifies writing programs, but on the other hand, it can become a source of errors that are sometimes hard to catch.

Let’s look at an example. While working on a client library for a popular API, we needed to implement a caching mechanism — saving already retrieved data locally "on the client" to avoid repeated requests to the remote API server. API access was provided within packages that had a limited number of requests per month, so using a caching mechanism was economically beneficial for users. However, since the use cases for this library weren't limited to just web applications (although that was the most common scenario), we couldn't implement a single caching strategy that would satisfy everyone. Even in the case of applications running within a web server, there are at least two (or even all three) caching options — in-memory caching and using something like Memcached or Redis. However, there are also CLI (command-line interface) applications, and the caching strategies that work well for web applications are not suitable for command-line ones.

As a result, we decided not to implement a single caching strategy, but to create our own interface listing methods for retrieving and storing data in the cache. We also wrote implementations of this interface for various caching strategies. This way, users of our library (other developers) could either use one of the implementations provided with the library or write their own custom implementation of the caching interface for their needs.

Thus, the situation arose where the interface implementation and its application were separated into different codebases: the implementations were in "our" library, while the application of the interface was in other developers' applications. Our task was to check that our own implementations were indeed correct implementations of our own interface.

Let's assume we have the cache.Interface interface and the cache.InMemory and cache.OnDisk types:

package cache

import (
    "encoding/json"
    "fmt"
    "os"
    "sync"
)

type Interface interface {
    Get(key string) (value []byte, ok bool)
    Set(key string, value []byte)
    Delete(key string)
}

type InMemory struct {
    mu    sync.Mutex
    items map[string][]byte
}

func NewInMemory() *InMemory {
    return &InMemory{
        items: make(map[string][]byte),
    }
}

func (c *InMemory) Get(key string) (value []byte, ok bool) {
    c.mu.Lock()
    value, ok = c.items[key]
    c.mu.Unlock()
    return value, ok
}

func (c *InMemory) Set(key string, value []byte) {
    c.mu.Lock()
    c.items[key] = value
    c.mu.Unlock()
}

func (c *InMemory) Delete(key string) {
    c.mu.Lock()
    delete(c.items, key)
    c.mu.Unlock()
}

type OnDisk struct {
    mu       sync.Mutex
    items    map[string][]byte
    filename string
}

func NewOnDisk(filename string) *OnDisk {
    return &OnDisk{
        items:    make(map[string][]byte),
        filename: filename,
    }
}

func (c *OnDisk) Get(key string) (value []byte, err error) {
    c.mu.Lock()
    defer c.mu.Unlock()

    f, err := os.Open(c.filename)
    if err != nil {
        return nil, err
    }
    defer f.Close()

    dec := json.NewDecoder(f)
    if err := dec.Decode(&c.items); err != nil {
        return nil, err
    }

    value, ok := c.items[key]
    if !ok {
        return nil, fmt.Errorf("no value for key: %s", key)
    }

    return value, nil
}

func (c *OnDisk) Set(key string, value []byte) error {
    c.mu.Lock()
    defer c.mu.Unlock()

    c.items[key] = value

    f, err := os.Create(c.filename)
    if err != nil {
        return err
    }

    enc := json.NewEncoder(f)
    if err := enc.Encode(c.items); err != nil {
        return err
    }

    return nil
}

func (c *OnDisk) Delete(key string) error {
    c.mu.Lock()
    defer c.mu.Unlock()

    delete(c.items, key)

    f, err := os.Create(c.filename)
    if err != nil {
        return err
    }

    enc := json.NewEncoder(f)
    if err := enc.Encode(c.items); err != nil {
        return err
    }

    return nil
}

Now we need to make sure that both of our types, cache.InMemory and cache.OnDisk, implement the cache.Interface. How can we achieve this? The first answer that comes to mind is to write a test.

Test

Let's write two small tests to check that our types cache.InMemory and cache.OnDisk implement the cache.Interface:

package cache

import "testing"

func TestInMemoryImplementsInterface(t *testing.T) {
    var v interface{} = NewInMemory()
    _, ok := v.(Interface)
    if !ok {
        t.Error("InMemory does not implement Interface")
    }
}

func TestOnDiskImplementsInterface(t *testing.T) {
    var v interface{} = NewOnDisk("cache.json")
    _, ok := v.(Interface)
    if !ok {
        t.Error("OnDisk does not implement Interface")
    }
}

Let’s run these tests:

go test -v ./cache
=== RUN   TestInMemoryImplementsInterface
--- PASS: TestInMemoryImplementsInterface (0.00s)
=== RUN   TestOnDiskImplementsInterface
    cache_test.go:17: OnDisk does not implement Interface
--- FAIL: TestOnDiskImplementsInterface (0.00s)
FAIL
FAIL    cache   0.002s
FAIL

As seen from the test results, the cache.InMemory type implements the cache.Interface, but the cache.OnDisk type does not.

But there is an easier way!

While using tests to check for interface implementation works, it does require a certain level of discipline from the developer. You need to remember to write the tests and, just as importantly, to run them periodically.

Fortunately, there is a simpler way to check whether a specific type implements the required interface. You only need to write a single line of code (for us, two lines, since we have two types) and run go build.

package cache

// ...

var _ Interface = (*InMemory)(nil)
var _ Interface = (*OnDisk)(nil)
go build ./cache

cache/cache.go:6:19: cannot use (*OnDisk)(nil) (value of type *OnDisk) as type Interface in variable declaration:
    *OnDisk does not implement Interface (wrong type for Delete method)
        have Delete(key string) error
        want Delete(key string)

As you can see, the Golang compiler not only informs us that a type does not implement the interface, but also provides insight into the reason for this. In our case, it’s due to different method signatures.

What is this magic?

There’s no magic. The underscore symbol (_) is a special variable name used when we need to assign a value but do not intend to use it later. One of the most common uses of such variables is to ignore errors, for example:

f, _ := os.Open("/path/to/file")

In the above example, we open a file but do not check for potential errors.

Thus, we create an unused variable of type cache.Interface and assign it a nil pointer to the implementation type (cache.InMemory or cache.OnDisk).

Conclusion

In this article, we explored the concept of an "interface" in different programming languages. We determined whether Go is an object-oriented language and learned how to check if a type implements an interface both via tests and during the compilation stage.

On our app platform you can deploy Golang apps, such as Beego and Gin.

Go
06.12.2024
Reading time: 10 min

Similar

Go

How to Install Go on Windows

Go, or Golang, is a high-performance, multithreaded programming language developed by Google in 2007 and released in 2009. To this day, Golang continues to gain popularity.  The Go programming language is a flexible option for development on a variety of platforms because it supports a wide range of operating systems. We will go over how to install Golang on Windows step-by-step in this tutorial. Installing GO on Windows is a simple process Installing Go on Windows Go supports Windows 7 and newer versions. Ensure that you have a supported version of the OS installed. In this guide, we will use Windows 11. You will also need an administrator account to configure environment variables. To install Golang on Windows: Download the installer for the latest version of Microsoft Windows from the official Go website. If needed, you can select any other available version of the language instead of the latest one. Once the file has finished downloading, run it and follow the installation wizard's instructions. If necessary, you can change the file location. This will be useful when configuring environment variables. After the installation, check if Golang was successfully installed on your system. To do this, open the terminal (Win + R → cmd) and run the following command: go version The output should show the version of Go you just installed. For example: GO version check To update Golang to a newer version on Windows, you must uninstall the old version and follow the instructions to install the new one. Now, let's move on to setting up environment variables so that Go works properly. Setting Up Environment Variables In order for the operating system to identify the location of the required Go files and directories, setting up environment variables is a crucial step in the Go installation process on Windows. For Go to work correctly, two environment variables are required: GOPATH points to where Go stores downloaded and compiled packages. PATH allows the system to find Go executable files without specifying their full paths. GOPATH First, let's set up the GOPATH environment variable. For this, you need to organize a workspace where Go files and projects will be stored. In this guide, we will create a workspace at C:\GoProject. We will also add two directories to this folder: bin – for storing executable files (binary files). Go creates an executable file and places it in this directory when you compile your project. src – for storing Go source files. All .go files will be placed here. After creating the workspace, we will set the GOPATH environment variable. To do this, go to the Control Panel → System and Security → System and click on Advanced System Settings. There is also an easier way to access system properties: open the Run window (Win + R) and enter: sysdm.cpl Click on Environment Variables, then click the New button under the User Variables section. Here, you need to fill in two fields: the variable name and its value. In the Variable name field, enter GOPATH, and in the Variable value field, enter the path to the workspace you created earlier (in our case, C:\GoProject). Click OK twice to save the changes. To verify the creation of the system variable, open the Run window (Win + R) and enter the string: %GOPATH% If everything was done correctly, your workspace will open. PATH The PATH environment variable should have been automatically added after we installed Go. To check this, go to the Control Panel → System and Security → System and click on Advanced System Settings. In the window that opens, you need to find PATH among the system variables. To view its values, double-click on it. In the new window, there should be an entry that holds the path to the Go bin folder. Go installation path In our case, it is C:\Program Files\Go\bin. If your value does not match what was specified during the Go installation, change it to the correct one using the Edit button. Golang has now been installed on Windows, and environment variables have been set up. We can now write and execute our first program to test its functionality. Verifying Installation To check the functionality of the newly installed Golang on Windows: Сreate a test file with the .go extension in the workspace (C:\GoProject\src). For example, ExampleProgram.go. Add the following simple code: package mainimport "fmt"func main() {    fmt.Println("Hello, Go has been successfully installed into your system!")} The program should display a message confirming that Go has been successfully installed on your system. To compile and run the program, enter the following command in the terminal: go run %GOPATH%/src/ExampleProgram.go As shown in the image below, the program compiles and runs, displaying the specified text on the screen. Go Successfully Installed Conclusion Installing Go on Windows is a straightforward process, involving downloading the installer, setting up environment variables, and verifying the installation. Once Go is properly configured, you can easily start developing applications. With support for multiple operating systems, Go remains a powerful and versatile language, ideal for cross-platform development. On our app platform you can deploy Golang apps, such as Beego and Gin. 
25 August 2025 · 5 min to read
Go

How to Install Go on MacOS

MacOS is an operating system for desktop computers and tablets developed by Apple specifically for its devices. It is initially pre-installed on all Apple devices, specifically the Apple Macintosh or Mac for short. Unlike Linux, macOS is a proprietary operating system, which, of course, brings certain peculiarities in installing various development tools on it. To see more details about it, check our instruction on how to deploy cloud server on MacOS. In this article, we will take a detailed look at how to install Go on a macOS computer. Google created the open source programming language Golang, or just Go, to build microservice-based systems. You may find other Go frameworks, like Beego and Gin, on our app platform. To ensure the stability of your computer and the Go compiler, we recommend using the latest version of macOS. Installing GO is a Simple Process 1. Uninstall old Golang versions Check if Golang is already installed Before you start installing Golang, first check if it is installed on your system already. A simple way to do this is to run a command that outputs the Golang version: go version If Go is indeed installed, you will see a message in the console terminal displaying the language version and the operating system's name. Something like this: go version go1.21.3 darwin/amd64 Uninstall Golang If Go is present on your system, you need to uninstall it to avoid possible installation conflicts. MacOS stores files from the Golang package in a predetermined location: The /usr/local/go directory. This is where Golang itself is placed. The /etc/paths.d/go file. Golang environment variables are specified here. So, to uninstall Golang, you need to clear the above directories: rm -rf /usr/local/go rm -rf /etc/paths.d/go The rm command deletes a directory or a file, while the -rf flag indicates a recursive-forced type of deletion. r stands for recursive and is used to delete the specified folder, all its subfolders, subfolders of subfolders, etc. f stands for force so no external states or variables can prevent the deletion from occurring Great! Golang is now removed from your computer. This means we can move on to downloading the Golang package for macOS and then installing it. 2. Download Golang The Go language archive can be downloaded to your computer in two different ways. One is highly automated, while the other more manual. Let's examine both. Manual download The official Golang website has a special page with links to download the latest version of Go. Once you open it, you will see several buttons leading to the latest language version for a particular platform. We are interested in the Apple operating system. At the moment of writing this article, there are two versions of the language for MacOS. One is for the new Apple ARM64 processor architecture, and the other is for the classic Intel 65-bit architecture. You should choose the one that suits your device. The latest Mac models have ARM64 processors. Clicking on the link will start downloading the archive file named go1.21.3.darwin-amd64.pkg, or a later version. Download via console An alternative to downloading manually is using the command line. MacOS has a special curl tool included in the operating system. So we can use the curl utility with the exact URL where the Golang archive file is available: curl -o golang.pkg https://dl.google.com/go/go1.21.3.darwin-amd64.pkg This command uses a special flag -o (--output), which ensures that the data received through the curl request is written to the golang.pkg file. Note that the URL contains the exact name of the file we want to download and the Golang version. When the curl command is finished, we will have a golang.pkg file containing the Golang language package. Then we just need to install it. 3. Install the Go package As with the download, installation is also available in two ways: through the GUI or the command line interface. Installing via GUI To install Go on macOs, simply run the downloaded package.  After the automatic installation is done, you will get a success message confirming that the software is installed. Installing via command line If you prefer working with the terminal, run the following command: sudo open golang.pkg After that, follow to the terminal's instructions until a popup confirming the installation's success displays. 4. Set environment variables After installation, we must tell the system where to find the Golang compiler when the console terminal receives the command to compile and run the application. First, let's navigate to the home directory using the following command: cd ~ Now add the locations of the Golang components to .bash_profile. This file is automatically loaded when you log in to your macOS account and contains all the startup configurations for the command line interface. Add environment variables to the end of the file, either manually or via the echo command: echo "export GOROOT=/usr/local/go" >> .bash_profileecho "export GOPATH=$HOME/Documents/go" >> .bash_profileecho "export PATH=$GOPATH/bin:$GOROOT/bin:$PATH" >> .bash_profile The >> operator indicates that the text in quotes after echo will be written to the .bash_profile file. The GOROOT variable points to the directory where the Go compiler is installed. GOPATH contains the address of the Go working directory. And PATH helps the command line to find binary files during source compilation. 5. Check the installation To verify that Golang has been successfully installed on macOS, you need to restart the command line terminal and query the Go version: go version If the installation was done correctly, the console will display a message: go version go1.21.3 darwin/amd64 6. Launch a test application In this article we won't go into the details of Golang syntax and peculiarities of programming in this language. We will just write, compile, and run a simple program with trivial output to the console to make sure that the installed compiler works. Let's create a new file in our home directory using the nano editor: nano main.go Then fill it with the following contents: package main import "fmt" func main() { fmt.Println("Hello, World!") // CONCLUSION: Hello, World! } To exit nano, press "CTRL+X". When prompted to save the file, press "Y", then "ENTER". Now we can compile and run our program with just one command: go run main.go There is also another command that builds the application source code into a complete executable file that can be distributed and deployed to other local machines: go build If you don't specify the name of the go file as an argument, the command will compile the file with the standard name main.go. For example, if the file containing our program were named test.go, the build command would look like this: go build test.go During build, the Go compiler will include all the .go files involved in the final "build", adding the auxiliary code needed to run the application on any computer with the same system architecture. Building to an executable file allows programs to run on other computers regardless of whether the Golang compiler itself is directly installed on them. Visualization of Go Installation on MacOS Conclusion Despite being a proprietary operating system, macOS allows you to install tools from third-party companies and developers (in our case, Google), including open-source solutions. In this article, we have looked at the standard way of installing the Golang compiler on macOS, which includes a few basic steps: Checking for older versions Uninstalling the old versions if they exist Downloading the package from the official website (manually or automatically) Installing the downloaded package (via GUI or terminal) Adding environment variables Checking if the installation is correct Compiling and running a simple code With these steps, we installed Go on macOS and ran our first program using fairly simple commands. For further study of the language and deeper familiarization with its syntax, we recommend checking the documentation on the official Golang website. Also, Hostman offers various VPS Servers for you to host on Mac by low price! Frequently Asked Questions How to install Go on Mac without Homebrew? Download the installer from golang.org, run it, and then update your PATH manually. What is the easiest way to install Go on macOS? Honestly? Just run brew install go if you already use Homebrew — it’s fast and simple. How do I set the PATH for Go on macOS? Add this line to your shell config: export PATH=$PATH:/usr/local/go/bin. Where is Go installed on macOS? Usually at /usr/local/go when using the official package.
21 August 2025 · 7 min to read
Microservices

Database Connection in Python, Go, and JavaScript

Databases are an essential part of almost any project today. Database interactions are especially familiar to system and database administrators, DevOps/SRE professionals, and software developers. While administrators typically deploy one or multiple database instances and configure the necessary connection parameters for applications, developers need to connect directly to the database within their code. This article explores how to connect to databases using different programming languages. Prerequisites We will provide examples for connecting to MySQL, PostgreSQL, Redis, MongoDB, and ClickHouse databases using Python, Go, and JavaScript. To follow this guide, you will need: A database deployed on a server or in the cloud. Installed environments for Python, Go, and JavaScript, depending on your application programming language. Additionally for Python: pip installed. Additionally for JavaScript: Node.js and npm installed. Database Connection in Python MySQL and Python For connecting to MySQL databases, we can use a Python driver called MySQL Connector. Install the driver using pip: pip install mysql-connector-python Initialize a new connection: Import the mysql.connector library and the Error class to handle specific connection errors. Create a function named create_connection, passing the database address (host), user name (user), and user password (password). To establish the connection, define a class called create_connection that receives the variable names containing the database connection details. import mysql.connector from mysql.connector import Error def create_connection(host_name, user_name, user_password): connection = None try: connection = mysql.connector.connect( host="91.206.179.29", user="gen_user", password="m-EE6Wm}z@wCKe" ) print("Successfully connected to MySQL Server!") except Error as e: print(f"The error '{e}' occurred") return connection def execute_query(connection, query): cursor = connection.cursor() try: cursor.execute(query) connection.commit() print("Query executed successfully") except Error as e: print(f"The error '{e}' occurred") connection = create_connection("91.206.179.29", "gen_user", "m-EE6Wm}z@wCKe") Run the script. If everything works correctly, you will see the "Successfully connected to MySQL Server!" message. If any errors occur, the console will display error code and description. Create a new table: Connect to the database using the connection.database class, specifying the name of the database. Note that the database should already exist. To create a table, initialize a variable create_table_query containing the SQL CREATE TABLE query. For data insertion, initialize another variable insert_data_query with the SQL INSERT INTO query. To execute each query, use the execute_query class, which takes the database connection string and the variable containing the SQL query. connection.database = 'test_db' create_table_query = """ CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, age INT NOT NULL ) """ execute_query(connection, create_table_query) insert_data_query = """ INSERT INTO users (name, age) VALUES ('Alice', 30), ('Bob', 25) """ execute_query(connection, insert_data_query) if connection.is_connected(): connection.close() print("Connection closed") Run the script. PostgreSQL and Python Python offers several plugins for connecting to PostgreSQL, but the most popular one is psycopg2, which we will use here. Psycopg2 is one of the most frequently used Python plugins for PostgreSQL connections. One of its key advantages is its support for multithreading which allows you to maintain the database connection across multiple threads. Install psycopg2 using pip (if not already installed): pip install psycopg2-binary Connect to PostgreSQL. Import the Python psycopg2 package and create a function create_new_conn, using the try block. Establish the connection with the psycopg2.connect function, which requires the database name, user name, password, and database address as input. To initialize the connection, use the create_new_conn() function. Here’s the full code example for connecting to a database: import psycopg2 from psycopg2 import OperationalError def create_new_conn(): conn_to_postgres = None while not conn_to_postgres: try: conn_to_postgres = psycopg2.connect( default_db="default_db", default_user="gen_user", password_for_default_user="PasswordForDefautUser9893#", db_address="91.206.179.128" ) print("The connection to PostgreSQL has been successfully established!") except OperationalError as e: print(e) return conn_to_postgres conn_to_postgres = create_new_conn() Run the script: python3 connect_to_postgres.py If successful, you will see the "The connection to PostgreSQL has been successfully established!" message. . Next, create a table named books, which will have three columns. Use the cursor class for SQL expressions, such as creating database objects. If the query involves adding or modifying data, you must call the conn_to_postgres.commit() function afterward to apply the changes. import psycopg2 from psycopg2 import OperationalError def create_new_conn(): conn_to_postgres = None while not conn_to_postgres: try: conn_to_postgres = psycopg2.connect( default_db="default_db", default_user="gen_user", password_for_default_user="PasswordForDefautUser9893#", db_address="91.206.179.128" ) except OperationalError as e: print(e) return conn_to_postgres conn_to_postgres = create_new_conn() cursor = conn_to_postgres.cursor() cursor.execute(""" CREATE TABLE books ( book_id INT PRIMARY KEY NOT NULL, book_name VARCHAR(255) NOT NULL, book_author VARCHAR(255) NOT NULL ) """) conn_to_postgres.commit() print("Table Created successfully") Run the script: python3 create_table.py Now, let’s run INSERT INTO to add a new line: cursor.execute(""" INSERT INTO books (book_id,book_name,book_author) VALUES (1, 'Long Walk to Freedom', 'Nelson_Mandela') """) The full code is below: import psycopg2 from psycopg2 import OperationalError def create_new_conn(): conn_to_postgres = None while not conn_to_postgres: try: conn_to_postgres = psycopg2.connect( default_db="default_db", default_user="gen_user", password_for_default_user="PasswordForDefautUser9893#", db_address="91.206.179.128" ) except OperationalError as e: print(e) return conn_to_postgres conn_to_postgres = create_new_conn() cursor = conn_to_postgres.cursor() cursor.execute(""" INSERT INTO books (book_id,book_name,book_author) VALUES (1, 'Long Walk to Freedom', 'Nelson_Mandela') """) conn_to_postgres.commit() conn_to_postgres.close() print("Data inserted successfully") Run the script: python3 insert-data.py Redis and Python Redis belongs to the class of NoSQL databases, where data is stored in memory rather than on hard drives. It uses a key-value format for data storage. Redis has a wide range of applications, from data storage and caching to serving as a message broker. We will use the redis-py (or simply redis) library for connecting to Redis. Install the Redis library using pip: pip install redis Connecting to a Redis instance: Use a try block structure for connection, specifying the function redis.StrictRedis where you provide the Redis address, port, and user password. import redis try: connect_to_redis_server = redis.StrictRedis( redis_db_host=91.206.179.128, redis_db_port=6379, redis_user_password='PasswordForRedis6379') print connect_to_redis_server connect_to_redis_server.ping() print 'Successfully connected to Redis Server!' except Exception as ex: print 'Error:', ex exit('Failed to connect to Redis server.') Run the script: python3 connect_to_redis.py If successful, you will see a message like "Successfully connected to Redis Server!". Unlike relational databases, Redis stores data in a key-value format. The key uniquely identifies the corresponding value. Use the set method to create a new record. The example below creates a record with the key City and the value Berlin: print('Create new record:', connect_to_redis_server.set("City", "Berlin")) Use the get method to retrieve the value associated with a key: print('Print record using record key:', connect_to_redis_server.get("City")) Use the delete method to remove a record by its key: print('Delete record with key:', connect_to_redis_server.delete("City")) The complete code fragment is below. import redis try: connect_to_redis_server = redis.StrictRedis( redis_db_host=91.206.179.128, redis_db_port=6379, redis_user_password='PasswordForRedis6379') print ('New record created:', connect_to_redis_server.set("City", "Berlin")) print ('Print created record using record key', connect_to_redis_server.get("City")) print ('Delete created record with key :', connect_to_redis_server.delete("City")) except Exception as ex: print ('Error:', ex) MongoDB and Python MongoDB is another widely used NoSQL database that belongs to the document-oriented category. Data is organized as JSON-like documents. To connect to a MongoDB database with Python, the recommended library is PyMongo, which provides a synchronous API. Install the PyMongo plugin: pip3 install pymongo Connect to MongoDB server using the following Python code. Import the pymongo module and use the MongoClient class to specify the database server address. To establish a connection to the MongoDB server, use a try block for error handling: import pymongo connect_to_mongo = pymongo.MongoClient("mongodb://91.206.179.29:27017/") first_db = connect_to_mongo["mongo-db1"] try: first_db.command("serverStatus") except Exception as e: print(e) else: print("Successfully connected to MongoDB Server!") connect_to_mongo.close() Run: python3 connect_mongodb.py If the connection is successfully established, the script will return the message: "Successfully connected to MongoDB Server!" Add data to MongoDB. To add data, you need to create a dictionary. Let's create a dictionary named record1, containing three keys: record1 = { "name": "Alex", "age": 25, "location": "London" } To insert the dictionary data, use the insert_one method in MongoDB. insertrecord = collection1.insert_one(record1) import pymongo connect_to_mongo = pymongo.MongoClient("mongodb://91.206.179.29:27017/") db1 = connect_to_mongo["newdb"] collection1 = db1["userdata"] record1 = { "name": "Alex", "age": 25, "location": "London" } insertrecord = collection1.insert_one(record1) print(insertrecord) Run the script: python3 connect_mongodb.py ClickHouse and Python ClickHouse is a columnar NoSQL database where data is stored in columns rather than rows. It is widely used for handling analytical queries. Install the ClickHouse driver for Python. There is a dedicated plugin for ClickHouse called clickhouse-driver. Install the driver using the pip package manager: pip install clickhouse-driver Connect to ClickHouse. To initialize a connection with ClickHouse, you need to import the Client class from the clickhouse_driver library. To execute SQL queries, use the client.execute function. You also need to specify the engine. For more details on supported engines in ClickHouse, you can refer to the official documentation. We'll use the default engine, MergeTree. Next, create a new table called users and insert two columns with data. To list the data to be added to the table, use the tuple data type. After executing the necessary queries, make sure to close the connection to the database using the client.disconnect() method. The final code will look like this: from clickhouse_driver import Client client = Client(host=91.206.179.128', user='root', password='P@$$w0rd123', port=9000) client.execute(''' CREATE TABLE IF NOT EXISTS Users ( id UInt32, name String, ) ENGINE = MergeTree() ORDER BY id ''') data = [ (1, 'Alice'), (2, 'Mary') ] client.execute('INSERT INTO Users (id, name) VALUES', data) result = client.execute('SELECT * FROM Users') for row in result: print(row) client.disconnect() Database Connection in Go Go is one of the youngest programming languages, developed in 2009 by Google.  It is widely used in developing microservice architectures and network utilities. For example, services like Docker and Kubernetes are written in Go. Go supports integrating all popular databases, including PostgreSQL, Redis, MongoDB, MySQL, ClickHouse, etc. MySQL and Go For working with the MySQL databases in Go, use the go-sql-driver/mysql driver. Create a new directory for storing project files and navigate into it: mkdir mysql-connect && cd mysql-connect Create a go.mod file to store the dependencies: go mod init golang-connect-mysql Download the MySQL driver using the go get command: go get -u github.com/go-sql-driver/mysql Create a new file named main.go. Specify the database connection details in the dsn variable: package main import ( "database/sql" "fmt" "log" _ "github.com/go-sql-driver/mysql" ) func main() { dsn := "root:password@tcp(localhost:3306)/testdb" db, err := sql.Open("mysql", dsn) if err != nil { log.Fatal(err) } defer db.Close() if err := db.Ping(); err != nil { log.Fatal(err) } fmt.Println("Successfully connected to the database!") query := "INSERT INTO users (name, age) VALUES (?, ?)" result, err := db.Exec(query, "Alex", 25) if err != nil { log.Fatal(err) } lastInsertID, err := result.LastInsertId() if err != nil { log.Fatal(err) } fmt.Printf("Inserted data with ID: %d\n", lastInsertID) } PostgreSQL and Go To connect to PostgreSQL, use the pq driver. Before installing the driver, let's prepare our environment. Create a new directory for storing the project files and navigate into it: mkdir postgres-connect && cd postgres-connect Since we will be working with dependencies, we need to create a go.mod file to store them: go mod init golang-connect-postgres Download the pq driver using the go get command: go get github.com/lib/pq Create a new file named main.go. In addition to importing the pq library, it is necessary to add the database/sql library as Go does not come with official database drivers by default. The database/sql library consists of general, independent interfaces for working with databases. It is also important to note the underscore (empty identifier) when importing the pq module: _ "github.com/lib/pq" The empty identifier is used to avoid the "unused import" error, as in this case, we only need the driver to be registered in database/sql. The fmt package is required to output data to the standard output stream, for example, to the console. To open a connection to the database, the sql.Open function is used, which takes the connection string (connStr) and the driver name (postgres). The connection string specifies the username, database name, password, and host address: package main import ( "database/sql" "fmt" "log" _ "github.com/lib/pq" ) func main() { connStr := "user=golang dbname=db_for_golang password=Golanguserfordb0206$ host=47.45.249.146 sslmode=disable" db, err := sql.Open("postgres", connStr) if err != nil { log.Fatal(err) } defer db.Close() err = db.Ping() if err != nil { log.Fatal(err) } fmt.Println("Successfully connected to PostgreSQL!") } Compile and run: go run main.go If everything works correctly, the terminal will display the message Successfully connected to PostgreSQL! Now, let's look at an example of how to insert data into a table.  First, we need to create a table in the database. When using Hostman cloud databases, you can copy the PostgreSQL connection string displayed in the "Connections" section of the Hostman web interface. Make sure that the postgresql-client utility is installed on your device beforehand. Enter the psql shell and connect to the previously created database: \c db_for_golang Create a table named Cities with three fields — city_id, city_name, and city_population: CREATE TABLE Cities ( city_id INT PRIMARY KEY, city_name VARCHAR(45) NOT NULL, city_population INT NOT NULL); Grant full privileges to the created table for the user: GRANT ALL PRIVILEGES ON TABLE cities TO golang; The function db.Prepare is used to prepare data. It specifies the query for insertion in advance. To insert data, use the function stmt.Exec. In Go, it's common to use plain SQL without using the ORM (Object-Relational Mapping) approach. stmt, err := db.Prepare("INSERT INTO Cities(city_id, city_name, city_population) VALUES($1, $2, $3)") if err != nil { log.Fatal(err) } defer stmt.Close() _, err = stmt.Exec(1, "Toronto", 279435) if err != nil { log.Fatal(err) } fmt.Println("Data inserted successfully!") } If all works correctly, you will see: Data inserted successfully! Redis and Go To connect to Redis, you need to use the go-redis driver. Сreate a new directory: mkdir connect-to-redis && cd connect-to-redis Prepare the dependency file: go mod init golang-connect-redis And optimize them: go mod tidy Download the go-redis module: go get github.com/go-redis/redis/v8 To connect to Redis, use the redis.Options function to specify the address and port of the Redis server. Since Redis does not use authentication by default, you can leave the Password field empty and use the default database (database 0): package main import ( "context" "fmt" "log" "github.com/go-redis/redis/v8" ) func main() { rdb := redis.NewClient(&redis.Options{ Addr: "91.206.179.128:6379", Password: "", DB: 0, }) ctx := context.Background() _, err := rdb.Ping(ctx).Result() if err != nil { log.Fatalf("Couldn't connect to Redis: %v", err) } fmt.Println("Successfully connected to Redis!") } You should see the message «Successfully connected to Redis!» MongoDB and Go To work with MongoDB, we'll use the mongo driver. Create a new directory to store the project structure: mkdir connect-to-mongodb && cd connect-to-mongodb Initialize the dependency file: go mod init golang-connect-mongodb Download the mongo library: go get go.mongodb.org/mongo-driver/mongo Connect to MongoDB using the options.Client().ApplyURI method. It takes a connection string such as mongodb://91.206.179.29:27017, where 91.206.179.29 is the MongoDB server address and 27017 is the port for connecting to MongoDB. The options.Client().ApplyURI string is used only for specifying connection data. To check the connection status, you can use another function, client.Ping, which shows the success or failure of the connection: package main import ( "context" "fmt" "log" "time" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) func main() { clientOptions := options.Client().ApplyURI("mongodb://91.206.179.29:27017") client, err := mongo.Connect(context.TODO(), clientOptions) if err != nil { log.Fatalf("Couldn't connect to MongoDB server: %v", err) } fmt.Println("successfully connected to MongoDB!") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() err = client.Ping(ctx, nil) if err != nil { log.Fatalf("Could not ping MongoDB server: %v", err) } fmt.Println("Ping MongoDB server successfully!") } You should see the message: successfully connected to MongoDB!Ping MongoDB server successfully MongoDB uses collections to store data. You can create collections using the .Collection function.  Below, we will create a database called first-database and a collection called first-collection. The collection will have a new document, containing three keys: user-name, user-age, and user-email. collection := client.Database("first-database").Collection("first-collection") document := map[string]interface{}{ "user-name": "Alice", "user-age": 25, "user-email": "alice@corporate.com", } insertResult, err := collection.InsertOne(ctx, document) if err != nil { log.Fatalf("Couldn't insert new document: %v", err) } fmt.Printf("Inserted new document with ID: %v\n", insertResult.InsertedID) if err := client.Disconnect(ctx); err != nil { log.Fatalf("Could not disconnect from MongoDB: %v", err) } fmt.Println("Disconnected from MongoDB!") } If successful, you will see the Inserted new document message with the document ID.  ClickHouse and Go To work with ClickHouse, use the clickhouse-go driver. Create a new directory to store the project files and navigate to it: clickhouse-connect && cd clickhouse-connect Create a go.mod file to store the dependencies: go mod init golang-connect-clickhouse Download the Clickhouse driver using the command: go get github.com/ClickHouse/clickhouse-go/v2 Create a new file named main.go, where you will specify the connection data to ClickHouse. package main import ( "database/sql" "log" "github.com/ClickHouse/clickhouse-go/v2" ) func main() { dsn := "tcp://localhost:9000?username=user1&password=PasswordForuser175465&database=new_db" db, err := sql.Open("clickhouse", dsn) if err != nil { log.Fatal(err) } defer db.Close() if err := db.Ping(); err != nil { log.Fatal(err) } log.Println("Connected to ClickHouse!") } Database Connection in JavaScript In JavaScript, all connections to external services are made using the Node.js platform. Make sure that you have Node.js and the npm package manager installed on your device. MySQL and JavaScript To work with MySQL, use the mysql2 driver. Create a directory where we will store the project files: mkdir js-mysql-connect && cd js-mysql-connect Initialize the project: npm init -y Install the mysql2 library: npm install mysql2 Use the following code to connect to MySQL: const mysql = require('mysql2'); const connection_to_mysql = mysql.createConnection({ host: 'localhost', user: 'root', password: 'PasswordForRoot74463', database: db1, }); connection_to_mysql.connect((err) => { if (err) { console.error('Error connecting to MySQL:', err.message); return; } console.log('Successfully connected to MySQL Server!'); connection_to_mysql.end((endErr) => { if (endErr) { console.error('Error closing the connection_to_mysql:', endErr.message); } else { console.log('Connection closed.'); } }); }); PostgreSQL and JavaScript Connecting to PostgreSQL is done using the pg library. Create a directory where we will store the project files: mkdir js-postgres-connect && cd js-postgres-connect Initialize the project: npm init -y Install the pg library: npm install pg To connect to PostgreSQL, first import the pg library. Then, create a constant where you specify variables for the database address, username, password, database name, and port. Use the new pg.Client class to pass the connection data. We will create a table called cities and add two records into it. To do this, we will use the queryDatabase function, which contains the SQL queries. const pg = require('pg'); const config = { postgresql_server_host: '91.206.179.29', postgresql_user: 'gen_user', postgresql_user_password: 'PasswordForGenUser56467$', postgresql_database_name: 'default_db', postgresql_database_port: 5432, }; const client = new pg.Client(config); client.connect(err => { if (err) throw err; else { queryDatabase(); } }); function queryDatabase() { const query = ` DROP TABLE IF EXISTS cities; CREATE TABLE cities (id serial PRIMARY KEY, name VARCHAR(80), population INTEGER); INSERT INTO cities (name, population) VALUES ('Berlin', 3645000); INSERT INTO cities (name, population) VALUES ('Paris', 2161000); `; client .query(query) .then(() => { console.log('Table created successfully!'); client.end(console.log('Closed client connection')); }) .catch(err => console.log(err)) .then(() => { console.log('Finished execution, exiting now'); process.exit(); }); } Use this command to run the code: node connect-to-postgres.js Redis and JavaScript To work with Redis, use the ioredis library. Create a directory to store the project files: mkdir js-redis-connect && cd js-redis-connect Initialize the project: npm init -y Install the ioredis library: npm install ioredis To connect to Redis, import the ioredis library. Then create a constant named redis and specify the Redis server address. Inserting data, i.e., creating key-value objects, is done using an asynchronous function named setData, which takes two values — key and value, corresponding to the data format of the Redis system. const Redis = require('ioredis'); const redis = new Redis({ host: '91.206.179.29', port: 6379, password: 'UY+p8e?Kxmqqfa', }); async function setData(key, value) { try { await redis.set(key, value); console.log('Data successfully set'); } catch (error) { console.error('Error setting data:', error); } } async function getData(key) { try { const value = await redis.get(key); console.log('Data retrieved'); return value; } catch (error) { console.error('Error getting data:', error); } } (async () => { await redis.select(1); await setData('user', 'alex'); await getData('user'); redis.disconnect(); })(); Run: node connect-to-redis.js MongoDB and JavaScript To work with MongoDB, use the mongodb driver. Create a directory for storing the project files: mkdir js-mongodb-connect && cd js-mongodb-connect Initialize the project: npm init -y Install the mongodb library: npm install mongodb To connect to MongoDB, import the mongodb library. Specify the database address in the constant uri and pass the address into the MongoClient class. const { MongoClient } = require('mongodb'); const uri = "mongodb://91.206.179.29:27017"; const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true }); async function connectToDatabase() { try { await client.connect(); console.log("Successfully connected to MongoDB!"); const database = client.db("myDatabase"); const collection = database.collection("myCollection"); const documents = await collection.find({}).toArray(); console.log("Documents found:", documents); } catch (error) { console.error("Error connecting to MongoDB:", error); } finally { await client.close(); console.log("Connection closed."); } } connectToDatabase(); ClickHouse and JavaScript To work with ClickHouse, use the clickhouse/client driver. Create a directory where we will store the project files: mkdir js-clickhouse-connect && cd js-clickhouse-connect Initialize the project: npm init -y Install the @clickhouse/client library: npm install @clickhouse/client To connect to ClickHouse, use the code below where we set the connection details and execute a simple SQL query that will return the first 10 records from the system table named system.tables: const { ClickHouse } = require('@clickhouse/client'); const client = new ClickHouse({ host: 'http://localhost:8123', username: 'default', password: 'PasswordforDefaultUser45435', database: 'default', }); async function connectAndQuery() { try { console.log('Successfully connected to ClickHouse Server!'); const rows = await client.query({ query: 'SELECT * FROM system.tables LIMIT 10', format: 'JSON', }).then((result) => result.json()); console.log('Query results:', rows); } catch (error) { console.error('Error Successfully connected to ClickHouse Server! or running the query:', error); } finally { console.log('Done.'); } } connectAndQuery(); Conclusion In today's article, we thoroughly explored how to connect to PostgreSQL, Redis, MongoDB, MySQL, and ClickHouse databases using Python, Go, and JavaScript. These languages can be used to create both web applications and microservices that utilize databases in their operation.
18 February 2025 · 23 min to read

Do you have questions,
comments, or concerns?

Our professionals are available to assist you at any moment,
whether you need help or are just unsure of where to start.
Email us
Hostman's Support