Menu Docs
Página inicial do Docs
/ /

Tutorial: Criar um Aplicativo da Web com o Driver Go e o Gi

Este tutorial mostra como criar um aplicação web usando o MongoDB Go Driver e a estrutura web Gi.

O Gi é um framework web rápido e leve para Go. Seu design mínima e modular o torna ideal para construir servidores web, APIs e microsserviços.

Neste tutorial, você pode aprender como criar um aplicação da web com os seguintes pontos de conexão que se conectam a um banco de dados MongoDB :

  • Um endpoint para recuperar todos os filmes de uma coleção

  • Um endpoint para recuperar um único filme por ID

  • Um endpoint para executar operações de agregação na collection movies

O tutorial utiliza a movies collection no sample_mflix banco de dados a partir do conjunto de dados de amostra do Atlas . Para saber como criar um cluster MongoDB Atlas gratuito e carregar os conjuntos de dados de amostra, consulte o guia Iniciar com Atlas .

Antes de iniciar este tutorial, verifique se você tem o seguinte:

  • Go instalado em sua máquina de desenvolvimento

  • Um sistema MongoDB . Você pode utilizar um agrupamento de MongoDB Atlas gratuito para este tutorial. Para mais informações, consulte o guia Iniciar com Atlas .

  • Uma ferramenta para testar sua API, como curl ou Postman.

1

Crie um novo diretório para seu projeto e navegue até ele:

mkdir mflix
cd mflix

Inicialize um novo módulo Go para gerenciar as dependências do seu projeto :

go mod init mflix
2

Instale as dependências necessárias para seu projeto:

go get github.com/gin-gonic/gin
go get go.mongodb.org/mongo-driver/v2/mongo
1

Crie um arquivo main.go no diretório do projeto e adicione o seguinte código para configurar um aplicação Gi básico :

package main
import (
"log"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello World",
})
})
if err := r.Run(); err != nil {
log.Fatal("Failed to start server:", err)
}
}
2

Execute o seguinte código para testar se seu aplicação básico está funcionando:

go run main.go

Navegue até http://localhost:8080 em seu navegador da web para ver uma resposta JSON com a mensagem "Hello World".

Atualize seu arquivo main.go para se conectar ao MongoDB. Substitua o código existente pelo seguinte código para se conectar à sua implantação do MongoDB :

package main
import (
"context"
"log"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options"
)
// Replace with your MongoDB connection string
const uri = "<connection-string>"
func main() {
// Connects to MongoDB
serverAPI := options.ServerAPI(options.ServerAPIVersion1)
opts := options.Client().ApplyURI(uri).SetServerAPIOptions(serverAPI)
client, err := mongo.Connect(opts)
if err != nil {
log.Fatal("Could not connect to MongoDB:", err)
}
// Ensures the client disconnects when main exits
defer func() {
if err := client.Disconnect(context.TODO()); err != nil {
log.Fatal("Error disconnecting from MongoDB:", err)
}
}()
// Pings the database to verify connection
if err := client.Ping(context.TODO(), nil); err != nil {
log.Fatal("Could not ping MongoDB:", err)
}
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello World",
})
})
if err := r.Run(); err != nil {
log.Fatal("Failed to start server:", err)
}
}

Substitua o <connection-string> espaço reservado por sua string de conexão real do MongoDB . Para saber mais sobre como obter sua string de conexão, consulte o guia Conectar a um cluster.

Agora, você pode adicionar três endpoints para interagir com os dados do filme. Atualize seu arquivo main.go para incluir as importações e implementações de endpoint necessárias.

1

Adicione as importações necessárias no topo do seu arquivo:

import (
"context"
"log"
"net/http"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/v2/bson"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options"
)
2

Adicione os seguintes manipuladores de rota após sua função connectToMongoDB:

