Learning Center
Go

How to Create and Deploy a Gin App on Hostman App Platform

16 Jan 2025
Hostman Team
Hostman Team

Gin is a highly efficient HTTP web framework written in the Go programming language, providing developers with powerful tools for building web applications, RESTful APIs, and microservices. It stands out among other frameworks due to its high request processing speed, flexible configuration, and ease of use.

One of Gin’s key advantages is its performance. Gin uses a minimalist approach to handling HTTP requests, making it one of the fastest frameworks on the market. It is built on the net/http module from Golang’s standard library, ensuring excellent integration with Go’s ecosystem and enabling the use of Go’s concurrency features to handle a large number of simultaneous requests.

Another important advantage of Gin is its simplicity. The syntax and structure of Gin are intuitive, reducing the learning curve for developers and speeding up the development process. Its built-in routing system makes it easy to define and handle routes, while its powerful middleware system allows flexible request handling.

Gin’s flexibility is also worth mentioning. It allows you to extend functionality  through plugins and middleware, enabling adaptation to specific project requirements. Built-in support for JSON and other data formats simplifies the creation of RESTful APIs, and tools for handling requests and responses make data management straightforward.

In addition, Gin has an active community and solid documentation, making it an excellent choice for developers looking for a reliable and well-supported framework. There are plenty of resources, including code examples, guides, and libraries, that make the learning and development process easier.

Creating the Application
Copy link

Functionality Overview
Copy link

Our application will support basic CRUD operations (Create, Read, Update, Delete) for notes through a RESTful API. During development, we will discuss key aspects of integrating Gin with the GORM ORM library and demonstrate how to ensure the security and performance of our web application. The main features of our application include:

  1. Creating a New Note

    • The user can add a new note by sending a POST request with the note’s title and content.
    • The application will save the new note in the database and return its unique identifier.
  1. Retrieving All Notes

    • The user can request a list of all notes by sending a GET request.
    • The application will return all notes from the database in JSON format.
  1. Retrieving a Note by ID

    • The user can retrieve a specific note by its ID by sending a GET request with the specified ID.
    • The application will find the note in the database and return it in JSON format.
  1. Updating an Existing Note

    • The user can update an existing note by sending a PUT request with a new title and content.
    • The application will update the note’s data in the database and return the updated note.
  1. Deleting a Note

    • The user can delete a note by its ID by sending a DELETE request with the specified ID.
    • The application will remove the note from the database and return a status indicating the successful completion of the operation.

Project Setup
Copy link

It is assumed that you have Go version 1.22 installed (you can install it using one of these guides: Windows, Ubuntu, MacOS). If you use an earlier version, errors may occur during the project setup and launch process. Additionally, you should have a basic understanding of Git and an account on one of the Git repository hosting services (GitHub, GitLab, Bitbucket, Gitea, etc.).

Step 1: Create a Project Directory

Run the following command to create the project directory:

mkdir GinApp

Navigate into the newly created directory:

cd GinApp

Step 2: Initialize a New Go Module

Run the following command to initialize a new Golang module:

go mod init gin-notes-api

Step 3: Install Required Packages

We will install the necessary packages for the project: Gin, GORM, and SQLite (for database interaction) using the following commands:

go get -u github.com/gin-gonic/gin
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite

Step 4: Create the Project Structure

The project structure should look like this:

GinApp/  
├── go.mod  
├── main.go  
├── models/  
│   └── note.go  
├── handlers/  
│   └── note_handlers.go  
├── storage/  
│   ├── storage.go  
│   └── database.go  

You can create this structure using your IDE’s file explorer or by running the following command in the terminal:

mkdir -p models handlers storage && touch go.mod main.go models/note.go handlers/note_handlers.go storage/storage.go storage/database.go

Application Structure
Copy link

models/note.go

Defines the data structure for notes. The Note model describes the fields of a note and is used to interact with the database through the GORM ORM library.

package models  

// Definition of the Note structure  
type Note struct {  
	ID      int    `json:"id" gorm:"primaryKey;autoIncrement"` // Unique identifier, auto-incremented  
	Title   string `json:"title"`                               // Note title  
	Content string `json:"content"`                             // Note content  
}  

storage/database.go

This file contains functions for initializing the database and retrieving the database instance. GORM is used to work with the SQLite database.

package storage  

import (  
	"gorm.io/driver/sqlite"  // Driver for SQLite  
	"gorm.io/gorm"           // GORM ORM library  
	"gin-notes-api/models"   // Importing the package with data models  
)  

// Declare a global variable to store the database instance  
var db *gorm.DB  

// Function to initialize the database  
func InitDatabase() error {  
	var err error  
	db, err = gorm.Open(sqlite.Open("notes.db"), &gorm.Config{}) // Connect to SQLite using GORM  
	if err != nil {  
		return err // Return an error if the connection fails  
	}  
	return db.AutoMigrate(&models.Note{}) // Automatically create the Note table if it doesn’t exist  
}  

// Function to retrieve the database instance  
func GetDB() *gorm.DB {  
	return db // Return the global db variable containing the database connection  
}  

