برنامه نویسی

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

در این وبلاگ، ما یک سرور API RESTful با دو نقطه پایانی خواهیم ساخت. پروژه مثال، مخزن داده‌های مربوط به کتاب‌ها در یک کتابخانه خواهد بود.

این شامل بخش های زیر است:

  1. طراحی نقاط پایانی API
  2. یک پوشه برای کد ایجاد کنید.
  3. با استفاده از qmgo به MongoDB متصل شوید
  4. کنترل کننده ها را بنویسید
    • یک کتاب جدید اضافه کنید
    • همه کتاب ها را دریافت کنید
    • یک کتاب خاص بگیرید
    • یک کتاب خاص را حذف کنید

پیش نیازها:

  • نصب 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 .

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا