Creating a CRUD application with Golang, React and MongoDB

Laurentiu Raducu
12 min readFeb 26, 2023

--

Photo by Mark Wong on Unsplash

Creating a full-stack application that allows users to perform CRUD (Create, Read, Update, and Delete) operations is a common task for software developers. In this tutorial, we’ll create such an application using some of the most popular and powerful technologies available today: Golang for the backend, React for the frontend, and MongoDB for the database.

Golang, also known as Go, is a modern programming language that’s designed for high-performance and concurrent applications. It’s widely used for web development due to its simplicity, speed, and strong community support.

React, on the other hand, is a JavaScript library that’s used for building user interfaces. It’s known for its declarative programming style and component-based architecture, which makes it easy to build complex applications while keeping the code organized and maintainable.

MongoDB is a NoSQL database that’s designed for scalability and performance. It’s a popular choice for web applications due to its flexible schema, fast queries, and ease of use.

In this post, we’ll start by setting up the backend with Golang and connecting it to a MongoDB database. Then, we’ll create the frontend with React and integrate it with the backend. Finally, we’ll test and deploy the application to a server.

By the end of this post, you’ll have a fully functional CRUD application that you can customize and build upon. Let’s get started!

Setting up the backend with Golang

Before we can start building our CRUD application, we need to set up the backend with Golang. Here’s how to do it:

Installing Golang

The first step is to install Golang on your machine. You can download the latest version of Golang from the official website: https://golang.org/dl/.

Once you’ve downloaded the installer, follow the instructions to install Golang on your system.

Creating a new Golang project

After installing Golang, we can create a new project for our backend. Open your terminal or command prompt and create a new directory for your project:

mkdir my-crud-app-backend
cd my-crud-app-backend

Next, create a new Golang file for our main application:

touch main.go

In your preferred code editor, open the main.go file and add the following code:

package main

import (
"fmt"
"net/http"
)

func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, world!")
})

http.ListenAndServe(":8080", nil)
}

This code creates a basic HTTP server that responds with the message “Hello, world!” when accessed at the root URL. To run the application, use the following command:

go run main.go

If everything works correctly, you should see the message “Hello, world!” in your browser when you visit http://localhost:8080.

Setting up a MongoDB connection with Golang

Next, we need to set up a connection to our MongoDB database. We can use the official MongoDB driver for Golang, which can be installed using the following command:

go get go.mongodb.org/mongo-driver/mongo

Once the driver is installed, we can create a new connection to our database using the following code:

package main

import (
"context"
"fmt"
"log"
"net/http"
"os"

"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
client, err := mongo.Connect(context.Background(), clientOptions)
if err != nil {
log.Fatal(err)
}

err = client.Ping(context.Background(), nil)
if err != nil {
log.Fatal(err)
}

fmt.Println("Connected to MongoDB!")
defer client.Disconnect(context.Background())

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, world!")
})

http.ListenAndServe(":8080", nil)
}

This code creates a new MongoDB client and connects to a local instance of the MongoDB server running on port 27017. It also includes a simple error handling mechanism to make sure that the connection is established successfully.

Implementing CRUD operations in Golang

With the MongoDB connection set up, we can start implementing the CRUD operations for our application. We’ll cover this in more detail in the next section, but for now, let’s add some placeholders for our CRUD functions:

package main

import (
"context"
"fmt"
"log"
"net/http"
"os"

"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)

type User struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Password string `json:"password"`
}

func getUsers(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Get all users")
}

func getUser(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Get a user")
}

func createUser(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Create a user")
}

func updateUser(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Update a user")
}

func deleteUser(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Delete a user")
}

func main() {
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
client, err := mongo.Connect(context.Background(), clientOptions)
if err != nil {
log.Fatal(err)
}
err = client.Ping(context.Background(), nil)
if err != nil {
log.Fatal(err)
}

fmt.Println("Connected to MongoDB!")
defer client.Disconnect(context.Background())

http.HandleFunc("/users", getUsers)
http.HandleFunc("/users/", getUser)
http.HandleFunc("/users/create", createUser)
http.HandleFunc("/users/update/", updateUser)
http.HandleFunc("/users/delete/", deleteUser)

http.ListenAndServe(":8080", nil)}

This code defines a `User` struct that represents our data model and adds placeholders for the CRUD functions that we’ll implement later. It also maps these functions to the corresponding HTTP routes using the `http.HandleFunc` function.

With this basic setup, we have a working Golang backend that connects to a MongoDB database and provides some basic endpoints for our CRUD application. In the next section, we’ll build the frontend using React and integrate it with our backend.

Building the Frontend with React

Now that we have our backend set up, we can move on to building the frontend of our CRUD application using React. We’ll use create-react-app to create a new React project and axios to make HTTP requests to our Golang backend.

First, let’s install create-react-app:

npm install -g create-react-app

Next, let’s create a new React project:

create-react-app my-crud-app

Once the project is created, let’s install the axios library:

cd my-crud-app
npm install axios

