在此博客中,我们将构建一个带有两个端点的RESTFUL API服务器。示例项目将是图书馆中有关书籍的数据存储库。
这包括以下各节:
- 设计API端点。
- 创建一个代码文件夹。
- 使用QMGO连接到MongoDB
- 将处理者写给
- 添加一本新书
- 获取所有书籍
- 获得一本特定的书
- 删除特定书
先决条件:
设计API端点:
我们将建立一个API,可在图书馆中访问这些书籍。因此,我们需要提供端点,客户可以在图书馆中获取,添加或删除书籍。
这是我们在本教程中创建的终点。
/books
获取所有书籍的清单,返回为JSON。
帖子â添加以JSON发送的请求数据中的新书。
/books/:id
获取一本书的ID,将书籍数据返回为JSON。
补丁–通过其ID更新一本书,将书数据返回为JSON。
删除删除一本书的ID,将删除状态返回为JSON。
为我们的代码创建一个文件夹:
开始,我们将为我们要编写的代码创建一个项目。
使用命令提示符,为我们的代码创建一个名为书籍的文件夹。
$ mkdir books
$ cd books
创建一个可以管理依赖项的模块。
运行go mod init
命令,为其代码所在的模块提供路径。
$ go mod init books
go: creating new go.mod: module books
此命令创建一个go.mod文件,其中我们添加的依赖项将被列出以进行跟踪。
代码
使用IDE/文本编辑器,创建一个名为main.go的文件。我们将在此文件中写入我们的GO代码。
在main.go中,在文件的顶部,添加以下包装声明和主函数,因为我们运行代码时将调用,因为独立程序(而不是库)始终在包装中。<<<<<<< br>
package main
func main() {
}
运行程序使用go run .
在包装声明之下,让我们开始编写连接到MongoDB的代码。
使用以下CMD
安装QMGOgo 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
在这里,我们已经注册了一个帖子路由器,让我们继续创建创建书籍功能以处理创建请求
创建一个新的文件书。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
}
在上面的代码中,我们使用getBookssponse方法来设置要发送的响应(我们也将其用于其他API响应)。
以下是用于获取,列表,更新和删除的处理程序。
获取书籍详细信息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查找这本书,并用于将Mongo数据绑定到书籍变量
更新一本书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
用于基于条件替换现有文档。
删除书处理程序:
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
用于根据提供的ID删除特定数据。
书籍清单处理程序
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)
}
在列表处理程序中,我们使用了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属性。
现在已经创建了所有处理程序,让我们在路由器中注册处理程序。Go通过在路由器声明后添加以下代码块。
router.GET("/books", GetBooks)
router.GET("/books/:bookId", GetBook)
router.PATCH("/books/:bookId", UpdateBook)
router.DELETE("/books/:bookId", DeleteBook)
恭喜!!!使用Mongo和GO在图书馆中用于书籍的CRUD REST API已成功完成。
您将能够在github repo中找到源代码: