Последнее обновление 03.01.2023 — Василий Иванов
Golang — один из самых высокооплачиваемых и востребованных языков программирования со множеством приложений. В сочетании с такими фреймворками, как Gin, Revel и gorilla/mux, вы можете легко создать API с помощью Go.
Узнайте, как создать CRUD API в Golang с помощью HTTP-фреймворка Gin.
Первоначальная настройка и установка
Начните работу с Golang, установив его на свой компьютер, если вы еще этого не сделали.
После установки следующим шагом будет создание корневой папки проекта на вашем компьютере и инициализация модуля Go в этом корневом каталоге.
Для этого откройте CLI, перейдите в корневую папку проекта и выполните:
go mod init module_name
Вы увидите имя своего модуля (например, CRUD_API) и его версию, когда откроете файл go.mod. Все пользовательские пакеты будут исходить из этого родительского модуля. Таким образом, любой импортированный пользовательский пакет имеет вид:
import(package CRUD_API/package-directory-name)
Затем установите пакеты, необходимые для создания CRUD API. В этом случае используйте Gin Gonic для маршрутизации конечных точек API:
go get github.com/gin-gonic/gin
Теперь установите драйвер MongoDB для хранения данных:
go get go.mongodb.org/mongo-driver/mongo
Как подключиться Перейти к MongoDB
Все, что вам нужно, это ваш URI MongoDB для подключения Golang к базе данных. Обычно это выглядит так, если вы подключаетесь к MongoDB Atlas локально:
Mongo_URL = "mongodb://127.0.0.1:27017"
Теперь создайте новую папку в корневом каталоге вашего проекта и назовите ее databases. Создайте файл Go внутри этой папки и назовите его database.go.
Это ваш пакет базы данных, и он начинается с импорта необходимых библиотек:
package database
import (
"context"
"fmt"
"log"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func ConnectDB() *mongo.Client {
Mongo_URL := "mongodb://127.0.0.1:27017"
client, err := mongo.NewClient(options.Client().ApplyURI(Mongo_URL))
if err != nil {
log.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), 10 * time.Second)
err = client.Connect(ctx)
defer cancel()
if err != nil {
log.Fatal(err)
}
fmt.Println("Connected to mongoDB")
return client
}
Лучше всего скрывать переменные среды, такие как строка подключения к базе данных, в файле .env с помощью пакета dotenv. Это делает ваш код более переносимым и пригодится, например, при использовании экземпляра облачного кластера MongoDB.
Функция ConnectDB устанавливает соединение и возвращает новый объект клиента MongoDB.
Создать коллекцию баз данных
MongoDB хранит данные в коллекциях, которые обеспечивают интерфейс для данных базовой базы данных.
Чтобы реализовать функцию получения коллекции, начните с создания новой папки Collection в корне проекта. Теперь создайте новый файл Go, getCollection.go, который получает коллекцию из базы данных:
package getcollection
import (
"go.mongodb.org/mongo-driver/mongo"
)
func GetCollection(client *mongo.Client, collectionName string) *mongo.Collection {
collection := client.Database("myGoappDB").Collection("Posts")
return collection
}
Эта функция получает коллекцию из базы данных MongoDB. Имя базы данных в данном случае — myGoappDB, а ее коллекция — Posts.
Создайте модель базы данных
Создайте новую папку в корневом каталоге и назовите ее model. Эта папка обрабатывает вашу модель базы данных.
Создайте новый файл Go внутри этой папки и назовите его model.go. Ваша модель в данном случае представляет собой сообщение в блоге с заголовком:
package model
import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
type Post struct {
ID primitive.ObjectID
Title string
Article string
}
Создание CRUD API с помощью Go
Далее следует создание CRUD API. Чтобы начать с этого раздела, создайте новую папку в корневом каталоге вашего проекта для обработки ваших конечных точек. Назовите это маршрутами.
Создайте в этой папке отдельный файл Go для каждого действия. Например, вы можете назвать их create.go, read.go, update.go и delete.go. Вы экспортируете эти обработчики как пакет маршрутов.
Как создать конечную точку POST в Go
Начните с определения конечной точки POST для записи данных в базу данных.
Внутри route/create.go добавьте следующее:
package routes
import (
getcollection "CRUD_API/Collection"
database "CRUD_API/databases"
model "CRUD_API/model"
"context"
"log"
"net/http"
"time"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson/primitive"
)
func CreatePost(c *gin.Context) {
var DB = database.ConnectDB()
var postCollection = getcollection.GetCollection(DB, "Posts")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
post := new(model.Posts)
defer cancel()
if err := c.BindJSON(&post); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"message": err})
log.Fatal(err)
return
}
postPayload := model.Posts{
Id: primitive.NewObjectID(),
Title: post.Title,
Article: post.Article,
}
result, err := postCollection.InsertOne(ctx, postPayload)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": err})
return
}
c.JSON(http.StatusCreated, gin.H{"message": "Posted successfully", "Data": map[string]interface{}{"data": result}})
}
Этот код начинается с импорта пользовательских модулей проекта. Затем он импортирует сторонние пакеты, включая Gin и драйвер MongoDB.
Кроме того, postCollection содержит коллекцию базы данных. Примечательно, что c.BindJSON(«post») — это экземпляр модели JSONified, который вызывает каждое поле модели как postPayload; это входит в базу данных.
Как создать конечную точку GET
Конечная точка GET в route/read.go считывает один документ из базы данных по его уникальному идентификатору. Он также начинается с импорта пользовательских и сторонних пакетов:
package routes
import (
getcollection "CRUD_API/Collection"
database "CRUD_API/databases"
model "CRUD_API/model"
"context"
"net/http"
"time"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
func ReadOnePost(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
var DB = database.ConnectDB()
var postCollection = getcollection.GetCollection(DB, "Posts")
postId := c.Param("postId")
var result model.Posts
defer cancel()
objId, _ := primitive.ObjectIDFromHex(postId)
err := postCollection.FindOne(ctx, bson.M{"id": objId}).Decode(&result)
res := map[string]interface{}{"data": result}
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": err})
return
}
c.JSON(http.StatusCreated, gin.H{"message": "success!", "Data": res})
}
Переменная postId является объявлением параметра. Он получает идентификатор объекта документа как objId.
Однако результатом является экземпляр модели базы данных, которая позже содержит возвращенный документ как res.
Как создать конечную точку PUT
Обработчик PUT в route/update.go аналогичен обработчику POST. На этот раз он обновляет существующий пост по его уникальному идентификатору объекта:
package routes
import (
getcollection "CRUD_API/Collection"
database "CRUD_API/databases"
model "CRUD_API/model"
"context"
"net/http"
"time"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
func UpdatePost(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 10 * time.Second)
var DB = database.ConnectDB()
var postCollection = getcollection.GetCollection(DB, "Posts")
postId := c.Param("postId")
var post model.Posts
defer cancel()
objId, _ := primitive.ObjectIDFromHex(postId)
if err := c.BindJSON(&post); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": err})
return
}
edited := bson.M{"title": post.Title, "article": post.Article}
result, err := postCollection.UpdateOne(ctx, bson.M{"id": objId}, bson.M{"$set": edited})
res := map[string]interface{}{"data": result}
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": err})
return
}
if result.MatchedCount < 1 {
c.JSON(http.StatusInternalServerError, gin.H{"message": "Data doesn't exist"})
return
}
c.JSON(http.StatusCreated, gin.H{"message": "data updated successfully!", "Data": res})
}
Формат JSON экземпляра модели (сообщения) вызывает каждое поле модели из базы данных. Переменная результата использует оператор MongoDB $set для обновления требуемого документа, вызываемого его идентификатором объекта.
Условие result.MatchedCount предотвращает запуск кода, если в базе данных нет записи или переданный идентификатор недействителен.
Создание конечной точки DELETE
Конечная точка DELETE в delete.go удаляет документ на основе идентификатора объекта, переданного в качестве параметра URL:
package routes
import (
getcollection "CRUD_API/Collection"
database "CRUD_API/databases"
"context"
"net/http"
"time"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
func DeletePost(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
var DB = database.ConnectDB()
postId := c.Param("postId")
var postCollection = getcollection.GetCollection(DB, "Posts")
defer cancel()
objId, _ := primitive.ObjectIDFromHex(postId)
result, err := postCollection.DeleteOne(ctx, bson.M{"id": objId})
res := map[string]interface{}{"data": result}
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": err})
return
}
if result.DeletedCount < 1 {
c.JSON(http.StatusInternalServerError, gin.H{"message": "No data to delete"})
return
}
c.JSON(http.StatusCreated, gin.H{"message": "Article deleted successfully", "Data": res})
}
Этот код удаляет запись с помощью функции DeleteOne. Он также использует свойство result.DeletedCount, чтобы предотвратить запуск кода, если база данных пуста или идентификатор объекта недействителен.
Создайте файл запуска API
Наконец, создайте main.go внутри корневого каталога вашего проекта. Ваша окончательная структура проекта должна выглядеть так:
Этот файл обрабатывает выполнение маршрутизатора для каждой конечной точки:
package main
import (
routes "CRUD_API/routes"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.POST("/", routes.CreatePost)
// called as localhost:3000/getOne/{id}
router.GET("getOne/:postId", routes.ReadOnePost)
// called as localhost:3000/update/{id}
router.PUT("/update/:postId", routes.UpdatePost)
// called as localhost:3000/delete/{id}
router.DELETE("/delete/:postId", routes.DeletePost)
router.Run("localhost: 3000")
}
Этот файл является основным пакетом, который запускает другие файлы. Он начинается с импорта обработчиков маршрутов. Далее идет переменная маршрутизатора, экземпляр gin, который вызывает действия HTTP и вызывает каждую конечную точку по имени ее функции из пакета маршрутов.
Ваш проект CRUD работает на локальном хосте: 3000. Чтобы запустить сервер и протестировать CRUD API, выполните следующую команду в базовом каталоге:
go run main.go
Превратите свой проект Golang CRUD в полезный продукт
Вы успешно создали CRUD API с помощью Go; поздравляю! Хотя это небольшой проект, вы видели, что нужно для выполнения обычных HTTP-запросов в Go.
Вы можете проявить больше творчества, превратив это в более практичное приложение, которое приносит пользу пользователям. Go — подходящий язык программирования для целого ряда случаев использования.