Como desenvolver uma API CRUD com Golang utilizando Gin e MongoDB

Início » Como desenvolver uma API CRUD com Golang utilizando Gin e MongoDB

Golang, também conhecida como Go, é uma linguagem de programação muito requisitada no mercado, com grande potencial em diversas aplicações. Quando utilizada em conjunto com frameworks como Gin, Revel ou gorilla/mux, é possível desenvolver APIs de forma eficiente. Neste guia, você aprenderá a criar uma API CRUD utilizando Golang, com o framework Gin para manipulação das requisições HTTP, e MongoDB como banco de dados.

Leia também: Vale a pena aprender Golang hoje?

Configuração inicial

Se ainda não possui o Go instalado em seu sistema, faça o download e instale-o. Após isso, crie um diretório para o projeto e inicialize um módulo Go dentro dele. Para isso, execute os seguintes comandos no terminal:

go mod init nome_do_modulo

Esse comando criará um arquivo go.mod com as informações do módulo, que servirá de base para os pacotes personalizados. Agora, instale o framework Gin para criar e gerenciar as rotas da API:

go get github.com/gin-gonic/gin

Em seguida, instale o driver do MongoDB para que possa armazenar e gerenciar os dados no banco de dados:

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

Conectando o Go ao MongoDB

Para conectar o Go ao MongoDB, você precisará da URL de conexão. Se estiver utilizando o MongoDB localmente, sua URI será semelhante a esta:

Mongo_URL := "mongodb://127.0.0.1:27017"

Crie uma pasta chamada databases no diretório raiz do projeto e adicione um arquivo database.go para gerenciar a conexão com o banco de dados. O código para a conexão será assim:

package database

import (
    "context"
    "log"
    "time"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

func ConnectDB() *mongo.Client {
    client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://127.0.0.1:27017"))
    if err != nil {
        log.Fatal(err)
    }

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    err = client.Connect(ctx)
    if err != nil {
        log.Fatal(err)
    }

    log.Println("Conectado ao MongoDB")
    return client
}

Recomenda-se usar arquivos .env para armazenar variáveis sensíveis, como a string de conexão do banco de dados.

Manipulando coleções do MongoDB

As coleções no MongoDB são responsáveis por armazenar os documentos. Para facilitar o acesso a essas coleções, crie uma pasta Collection e dentro dela um arquivo getCollection.go com o seguinte código:

package getcollection

import "go.mongodb.org/mongo-driver/mongo"

func GetCollection(client *mongo.Client, collectionName string) *mongo.Collection {
    return client.Database("meuAppGo").Collection(collectionName)
}

Essa função recupera a coleção especificada, neste caso, da base de dados meuAppGo.

Definindo o modelo de dados

Crie uma pasta model para organizar o modelo de dados. Dentro dela, crie um arquivo model.go que definirá o modelo de post, com título e conteúdo:

package model

import "go.mongodb.org/mongo-driver/bson/primitive"

type Post struct {
    ID      primitive.ObjectID `bson:"_id,omitempty"`
    Title   string             `bson:"title"`
    Article string             `bson:"article"`
}

Criando os endpoints CRUD

Agora, é hora de criar os endpoints para manipular os dados. Para isso, crie uma pasta chamada routes e, dentro dela, arquivos para cada ação: create.go, read.go, update.go e delete.go.

Endpoint POST (Criar)

O endpoint para criar novos posts ficará assim:

package routes

import (
    "context"
    "net/http"
    "time"
    "log"
    "github.com/gin-gonic/gin"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "CRUD_API/databases"
    "CRUD_API/model"
    "CRUD_API/Collection"
)

func CreatePost(c *gin.Context) {
    var DB = databases.ConnectDB()
    var postCollection = Collection.GetCollection(DB, "Posts")
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    var post model.Post
    if err := c.BindJSON(&post); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
        return
    }

    post.ID = primitive.NewObjectID()
    _, err := postCollection.InsertOne(ctx, post)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
        return
    }

    c.JSON(http.StatusCreated, gin.H{"message": "Post criado com sucesso!"})
}

Endpoint GET (Ler)

Para ler um post específico pelo ID:

package routes

import (
    "context"
    "net/http"
    "time"
    "github.com/gin-gonic/gin"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "CRUD_API/databases"
    "CRUD_API/model"
    "CRUD_API/Collection"
)

func ReadOnePost(c *gin.Context) {
    var DB = databases.ConnectDB()
    var postCollection = Collection.GetCollection(DB, "Posts")
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    postId := c.Param("postId")
    objId, _ := primitive.ObjectIDFromHex(postId)

    var post model.Post
    err := postCollection.FindOne(ctx, bson.M{"_id": objId}).Decode(&post)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
        return
    }

    c.JSON(http.StatusOK, gin.H{"data": post})
}

Endpoint PUT (Atualizar)

Para atualizar um post:

package routes

import (
    "context"
    "net/http"
    "time"
    "github.com/gin-gonic/gin"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "CRUD_API/databases"
    "CRUD_API/model"
    "CRUD_API/Collection"
)

func UpdatePost(c *gin.Context) {
    var DB = databases.ConnectDB()
    var postCollection = Collection.GetCollection(DB, "Posts")
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    postId := c.Param("postId")
    objId, _ := primitive.ObjectIDFromHex(postId)

    var post model.Post
    if err := c.BindJSON(&post); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
        return
    }

    update := bson.M{"title": post.Title, "article": post.Article}
    _, err := postCollection.UpdateOne(ctx, bson.M{"_id": objId}, bson.M{"$set": update})
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
        return
    }

    c.JSON(http.StatusOK, gin.H{"message": "Post atualizado com sucesso!"})
}

Endpoint DELETE (Excluir)

Para remover um post pelo ID:

package routes

import (
    "context"
    "net/http"
    "time"
    "github.com/gin-gonic/gin"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "CRUD_API/databases"
    "CRUD_API/Collection"
)

func DeletePost(c *gin.Context) {
    var DB = databases.ConnectDB()
    var postCollection = Collection.GetCollection(DB, "Posts")
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    postId := c.Param("postId")
    objId, _ := primitive.ObjectIDFromHex(postId)

    _, err := postCollection.DeleteOne(ctx, bson.M{"_id": objId})
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
        return
    }

    c.JSON(http.StatusOK, gin.H{"message": "Post deletado com sucesso!"})
}

Executando o projeto

No arquivo principal main.go, importe as rotas e configure o roteador:

package main

import (
    "CRUD_API/routes"
    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()

    router.POST("/create", routes.CreatePost)
    router.GET("/read/:postId", routes.ReadOnePost)
    router.PUT("/update/:postId", routes.UpdatePost)
    router.DELETE("/delete/:postId", routes.DeletePost)

    router.Run(":3000")
}

Conclusão

Você criou uma API CRUD completa com Golang, Gin e MongoDB. Essa estrutura é apenas o início para projetos mais robustos e escaláveis.

Leia também: Como criar um ambiente de desenvolvimento PHP no Linux

brayan

Brayan Monteiro

Bacharel em Sistemas de Informação pela Faculdade Maurício de Nassau e desenvolvedor PHP. Além de programador, produzo conteúdo e gerencio blogs. Sou especialista em desenvolvimento de software, SEO de sites e em negócios digitais.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

four × five =