Docs Menu
Docs Home
/ /

튜토리얼: 고 (Go) 운전자 및 Gin을 사용하여 웹 애플리케이션 빌드

이 튜토리얼에서는 MongoDB 고 (Go) 드라이버 와 Gin 웹 프레임워크 사용하여 웹 애플리케이션 빌드 방법을 보여줍니다.

Gin은 고 (Go) 위한 빠르고 가벼운 웹 프레임워크 입니다. 최소한의 모듈식 설계로 웹 서버, API 및 마이크로서비스 구축에 이상적입니다.

이 튜토리얼에서는 MongoDB database 에 연결하는 다음 엔드포인트를 사용하여 웹 애플리케이션 만드는 방법을 학습 수 있습니다.

  • 컬렉션 에서 모든 영화를 조회 하는 엔드포인트

  • ID 로 단일 영화를 조회 하는 엔드포인트

  • movies 컬렉션 에서 집계 작업을 실행 위한 엔드포인트입니다.

이 튜토리얼에서는 Atlas 샘플 데이터 세트의 데이터베이스 movies 에 있는 컬렉션 sample_mflix 사용합니다. 무료 MongoDB Atlas cluster 생성하고 샘플 데이터 세트를 로드하는 방법을 학습 Atlas 시작하기 가이드 참조하세요.

이 튜토리얼을 시작하기 전에 다음 사항이 있는지 확인하세요.

1

프로젝트 에 대한 새 디렉토리 만들고 해당 디렉토리로 이동합니다.

mkdir mflix
cd mflix

새 고 (Go) 모듈을 초기화하여 프로젝트 종속성을 관리 .

go mod init mflix
2

프로젝트 에 필요한 종속성을 설치합니다.

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

프로젝트 디렉토리 에 main.go 파일 만들고 다음 코드를 추가하여 기본 Gin 애플리케이션 설정하다 합니다.

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

다음 코드를 실행하여 기본 애플리케이션 작동하는지 테스트합니다.

go run main.go

웹 브라우저에서 http://localhost:8080 로 이동하여 'Hello World' 메시지가 포함된 JSON 응답을 확인합니다.

main.go 파일 업데이트하여 MongoDB 에 연결합니다. 기존 코드를 다음 코드로 대체하여 MongoDB deployment 에 연결합니다.

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)
}
}

자리 <connection-string> 표시자를 실제 MongoDB 연결 문자열 로 바꿉니다. 연결 문자열 얻는 방법에 대해 자세히 학습 클러스터에 연결 가이드 를 참조하세요.

이제 엔드포인트 3개를 추가하여 영화 데이터와 상호 작용 수 있습니다. 필요한 가져오기 및 엔드포인트 구현을 포함하도록 main.go 파일 업데이트합니다.

1

파일 상단에 필요한 가져오기를 추가합니다.

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

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

main 함수를 업데이트하여 새 경로를 등록합니다.

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)
}
}

생성한 엔드포인트를 테스트하여 예상대로 작동하는지 확인할 수 있습니다.

서버 다시 시작하고 웹 브라우저에서 http://localhost:8080/movies (으)로 이동합니다. 샘플 데이터 세트의 영화 배열 포함된 JSON 응답이 표시되어야 합니다.

단일 영화 엔드포인트를 테스트하려면 영화 응답에서 _id 값을 복사하고 http://localhost:8080/movies/{id}로 이동합니다.

예시 들어 http://localhost:8080/movies/573a1390f29313caabcd42e8(으)로 이동하면 브라우저의 응답은 다음과 유사합니다.

{
"_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"
],"
....
}

집계 엔드포인트를 테스트하려면 POST 요청 해야 합니다. curl 또는 Postman과 같은 도구를 사용하여 요청 본문의 집계 파이프라인 사용하여 요청 보낼 수 있습니다.

다음 집계 예시 연도별 희극 영화 수를 계산합니다.

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

터미널에서 다음 코드를 실행하여 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
},
...
]

경고

이 튜토리얼의 집계 엔드포인트를 통해 사용자는 모든 집계 파이프라인 실행 수 있습니다. 프로덕션 환경에서는 잠재적인 보안 문제나 성능 문제를 방지하기 위해 작업 유형을 제한하고 입력의 유효성을 검사해야 합니다.

다음 파일 웹 애플리케이션 의 전체 코드를 보여줍니다.

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)
}

이제 다음을 보여주는 기본 애플리케이션 생겼습니다.

  • Gin 웹 프레임워크 와 고 (Go) 운전자 사용하여 고 (Go) 프로젝트 설정합니다.

  • 고 (Go) 운전자 사용하여 MongoDB database 에 연결합니다.

  • MongoDB 작업을 수행하여 문서를 찾고, 단일 문서 찾고, 집계 파이프라인을 실행 REST API 엔드포인트를 구현합니다.

  • 문자열 ID를 ObjectID로 변환하는 등의 일반적인 시나리오를 처리합니다.

  • 데이터베이스 작업에 대한 적절한 오류 처리를 구현합니다.

애플리케이션 추가로 개발하려면 다음 단계를 고려하세요.

  • 집계 엔드포인트에 대한 입력 유효성 검사 및 요청 제한 추가

  • 인증 및 권한 부여 부여 구현

  • 인덱스를 추가하여 쿼리 성능 개선

이 튜토리얼의 개념에 대해 자세히 학습 다음 리소스를 참조하세요.

돌아가기

대용량 파일 저장