// GET /movies - Retrieves all movies
func getMovies(c *gin.Context, client *mongo.Client) {
// Find all movies in the collection
cursor, err := client.Database("sample_mflix").Collection("movies").Find(c.Request.Context(), bson.D{})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
defer cursor.Close(c.Request.Context())
// Decodes all results
var movies []bson.D
if err = cursor.All(c.Request.Context(), &movies); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// Returns the movies
c.JSON(http.StatusOK, movies)
}
// GET /movies/:id - Retrieves a movie by ID
func getMovieByID(c *gin.Context, client *mongo.Client) {
// Gets the movie ID from the URL parameter as a string
idStr := c.Param("id")
// Converts string ID to MongoDB ObjectID
id, err := bson.ObjectIDFromHex(idStr)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid movie ID format"})
return
}
// Finds the movie by ObjectID
var movie bson.D
err = client.Database("sample_mflix").Collection("movies").FindOne(c.Request.Context(), bson.D{{"_id", id}}).Decode(&movie)
if err != nil {
if err == mongo.ErrNoDocuments {
c.JSON(http.StatusNotFound, gin.H{"error": "Movie not found"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// Returns the movie
c.JSON(http.StatusOK, movie)
}
// POST /movies/aggregations - Runs aggregation pipeline
func aggregateMovies(c *gin.Context, client *mongo.Client) {
// Gets aggregation pipeline from request body
var pipeline interface{}
if err := c.ShouldBindJSON(&pipeline); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid aggregation pipeline"})
return
}
// Executes the aggregation pipeline
cursor, err := client.Database("sample_mflix").Collection("movies").Aggregate(c.Request.Context(), pipeline)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
defer cursor.Close(c.Request.Context())
// Decodes the results
var result []bson.D
if err = cursor.All(c.Request.Context(), &result); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// Returns the aggregation result
c.JSON(http.StatusOK, result)
}
3

Atualize sua função main para registrar as novas rotas:

func main() {
// Connects to MongoDB
serverAPI := options.ServerAPI(options.ServerAPIVersion1)
opts := options.Client().ApplyURI(uri).SetServerAPIOptions(serverAPI)
client, err := mongo.Connect(opts)
if err != nil {
log.Fatal("Could not connect to MongoDB:", err)
}
// Ensures the client disconnects when main exits
defer func() {
if err := client.Disconnect(context.TODO()); err != nil {
log.Fatal("Error disconnecting from MongoDB:", err)
}
}()
// Pings the database to verify connection
if err := client.Ping(context.TODO(), nil); err != nil {
log.Fatal("Could not ping MongoDB:", err)
}
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello World",
})
})
// Registers movie endpoints
r.GET("/movies", func(c *gin.Context) {
getMovies(c, client)
})
r.GET("/movies/:id", func(c *gin.Context) {
getMovieByID(c, client)
})
r.POST("/movies/aggregations", func(c *gin.Context) {
aggregateMovies(c, client)
})
if err := r.Run(); err != nil {
log.Fatal("Failed to start server:", err)
}
}

Você pode testar os endpoints criados para garantir que funcionem conforme o esperado.

Reinicie seu servidor e navegue até http://localhost:8080/movies em seu navegador da web. Você deverá ver uma resposta JSON contendo uma array de filmes do conjunto de dados de amostra.

Para testar o endpoint de filme único, copie um valor _id da resposta do filme e navegue até http://localhost:8080/movies/{id}.

Por exemplo, se você navegar para http://localhost:8080/movies/573a1390f29313caabcd42e8, a resposta no navegador será semelhante ao seguinte:

{
"_id": "573a1390f29313caabcd42e8",
"awards": {
"wins": 1,
"nominations": 0,
"text": "1 win."
},
"cast": [
"A.C. Abadie",
"Gilbert M. 'Broncho Billy' Anderson",
"George Barnes",
"Justus D. Barnes"
],
"countries": [
"USA"
],
"directors": [
"Edwin S. Porter"
],
"fullplot": "Among the earliest existing films in American cinema - notable as the first film that presented a narrative story to tell - it depicts a group of cowboy outlaws who hold up a train and rob the passengers. They are then pursued by a Sheriff's posse. Several scenes have color included - all hand tinted.",
"genres": [
"Short",
"Western"
],"
....
}

Para testar o endpoint de agregação , é necessário fazer uma solicitação POST. Você pode usar uma ferramenta como curl ou Postman para enviar uma solicitação com um pipeline de agregação no corpo da solicitação.

O exemplo de agregação a seguir conta filmes de comedia por ano:

[
{"$match": {"genres": "Comedy"}},
{"$group": {
"_id": "$year",
"count": {"$sum": 1}
}},
{"$sort": {"count": -1}}
]

Execute o seguinte código no seu terminal para testar esse endpoint com curl:

curl -X POST http://localhost:8080/movies/aggregations \
-H "Content-Type: application/json" \
-d '[
{"$match": {"genres": "Comedy"}},
{"$group": {"_id": "$year", "count": {"$sum": 1}}},
{"$sort": {"count": -1}}
]'
[
{
"_id": 2014,
"count": 287
},
{
"_id": 2013,
"count": 286
},
{
"_id": 2009,
"count": 268
},
{
"_id": 2011,
"count": 263
},
{
"_id": 2006,
"count": 260
},
...
]

Aviso

O endpoint de agregação neste tutorial permite que os usuários executem qualquer pipeline de agregação . Em um ambiente de produção, você deve limitar os tipos de operações e validar a entrada para evitar possíveis problemas de segurança ou de desempenho.

O seguinte arquivo mostra o código completo do seu aplicação da web :

package main
import (
"context"
"log"
"net/http"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/v2/bson"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options"
)
// Replace with your MongoDB connection string
const uri = "YOUR-CONNECTION-STRING-HERE"
func main() {
// Connects to MongoDB
serverAPI := options.ServerAPI(options.ServerAPIVersion1)
opts := options.Client().ApplyURI(uri).SetServerAPIOptions(serverAPI)
client, err := mongo.Connect(opts)
if err != nil {
log.Fatal("Could not connect to MongoDB:", err)
}
// Ensures the client disconnects when main exits
defer func() {
if err := client.Disconnect(context.TODO()); err != nil {
log.Fatal("Error disconnecting from MongoDB:", err)
}
}()
// Pings the database to verify connection
if err := client.Ping(context.TODO(), nil); err != nil {
log.Fatal("Could not ping MongoDB:", err)
}
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello World",
})
})
// Registers movie endpoints
r.GET("/movies", func(c *gin.Context) {
getMovies(c, client)
})
r.GET("/movies/:id", func(c *gin.Context) {
getMovieByID(c, client)
})
r.POST("/movies/aggregations", func(c *gin.Context) {
aggregateMovies(c, client)
})
if err := r.Run(); err != nil {
log.Fatal("Failed to start server:", err)
}
}
// GET /movies - Retrieves all movies
func getMovies(c *gin.Context, client *mongo.Client) {
// Find all movies in the collection
cursor, err := client.Database("sample_mflix").Collection("movies").Find(c.Request.Context(), bson.D{})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
defer cursor.Close(c.Request.Context())
// Decodes all results
var movies []bson.D
if err = cursor.All(c.Request.Context(), &movies); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// Returns the movies
c.JSON(http.StatusOK, movies)
}
// GET /movies/:id - Retrieves a movie by ID
func getMovieByID(c *gin.Context, client *mongo.Client) {
// Gets the movie ID from the URL parameter as a string
idStr := c.Param("id")
// Converts string ID to MongoDB ObjectID
id, err := bson.ObjectIDFromHex(idStr)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid movie ID format"})
return
}
// Finds the movie by ObjectID
var movie bson.D
err = client.Database("sample_mflix").Collection("movies").FindOne(c.Request.Context(), bson.D{{"_id", id}}).Decode(&movie)
if err != nil {
if err == mongo.ErrNoDocuments {
c.JSON(http.StatusNotFound, gin.H{"error": "Movie not found"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// Returns the movie
c.JSON(http.StatusOK, movie)
}
// POST /movies/aggregations - Runs aggregation pipeline
func aggregateMovies(c *gin.Context, client *mongo.Client) {
// Gets aggregation pipeline from request body
var pipeline interface{}
if err := c.ShouldBindJSON(&pipeline); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid aggregation pipeline"})
return
}
// Executes the aggregation pipeline
cursor, err := client.Database("sample_mflix").Collection("movies").Aggregate(c.Request.Context(), pipeline)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
defer cursor.Close(c.Request.Context())
// Decodes the results
var result []bson.D
if err = cursor.All(c.Request.Context(), &result); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// Returns the aggregation result
c.JSON(http.StatusOK, result)
}

Agora você tem um aplicação básico que demonstra o seguinte:

  • Configura um projeto Go com o framework web Gi e o driver Go.

  • Conecta-se a um banco de dados MongoDB usando o driver Go.

  • Implementa endpoints de API REST que executam operações MongoDB para localizar documentos, localizar um único documento e executar pipelines de agregação .

  • Manipula cenários comuns, como converter IDs de string em ObjectIDs.

  • Implementa o tratamento adequado de erros para operações de banco de dados .

Para desenvolver ainda mais seu aplicação, considere as seguintes etapas a seguir:

  • Adicionar validação de entrada e limitação de solicitação para o endpoint de agregação

  • Implementar autenticação e autorização do

  • Adicionar índices para melhorar o desempenho da query

Para saber mais sobre os conceitos deste tutorial, consulte os seguintes recursos:

Voltar

Armazenar arquivos grandes