Создание REST API в Go с интеграцией MongoDB: пошаговое руководство
3 марта 2023 г.В этой статье я покажу вам, как написать REST API на Go и интегрировать MongoDB в качестве вашей базы данных. Вы будете использовать драйвер MongoDB для создания Note API, который выполняет четыре основные операции: Create-Retrieve-Update-Delete с внутренними библиотеками Go.
Это введение в Go, и, поскольку вы знаете, что это серверный язык, написание API — это то, что вы должны знать как бэкэнд-разработчик.
:::информация Примечание. Я использую операционную систему Windows 10.
:::
Настройка среды разработки
Давайте создадим нашу среду разработки, открыв командную строку и создав папку. Я называю проект tautpad, так как taut означает лаконичный и блокнот, на котором можно писать.
>> mkdir tautpad
>> cd tautpad
~ Инициализируйте наш модуль go (вы можете сделать это с помощью команды инициализации go mod и добавления к ней суффикса с именем проекта или, если у вас есть учетная запись GitHub и репозиторий для проекта, вы добавляете суффикс URL к команде инициализации go mod.
go mod init tautpad
В качестве альтернативы
go mod init github.com/seyiadel/taut-pad
Мы продолжаем кодировать, открыв наш редактор кода (VScode), и для этого мы используем «код». команда, чтобы открыть наш текущий каталог.
C:UsersSeyi Adeleyetautpad>> code .
Создайте файл main.go в текущем каталоге «tautpad». Откройте файл main.go и напишите;
package main
:::подсказка Зачем упаковывать main в первую строку кода? Это должно сообщить компилятору Go, что пакет является исполняемой программой, а не общей библиотекой.
:::
Теперь мы создадим наш простой веб-сервер и маршрутизатор, используя библиотеку net/http:
import "net/http"
func main(){
router := http.NewServeMux()
server := &http.Server(
Addr: 0.0.0.0:8000
Handler: router
)
server.ListenAndServe()
}
:::информация func main(). Это особый тип функции, которая может быть определена в пакете и действует как точка входа для исполняемой программы.
http.NewServeMux() — сопоставляет обработчик с URL-адресом. Подробнее.... р>
:::
На этом этапе нам нужно подключиться к нашей базе данных MongoDB Compass через ее драйвер. Убедитесь, что у вас установлен и запущен MongoDB Community Server.
Если нет, посетите https://www.mongodb.com/try/download/community скачать. Прочтите документацию по установке и получите строку подключения (URI базы данных). Установка поставляется с MongoDB Shell и MongoDB Compass, графическим пользовательским интерфейсом, который упрощает использование.
После этого пришло время подключить наше приложение к установленной базе данных. Во-первых, мы устанавливаем драйверы с помощью команды go get
>> go get go.mongodb.org/mongo-driver/mongo
Теперь в нашем main.go мы подключаемся к базе данных с установленным драйвером и строкой подключения к базе данных (URI базы данных).
Наш файл main.go выглядит так:
package main
import (
"context"
"fmt"
"net/http"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
func main(){
//Connects to the database with uri generated from the database.
const uri = "mongodb://localhost:27017"
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))
if err != nil{
panic(err)
}
// Makes sure the database disconnects after function/program runs
defer func(){
if err = client.Disconnect(context.TODO()); err != nil{
panic(err)
}
}()
//Check the database is connected and active
if err := client.Ping(context.TODO(), readpref.Primary()); err !=nil {
panic(err)
}
//Database name and the collection to store our data
collection = client.Database("tautpad").Collection("notes")
fmt.Println("Database connected and pinged")
router := http.NewServeMux()
server := &http.Server{
Addr : "0.0.0.0:8080",
Handler: router,
}
server.ListenAndServe()
}
:::информация контекст.TODO()
readpref.Primary
:::
Запустите go mod tidy, чтобы включить используемый драйвер в качестве зависимости.
>> go mod tidy
Пришло время CRUD!🎈
Простая заметка имеет заголовок и текст. Давайте создадим модель заметки с этими требованиями, используя тип структуры. Здесь мы начинаем импортировать библиотеки из MongoDB. Первая внешняя библиотека является примитивной, она предназначена для создания идентификатора каждой созданной заметки.
import (
//internal libraries
"context"
"fmt"
"net/http"
//external libraries
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
type Note struct{
ID primitive.ObjectID `json:"_id" bson:"_id,omitempty"`
Title string `json:"title bson:"title,omitempty"`
Body string `json:"body" bson:"body,omitempty"
}
Мы добились прогресса. Давайте завершим его созданием функций или обработчиков для выполнения CRUD. Мы бы написали обработчик создания и извлечения, что означает запрос POST и GET. Я бы использовал тип switch-case, чтобы сделать обработчики краткими и понятными.
func createAndGetNoteHandler(response http.ResponseWriter, request http.Request){
response.Header().Set("content-type", "application/json")
switch request.Method {
case "POST":
var note Note
_ = json.NewDecoder(request.Body).Decode(¬e)
output, err := collection.InsertOne(context.Background(), note)
if err != nil{
log.Fatal(err)
}
json.NewEncoder(response).Encode(output)
case "GET":
var notes []Note
output, err := collection.Find(context.TODO(), bson.D{})
if err != nil{
panic(err)
}
err = output.All(context.TODO(), ¬es)
if err != nil{
panic(err)
}
json.NewEncoder(response).Encode(notes)
}
}
Наконец, мы пишем функции обновления и удаления, чтобы завершить их как CRUD (создать-получить-обновить-удалить). Update принимает запрос PUT, а Delete — запрос DELETE.
func getUpdateDeleteTautPadHandler(response http.ResponseWriter, request *http.Request){
response.Header().Set("content-type", "application/json")
var note Note
ctx := context.TODO()
switch request.Method{
case "GET":
getId := strings.TrimPrefix(request.URL.Path, "/notes/")
id, err := primitive.ObjectIDFromHex(getId)
if err != nil{
panic(err)
}
err = collection.FindOne(ctx, bson.M{"_id": id} ).Decode(¬e)
if err != nil{
panic(err)
}
json.NewEncoder(response).Encode(note)
case "PUT":
err := json.NewDecoder(request.Body).Decode(¬e)
if err != nil{
panic(err)
}
getId := strings.TrimPrefix(request.URL.Path, "/notes/")
id, err := primitive.ObjectIDFromHex(getId)
if err != nil{
panic(err)
}
result, err := collection.UpdateOne(ctx, bson.M{"_id": id,}, bson.M{"$set": note,})
if err != nil{
panic(err)
}
json.NewEncoder(response).Encode(result)
case "DELETE":
getID := strings.TrimPrefix(request.URL.Path, "/notes/")
id, err := primitive.ObjectIDFromHex(getID)
if err != nil{
panic(err)
}
output, err := collection.DeleteOne(ctx, bson.M{"_id": id,})
if err != nil{
panic(err)
}
json.NewEncoder(response).Encode(output)
}
}
Мы добавляем созданные нами обработчики к маршрутизаторам, чтобы они соответствовали URL-адресу для выполнения своих операций.
Это основная функция в файле main.go
router := http.NewServeMux()
router.Handle("/notes", http.HandlerFunc(tautPadHandler))
router.Handle("/notes/", http.HandlerFunc(getUpdateDeleteTautPadHandler))
Готово!🎉
Мы успешно написали API-интерфейс Note REST для выполнения операций CRUD с MongoDB в качестве сохраняемости.
Ваш файл main.go должен выглядеть так:
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
type Note struct {
/*no space between _id and omitempty else _id generated would be zeros
and won't allow another insertion, so as to prompt go drivers for
random _id to be generated*/
Id primitive.ObjectID `json:"_id" bson:"_id,omitempty"`
Title string `json:"title" bson:"title,omitempty"`
Description string `json:"description" bson:"description,omiempty"`
}
var collection *mongo.Collection
const uri = "mongodb://localhost:27017"
func tautPadHandler(response http.ResponseWriter, request *http.Request){
response.Header().Set("content-type", "application/json")
switch request.Method {
case "POST":
var note Note
_ =json.NewDecoder(request.Body).Decode(¬e)
output, err := collection.InsertOne(context.Background(), note)
if err != nil{
log.Fatal(err)
}
json.NewEncoder(response).Encode(output)
case "GET":
var notes []Note
output, err := collection.Find(context.TODO(), bson.D{})
if err != nil{
panic(err)
}
err = output.All(context.TODO(), ¬es)
if err != nil{
panic(err)
}
json.NewEncoder(response).Encode(notes)
}
}
func getUpdateDeleteTautPadHandler(response http.ResponseWriter, request *http.Request){
response.Header().Set("content-type", "application/json")
var note Note
ctx := context.TODO()
switch request.Method{
case "GET":
getId := strings.TrimPrefix(request.URL.Path, "/notes/")
id, err := primitive.ObjectIDFromHex(getId)
if err != nil{
panic(err)
}
err = collection.FindOne(ctx, bson.M{"_id": id} ).Decode(¬e)
if err != nil{
panic(err)
}
json.NewEncoder(response).Encode(note)
case "PUT":
err := json.NewDecoder(request.Body).Decode(¬e)
if err != nil{
panic(err)
}
getId := strings.TrimPrefix(request.URL.Path, "/notes/")
id, err := primitive.ObjectIDFromHex(getId)
if err != nil{
panic(err)
}
result, err := collection.UpdateOne(ctx, bson.M{"_id": id,}, bson.M{"$set": note,})
if err != nil{
panic(err)
}
json.NewEncoder(response).Encode(result)
case "DELETE":
getID := strings.TrimPrefix(request.URL.Path, "/notes/")
id, err := primitive.ObjectIDFromHex(getID)
if err != nil{
panic(err)
}
output, err := collection.DeleteOne(ctx, bson.M{"_id": id,})
if err != nil{
panic(err)
}
json.NewEncoder(response).Encode(output)
}
}
func main(){
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))
if err != nil{
panic(err)
}
defer func(){
if err = client.Disconnect(context.TODO()); err != nil{
panic(err)
}
}()
if err := client.Ping(context.TODO(), readpref.Primary()); err !=nil {
panic(err)
}
collection = client.Database("tautpad").Collection("notes")
fmt.Println("Database connected and pinged")
router := http.NewServeMux()
router.Handle("/notes", http.HandlerFunc(tautPadHandler))
router.Handle("/notes/", http.HandlerFunc(getUpdateDeleteTautPadHandler))
server := &http.Server{
Addr : "0.0.0.0:8080",
Handler: router,
}
server.ListenAndServe()
}
Оригинал