storage/storage.go

This file provides CRUD (Create, Read, Update, Delete) operations for the Note model using GORM to interact with the SQLite database.

package storage  

import (  
	"gin-notes-api/models" // Importing the package with data models  
)  

// Function to retrieve all notes from the database  
func GetAllNotes() []models.Note {  
	var notes []models.Note  
	db.Find(¬es) // Use GORM to execute a SELECT query and fill the notes slice  
	return notes    // Return all retrieved notes  
}  

// Function to retrieve a note by ID  
func GetNoteByID(id int) *models.Note {  
	var note models.Note  
	if result := db.First(¬e, id); result.Error != nil {  
		return nil // Return nil if the note with the specified ID is not found  
	}  
	return ¬e // Return the found note  
}  

// Function to create a new note  
func CreateNote(title, content string) models.Note {  
	note := models.Note{  
		Title:   title,  
		Content: content,  
	}  
	db.Create(¬e) // Use GORM to execute an INSERT query and save the new note  
	return note      // Return the created note  
}  

// Function to update an existing note by ID  
func UpdateNote(id int, title, content string) *models.Note {  
	var note models.Note  
	if result := db.First(¬e, id); result.Error != nil {  
		return nil // Return nil if the note with the specified ID is not found  
	}  
	note.Title = title  
	note.Content = content  
	db.Save(¬e) // Use GORM to execute an UPDATE query and save the updated note  
	return ¬e   // Return the updated note  
}  

// Function to delete a note by ID  
func DeleteNoteByID(id int) bool {  
	if result := db.Delete(&models.Note{}, id); result.Error != nil {  
		return false // Return false if deletion fails  
	}  
	return true // Return true if the note is successfully deleted  
} 

handlers/note_handlers.go

This file contains handler functions for processing HTTP requests. These functions are triggered in response to different routes and perform actions such as creating, retrieving, updating, and deleting notes.

package handlers  

import (  
	"net/http"                 // HTTP package  
	"strconv"                  // For converting strings to other data types  

	"github.com/gin-gonic/gin" // Gin web framework  
	"gin-notes-api/storage"    // Import the storage module for database operations  
)  

// Handler for retrieving all notes  
func GetNotes(c *gin.Context) {  
	notes := storage.GetAllNotes()               // Fetch all notes from storage  
	c.JSON(http.StatusOK, notes)                 // Return notes in JSON format with a 200 OK status  
}  

// Handler for retrieving a note by ID  
func GetNoteByID(c *gin.Context) {  
	id, err := strconv.Atoi(c.Param("id"))       // Convert the ID parameter from string to integer  
	if err != nil {  
		c.JSON(http.StatusBadRequest, gin.H{     // Return 400 Bad Request if the ID is invalid  
			"error": "Invalid note ID",  
		})  
		return  
	}  
	note := storage.GetNoteByID(id)              // Fetch the note by ID from storage  
	if note == nil {  
		c.JSON(http.StatusNotFound, gin.H{       // Return 404 Not Found if the note is not found  
			"error": "Note not found",  
		})  
		return  
	}  
	c.JSON(http.StatusOK, note)                  // Return the found note in JSON format with a 200 OK status  
}  

// Handler for creating a new note  
func CreateNote(c *gin.Context) {  
	var input struct {  
		Title   string `json:"title" binding:"required"`  
		Content string `json:"content" binding:"required"`  
	}  
	if err := c.ShouldBindJSON(&input); err != nil {  
		c.JSON(http.StatusBadRequest, gin.H{     // Return 400 Bad Request if the input data is invalid  
			"error": err.Error(),  
		})  
		return  
	}  
	note := storage.CreateNote(input.Title, input.Content) // Create a new note in storage  
	c.JSON(http.StatusCreated, note)                       // Return the created note in JSON format with a 201 Created status  
}  

// Handler for updating an existing note by ID  
func UpdateNoteByID(c *gin.Context) {  
	id, err := strconv.Atoi(c.Param("id"))       // Convert the ID parameter from string to integer  
	if err != nil {  
		c.JSON(http.StatusBadRequest, gin.H{     // Return 400 Bad Request if the ID is invalid  
			"error": "Invalid note ID",  
		})  
		return  
	}  
	var input struct {  
		Title   string `json:"title" binding:"required"`  
		Content string `json:"content" binding:"required"`  
	}  
	if err := c.ShouldBindJSON(&input); err != nil {  
		c.JSON(http.StatusBadRequest, gin.H{     // Return 400 Bad Request if the input data is invalid  
			"error": err.Error(),  
		})  
		return  
	}  
	note := storage.UpdateNote(id, input.Title, input.Content) // Update the note in storage  
	if note == nil {  
		c.JSON(http.StatusNotFound, gin.H{       // Return 404 Not Found if the note is not found  
			"error": "Note not found",  
		})  
		return  
	}  
	c.JSON(http.StatusOK, note)                  // Return the updated note in JSON format with a 200 OK status  
}  