Now we can start building our frontend. First, let’s create a new component that will display a list of users. Create a new file called UserList.js in the src directory with the following code:

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function UserList() {
const [users, setUsers] = useState([]);

useEffect(() => {
axios.get('/users')
.then(response => {
setUsers(response.data);
})
.catch(error => {
console.log(error);
});
}, []);

return (
<div>
<h2>User List</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{users.map(user => (
<tr key={user.id}>
<td>{user.name}</td>
<td>{user.email}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}

export default UserList;

This code defines a new React component called UserList that displays a list of users fetched from our Golang backend using the axios library. We use the useState hook to store the list of users in the component state, and the useEffect hook to fetch the list of users from the backend when the component is mounted.

Next, let’s update the App.js file to render the UserList component:

import React from 'react';
import UserList from './UserList';

function App() {
return (
<div>
<UserList />
</div>
);
}

export default App;

Now if you run the frontend using npm start and the backend using go run main.go, you should see a list of users displayed in your browser.

Next, let’s create a form to add new users. Create a new file called UserForm.js in the src directory with the following code:

import React, { useState } from 'react';
import axios from 'axios';

function UserForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');

const handleSubmit = (event) => {
event.preventDefault();
axios.post('/users/create', { name, email, password })
.then(response => {
console.log(response);
})
.catch(error => {
console.log(error);
});
};

return (
<div>
<h2>Add User</h2>
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={name} onChange={e => setName(e.target.value)} />
</label>
<label>
Email:
<input type="email" value={email} onChange={e => setEmail (e.target.value)} />
</label>
<label>
Password:
<input type="password" value={password} onChange={e => setPassword(e.target.value)} />
</label>
<button type="submit">Submit</button>
</form>
</div>
);
}

export default UserForm;

This code defines a new React component called `UserForm` that displays a form to add a new user to our Golang backend using the `axios` library. We use the `useState` hook to store the form input values in the component state, and the `handleSubmit` function to send a POST request to the backend when the form is submitted.

Finally, let’s update the `App.js` file to render the `UserForm` component:

import React from 'react';
import UserList from './UserList';
import UserForm from './UserForm';

function App() {
return (
<div>
<UserList />
<UserForm />
</div>
);
}

export default App;

Now if you run the frontend using npm start and the backend using go run main.go, you should see a form to add new users displayed in your browser.

Congratulations, you have successfully built a full-stack CRUD application using Golang, React, and MongoDB! Now, it’s time for testing.

Testing the Application

Testing is an important part of software development, and can help catch bugs and ensure that our application works as expected. In this section, we will cover how to unit test the backend with Golang, integration test the frontend and backend, and test MongoDB queries.

Unit Testing the Backend with Golang

Golang comes with a built-in testing framework that makes it easy to write unit tests for your code. Unit tests help ensure that individual functions or methods work as expected, and can catch bugs early in the development process.

To write unit tests for our Golang backend, we can create a new file in our api directory called user_test.go. Here is an example test for our CreateUser function:

func TestCreateUser(t *testing.T) {
// Set up a mock MongoDB database
db := new(MockDatabase)
db.On("CreateUser", mock.Anything).Return(nil)

// Create a new UserAPI using the mock database
api := UserAPI{db}

// Create a new user
user := User{
Name: "Test User",
Email: "test@example.com",
}
err := api.CreateUser(user)

// Check that the CreateUser function returns nil (no error)
if err != nil {
t.Errorf("Expected CreateUser to return nil, but got %v", err)
}

// Check that the CreateUser function was called with the correct arguments
db.AssertCalled(t, "CreateUser", user)
}

This test sets up a mock MongoDB database using the github.com/stretchr/testify/mock library, creates a new UserAPI using the mock database, and then calls the CreateUser function with a new User object. It checks that the function returns nil (indicating no error) and that the function was called with the correct arguments.

You can run all of your tests using the go test command.

Integration Testing the Frontend and Backend

Integration tests help ensure that different parts of your application work together correctly. To write integration tests for our application, we can use the testing-library/react library to render our React components and simulate user interactions.

Here is an example test for our UserForm component:

import React from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react';
import axios from 'axios';
import UserForm from './UserForm';

jest.mock('axios');

describe('UserForm', () => {
it('submits a new user', async () => {
axios.post.mockResolvedValueOnce({ data: { message: 'User created' } });

const { getByLabelText, getByText } = render(<UserForm />);

fireEvent.change(getByLabelText('Name:'), { target: { value: 'Test User' } });
fireEvent.change(getByLabelText('Email:'), { target: { value: 'test@example.com' } });
fireEvent.change(getByLabelText('Password:'), { target: { value: 'testpassword' } });
fireEvent.click(getByText('Submit'));

await waitFor(() => {
expect(getByText('User created')).toBeInTheDocument();
});
});
});

This test uses the jest.mock function to mock the axios library and simulate a successful POST request to our backend when the form is submitted. It then uses the render function from testing-library/react to render the UserForm component, simulates user input using the fireEvent function, and checks that the message "User created" is displayed on the page after the form is submitted.

Testing MongoDB Queries

Testing MongoDB queries can help ensure that your data is being stored and retrieved correctly from the database. To test MongoDB queries in Golang, we can use the github.com/stretchr/testify/assert library to write assertions about our data.

Here is an example test for our GetUsers function:

func TestGetUsers(t *testing.T) {
// Set up a mock MongoDB database
db := new(MockDatabase)
db.On("GetUsers").Return([]User{
{ID: "1", Name: "Test User 1", Email: "test1@example.com"},
{ID: "2", Name: "Test User 2", Email: "test2@example.com"},
{ID: "3", Name: "Test User 3", Email: "test3@example.com"},
}, nil)

// Create a new UserAPI using the mock database
api := UserAPI{db}

// Call the GetUsers function
users, err := api.GetUsers()

// Check that the GetUsers function returns the correct number of users
assert.Equal(t, 3, len(users))

// Check that the first user has the correct name and email
assert.Equal(t, "Test User 1", users[0].Name)
assert.Equal(t, "test1@example.com", users[0].Email)

// Check that the GetUsers function returns nil (no error)
assert.Nil(t, err)
}

This test sets up a mock MongoDB database using the github.com/stretchr/testify/mock library, creates a new UserAPI using the mock database, and then calls the GetUsers function. It checks that the function returns the correct number of users, and that the first user has the correct name and email.

You can run all of your tests using the go test command.

By following the steps in these instructions and writing tests for your application, you can ensure that your application is reliable and works as expected.

Deploying the Application

Once you have completed developing and testing your CRUD application, the next step is to deploy it to a server where it can be accessed by users. In this section, we will cover how to prepare the application for deployment, as well as how to deploy the backend and frontend to a server.

Preparing the Application for Deployment

Before deploying the application, there are a few things you need to do to ensure that it is ready for production:

  • Set up environment variables: You should configure your application to use environment variables for sensitive information like API keys, database credentials, and session secrets. This ensures that this information is not hard-coded into the application code and is kept secure.
  • Build the frontend for production: You should build the frontend of your application for production by running the following command inside the frontend directory:
npm run build

This will generate a build directory that contains the optimized and minified version of your frontend code.

  • Configure your server: You should configure your server to serve the frontend and backend of your application. One common approach is to use a reverse proxy like Nginx or Apache to handle incoming requests and route them to the appropriate backend or frontend server.

Deploying the Backend to a Server

To deploy the backend of your CRUD application to a server, follow these steps:

  • Set up the server: You will need to set up a server that meets the minimum requirements for running your Golang application. You can use a cloud hosting provider like Amazon Web Services, Google Cloud Platform, or Microsoft Azure, or you can use a dedicated server from a web hosting provider.
  • Copy the application code to the server: Copy the Golang code for your backend to the server using a tool like scp or rsync.
  • Build the application: Build the Golang application on the server by running the following command in the root directory of your backend code:
go build

This will generate a binary file that can be run on the server.

  • Start the application: Start the application by running the following command:
./your-app-name
  • Replace your-app-name with the name of your binary file.

Your backend should now be running on your server and ready to serve requests from the frontend.

Deploying the Frontend to a Server

To deploy the frontend of your CRUD application to a server, follow these steps:

  1. Set up the server: You will need to set up a server that meets the minimum requirements for running your React application. You can use a cloud hosting provider like Amazon Web Services, Google Cloud Platform, or Microsoft Azure, or you can use a dedicated server from a web hosting provider.
  2. Copy the application code to the server: Copy the React code for your frontend to the server using a tool like scp or rsync.
  3. Serve the frontend: Serve the frontend by running a web server like Nginx or Apache. You can use the build directory that was generated in step 2 of the "Preparing the Application for Deployment" section as the root directory for your web server.
  4. Configure the server: Configure your server to proxy requests to your backend server. You can use a reverse proxy like Nginx or Apache to handle incoming requests and route them to the appropriate backend or frontend server.

After following these steps, your CRUD application should be up and running on your server and ready to be accessed by users.

Conclusions

In this tutorial, we have built a full-stack CRUD application using Golang for the backend, React for the frontend, and MongoDB for the database. We started by setting up our Golang backend and connecting it to our MongoDB database, then we built our React frontend and used the axios library to make HTTP requests to our backend. We created a UserList component to display a list of users, a UserForm component to add new users, and used the useState and useEffect hooks to manage component state and make HTTP requests.

If you would like to continue learning, here are some next steps:

  • Learn more about Golang by reading the official documentation: https://golang.org/doc/
  • Learn more about React by reading the official documentation: https://reactjs.org/docs/getting-started.html
  • Learn more about MongoDB by reading the official documentation: https://docs.mongodb.com/
  • Practice building more full-stack applications using Golang, React, and MongoDB
  • Explore other technologies and frameworks for building full-stack applications, such as Node.js, Express, and PostgreSQL.

Thank you for following along with this tutorial, and happy coding!

--

--

No responses yet