REST API با استفاده از GO(gin) و Mongo

در این وبلاگ، ما یک سرور API RESTful با دو نقطه پایانی خواهیم ساخت. پروژه مثال، مخزن دادههای مربوط به کتابها در یک کتابخانه خواهد بود.
این شامل بخش های زیر است:
- طراحی نقاط پایانی API
- یک پوشه برای کد ایجاد کنید.
- با استفاده از qmgo به MongoDB متصل شوید
- کنترل کننده ها را بنویسید
- یک کتاب جدید اضافه کنید
- همه کتاب ها را دریافت کنید
- یک کتاب خاص بگیرید
- یک کتاب خاص را حذف کنید
پیش نیازها:
- نصب Go 1.20 یا بالاتر. برای دستورالعمل نصب، مراجعه کنید.
- نصب MongoDB 6.0 یا بالاتر. برای دستورالعمل نصب، مراجعه کنید
- هر ویرایشگر متن یا IDE که داشته باشیم به خوبی کار خواهد کرد.
طراحی نقاط پایانی API:
ما یک API ایجاد خواهیم کرد که دسترسی به کتابهای موجود در یک کتابخانه را فراهم میکند. بنابراین ما باید نقاط پایانی را ارائه کنیم که از طریق آنها مشتری بتواند کتابهای موجود در کتابخانه را دریافت، اضافه یا حذف کند.
در اینجا نقاط پایانی است که در این آموزش ایجاد خواهیم کرد.
/books
GET – فهرستی از همه کتابها را دریافت کنید که بهعنوان JSON برگردانده شدهاند.
POST – یک کتاب جدید از داده های درخواست ارسال شده به عنوان JSON اضافه کنید.
/books/:id
GET – کتابی را با شناسه آن دریافت کنید و داده های کتاب را به صورت JSON برگردانید.
PATCH – یک کتاب را با شناسه آن به روز کنید و داده های کتاب را به صورت JSON برگردانید.
DELETE – یک کتاب را با شناسه آن حذف کنید و وضعیت حذف را به صورت JSON برگردانید.
یک پوشه برای کد ما ایجاد کنید:
برای شروع، ما یک پروژه برای کدی که می خواهیم بنویسیم ایجاد می کنیم.
با استفاده از خط فرمان، یک پوشه برای کد خود به نام books ایجاد کنید.
$ mkdir books
$ cd books
ماژولی ایجاد کنید که در آن بتوانیم وابستگی ها را مدیریت کنیم.
را اجرا کنید go mod init
دستور، به آن مسیر ماژول را می دهیم که کد ما در آن قرار خواهد گرفت.
$ go mod init books
go: creating new go.mod: module books
این دستور یک فایل go.mod ایجاد می کند که در آن وابستگی هایی که اضافه می کنیم برای ردیابی لیست می شوند.
با استفاده از ویرایشگر IDE/Text، فایلی به نام main.go در فهرست کتاب ها ایجاد کنید. ما کد Go خود را در این فایل می نویسیم.
در main.go، در بالای فایل، اعلان بسته زیر و تابع اصلی را اضافه کنید که هنگام اجرای کد فراخوانی می شود زیرا یک برنامه مستقل (برخلاف کتابخانه) همیشه در بسته اصلی است.
package main
func main() {
}
برای اجرای برنامه از go run .
در زیر اعلان بسته، شروع به نوشتن کد اتصال به MongoDB می کنیم.
qmgo را با استفاده از cmd زیر نصب کنید
go get github.com/gin-gonic/gin
بسته “github.com/qiniu/qmgo” را وارد کرده و متغیر را اعلام کنید database
و collection
و آنها را در تابع اصلی مقداردهی کنید تا بعداً بتوان از آن برای انجام عملیات CRUD روی داده ها در پایگاه داده استفاده کرد.
var database *qmgo.Database
var collection *qmgo.Collection
func main() {
// create new Client
const databaseURI = "mongodb://localhost:27017"
fmt.Println("Connecting to database", databaseURI)
ctx := context.Background()
connection, err := qmgo.NewClient(ctx, &qmgo.Config{Uri: databaseURI})
database = connection.Database("test") // creating Database connection
collection = database.Collection("books") // get the collection
defer func() {
if err = connection.Close(ctx); err != nil {
fmt.Println("Closing Connection to database", databaseURI)
panic(err)
}
}()
}
اکنون به نوشتن هندلرها و پیکربندی برنامه برای گوش دادن به پورت http ادامه می دهیم (در مورد ما 8000
) در تابع اصلی.
جین را با استفاده از cmd زیر نصب کنید
go get github.com/gin-gonic/gin
و آن را در فایل اصلی وارد کنید
router := gin.Default() // create router using gin
// register routes
router.POST("/books", CreateBook)
fmt.Println("Service is up & running at localhost:8000")
router.Run(":8000") // register router to port 8000
در اینجا ما یک روتر POST ثبت کردهایم، بیایید پیش برویم و تابع CreateBook را برای رسیدگی به درخواست ایجاد ایجاد کنیم.
یک فایل books.go جدید ایجاد کنید که در آن کد رسیدگی به درخواست ها را بنویسیم
ساختار درخواست و پاسخ را برای کتاب ها ایجاد کنید:
// form:"title" to map the JSON field name to the struct
// binding:"required" to enforce the value is required
type BookCreateUpdateRequest struct {
Title string `form:"title" binding:"required"`
Author string `form:"author"`
}
// json:"id" to map the struct Name to its Json field name
type BookResponse struct {
Id primitive.ObjectID `json:"id"`
Title string `json:"title"`
Author string `json:"author"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
ساختار مدل پایگاه داده را ایجاد کنید:
type Book struct {
field.DefaultField `bson:"inline"`
Title string `bson:"title" validate:"required"`
Author string `bson:"author"`
}
بیایید CreateBookmethod را برای رسیدگی به درخواستهای ایجاد کتاب ایجاد کنیم.
func CreateBook(ctx *gin.Context) {
var newBook BookCreateUpdateRequest
// to bind the received JSON to BookRequest to strip the unnecessary fields.
if err := ctx.ShouldBind(&newBook); err != nil {
ctx.JSON(http.StatusBadRequest, "Invalid Request")
return
}
// setting data to book model struct
book := Book{
Title: newBook.Title,
Author: newBook.Author,
}
_, err := collection.InsertOne(ctx, &book) //Inserting the Book Data to database
// to send error response if any error occurs
if err != nil {
ctx.JSON(http.StatusInternalServerError, "Something went wrong, Try again after sometime")
return
}
// to send success response on completion
ctx.JSON(http.StatusCreated, GetBooksResponse(book))
}
func GetBooksResponse(book Book) (bookResponse BookResponse) {
// setting response for book
bookResponse = BookResponse{
Id: book.DefaultField.Id,
Title: book.Title,
Author: book.Author,
CreatedAt: book.CreateAt,
UpdatedAt: book.UpdateAt,
}
return
}
در کد بالا، از متد GetBooksResponse برای تنظیم پاسخی که قرار است ارسال کنیم استفاده می کنیم (از این روش برای سایر پاسخ های API نیز استفاده خواهیم کرد).
در زیر Handlers برای Get, List, Update و Delete آمده است.
دریافت API جزئیات کتاب:
func GetBook(ctx *gin.Context) {
// to get and convert the received path variable to desired type
bookId, err := primitive.ObjectIDFromHex(ctx.Param("bookId"))
if err != nil {
ctx.JSON(http.StatusBadRequest, "Invalid Request")
return
}
//Getting the Book Data from database
var book Book
err = collection.Find(ctx, bson.M{"_id": bookId}).One(&book)
// to send error response if any error occurs
if err != nil {
ctx.JSON(http.StatusNotFound, "Book Not Found")
return
}
// to send success response on completion
ctx.JSON(http.StatusOK, GetBooksResponse(book))
}
در کد بالا bson.M{"_id": bookId}
برای یافتن کتاب توسط Id و One برای اتصال داده mongo به متغیر book استفاده می شود
بهروزرسانی یک API کتاب:
func UpdateBook(ctx *gin.Context) {
// to get and convert the received path variable to desired type
bookId, err := primitive.ObjectIDFromHex(ctx.Param("bookId"))
if err != nil {
ctx.JSON(http.StatusBadRequest, "Invalid Book ID")
return
}
var newBook BookCreateUpdateRequest
// to bind the received JSON to BookRequest to strip the unnecessary fields.
if err := ctx.ShouldBind(&newBook); err != nil {
ctx.JSON(http.StatusBadRequest, "Invalid Request")
return
}
//Getting the Book Data from database
var book Book
err = collection.Find(ctx, bson.M{"_id": bookId}).One(&book)
// to send error response if any error occurs
if err != nil {
ctx.JSON(http.StatusNotFound, "Book Not Found")
return
}
// set the updated value in the book
book.Author = newBook.Author
book.Title = newBook.Title
// update in database
err = collection.ReplaceOne(ctx, bson.M{"_id": bookId}, &book)
if err != nil {
ctx.JSON(http.StatusInternalServerError, "Something went wrong, Try again after sometime")
return
}
// to send success response on completion
ctx.JSON(http.StatusOK, GetBooksResponse(book))
}
در بلوک کد بالا، collection.ReplaceOne
برای جایگزینی سند موجود بر اساس شرایط استفاده می شود. روش ReplaceOne همچنین فیلد پیش فرض UpdateAT را در پایگاه داده به روز می کند.
حذف راهنمای کتاب:
func DeleteBook(ctx *gin.Context) {
// to get and convert the received path variable to desired type
bookId, err := primitive.ObjectIDFromHex(ctx.Param("bookId"))
if err != nil {
ctx.JSON(http.StatusBadRequest, "Invalid Request")
return
}
//Getting the Book Data from database
var book Book
err = collection.Find(ctx, bson.M{"_id": bookId}).One(&book)
// to send error response if any error occurs
if err != nil {
ctx.JSON(http.StatusNotFound, "Book Not Found")
return
}
// Deleting the book
err = collection.RemoveId(ctx, bookId)
// to send error response if any error occurs
if err != nil {
ctx.JSON(http.StatusInternalServerError, "Something went wrong, Try again after sometime")
return
}
// to send success response on completion
ctx.JSON(http.StatusOK, true)
}
در بلوک کد بالا، collection.RemoveId
برای حذف داده های خاص بر اساس شناسه ارائه شده استفاده می شود.
راهنمای فهرست کتاب ها
func GetBooks(ctx *gin.Context) {
//Getting the Book Data to database
var books []BookListResponse
err := collection.Find(ctx, bson.M{}).All(&books)
// to send error response if any error occurs
if err != nil {
fmt.Println(err)
ctx.JSON(http.StatusInternalServerError, "Something went wrong, Try again after sometime")
return
}
// to send success response on completion
ctx.JSON(http.StatusOK, books)
}
در اینجا در کنترل کننده List، از BookListResponse استفاده کرده ایم که برای محدود کردن مقادیر خوانده شده از پایگاه داده استفاده می شود زیرا شناسه و نام کتاب در فهرست API کافی است. در زیر نوع BookListResponse آمده است.
type BookListResponse struct {
Id primitive.ObjectID `json:"id" bson:"_id"` // bson to map mongo _id to id
Title string `json:"title"`
}
اینجا bson:"_id"
برای نگاشت mongo _id به ویژگی ID در پاسخ استفاده می شود.
اکنون همه Handler ها ایجاد شده اند، اجازه دهید Handler ها را در روتر در main.go با افزودن بلوک کد زیر پس از اعلام روتر ثبت کنیم.
router.GET("/books", GetBooks)
router.GET("/books/:bookId", GetBook)
router.PATCH("/books/:bookId", UpdateBook)
router.DELETE("/books/:bookId", DeleteBook)
تبریک می گویم!!! CRUD REST API برای کتابهای موجود در کتابخانه با استفاده از Mongo and Go با موفقیت تکمیل شد.
شما می توانید کد منبع را در مخزن Github پیدا کنید:
Books REST API با استفاده از go و mongo
Books REST API با استفاده از go و mongo
پیش نیازها:
- نصب Go 1.20 یا بالاتر. برای دستورالعمل نصب، مراجعه کنید.
- نصب MongoDb 6.0 یا بالاتر. برای دستورالعمل نصب، مراجعه کنید
برای راه اندازی سرور REST API از cmd استفاده کنید
go run .