// Handler for deleting a note by ID  
func DeleteNoteByID(c *gin.Context) {  
	id, err := strconv.Atoi(c.Param("id"))       // Convert the ID parameter from string to integer  
	if err != nil {  
		c.JSON(http.StatusBadRequest, gin.H{     // Return 400 Bad Request if the ID is invalid  
			"error": "Invalid note ID",  
		})  
		return  
	}  
	if success := storage.DeleteNoteByID(id); !success {  
		c.JSON(http.StatusNotFound, gin.H{       // Return 404 Not Found if the note is not found  
			"error": "Note not found",  
		})  
		return  
	}  
	c.Status(http.StatusNoContent)              // Return 204 No Content on successful deletion  
}  

main.go

This file serves as the main entry point of the application. It initializes the database and sets up routes for handling HTTP requests using the Gin web framework.

package main

import (
	"log"                      // Package for logging
	"github.com/gin-gonic/gin" // Gin web framework
	"gin-notes-api/handlers"   // Importing the module with request handlers
	"gin-notes-api/storage"    // Importing the module for database operations
)

func main() {
	// Initialize the database
	if err := storage.InitDatabase(); err != nil {
		log.Fatalf("Failed to initialize database: %v", err) // Log the error and terminate the program if database initialization fails
	}

	// Create a new Gin router with default settings
	router := gin.Default()

	// Define routes and bind them to their respective handlers
	router.GET("/notes", handlers.GetNotes)             // Route for retrieving all notes
	router.GET("/notes/:id", handlers.GetNoteByID)      // Route for retrieving a note by ID
	router.POST("/notes", handlers.CreateNote)          // Route for creating a new note
	router.PUT("/notes/:id", handlers.UpdateNoteByID)   // Route for updating a note by ID
	router.DELETE("/notes/:id", handlers.DeleteNoteByID) // Route for deleting a note by ID

	// Start the web server on port 8080
	router.Run(":8080")
}

Now we can run the application locally and test its functionality.

To start the application, use the following command:

go run main.go

Examples of curl Requests for Testing Functionality
Copy link

Create a New Note

This request creates a new note with a specified title and content.

curl -X POST http://localhost:8080/notes \
-H "Content-Type: application/json" \
-d '{"title":"Title","content":"Note body"}'

Get All Notes

This request retrieves a list of all notes stored in the database.

curl -X GET http://localhost:8080/notes

Get a Note by ID

This request fetches a specific note by its unique ID.

curl -X GET http://localhost:8080/notes/1

Update a Note by ID

This request updates an existing note by its ID, providing a new title and content.

curl -X PUT http://localhost:8080/notes/1 \
-H "Content-Type: application/json" \
-d '{"title":"Updated Title","content":"Updated note body"}'

Delete a Note by ID

This request deletes a note with a specific ID.

curl -X DELETE http://localhost:8080/notes/1

Deploying the Gin Application on Hostman App Platform
Copy link

Creating and Uploading the Repository
Copy link

To deploy the application using Hostman App Platform, first ensure your project is hosted in a Git repository. This example uses GitHub.

  1. Initialize a Git repository locally in your project directory:

git init -b main
git add .
git commit -m 'First commit'
  1. Push the repository to a remote server using the commands provided when creating a new GitHub repository:

git remote add origin git@github.com:your_user/your_repository.git
git push -u origin main

Setting Up Hostman App Platform
Copy link

  1. Go to the App Platform section in Hostman and click Create app.

  2. Under the Type section, choose the Backend tab and select the Gin framework.

  3. Connect your GitHub account by granting access to the repositories, or manually select the necessary repository.

  4. After connecting your GitHub account, select the repository containing your application in the Repository section.

  5. Choose a region where your application will be hosted.

  6. In the Configuration section, select the minimum settings; they are sufficient for this project. You can modify them later if needed.

  7. Leave the default values in the App settings section. For more complex projects, you may specify environment variables and custom build commands.

  8. Specify a name for your application and click Start deploy.

Deployment Process
Copy link

  • The deployment process can take up to 10 minutes. Once it’s completed, you will see the message “Deployment successfully completed” in the deployment logs.

  • Navigate to the Settings tab on the application page to view the domain assigned to your app.
    In the same section, you can modify the server configuration, edit deployment settings, and update the domain binding. If you connect a custom domain, a Let’s Encrypt SSL certificate will be automatically issued and renewed 7 days before expiration.

Testing the Application
Copy link

To verify that the application is working correctly, execute a curl request, replacing localhost with the assigned domain:

curl -X GET https://your_domain/notes

Conclusion
Copy link

In this tutorial, we have developed a basic web application for managing notes using the Gin framework and GORM library. The created RESTful API supports basic CRUD operations, making the application simple and user-friendly. You can also use our S3 compatible storage to save all the data you need for your app.

Gin proved to be an efficient and easy-to-learn tool. Its routing system and support for concurrent requests made development smoother. GORM facilitated database interaction by automating many tasks.

The application was successfully deployed on the Hostman App Platform, providing a fast and reliable deployment process. 

In the future, we can enhance the application by adding new features such as user authentication and advanced note search capabilities.

This project demonstrated how modern development tools like Gin and GORM simplify web application creation.