如何在另一个函数中使用我已连接到 MongoDB 和集合的句柄?

huangapple go评论91阅读模式
英文:

How do I use the handles that I have connected to my mongodb and collections in another function?

问题

我有一个在Mongo上设置的数据库,其中包含一些我需要通过URL参数从端点查询的数据。为了使用该库,我在一个单独的setup()函数中定义了一些句柄并进行了整个数据库连接的设置,但我无法在外部使用我需要的句柄。

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/gorilla/mux"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"go.mongodb.org/mongo-driver/mongo/readpref"
)

func setup() {
	clientOptions := options.Client().
		ApplyURI("mongodb+srv://<username>:<password>@cluster0.um5qb.mongodb.net/<db>?retryWrites=true&w=majority")
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	client, err := mongo.Connect(ctx, clientOptions)
	if err != nil {
		log.Fatal(err)
	}
	err = client.Ping(ctx, readpref.Primary())
	if err != nil {
		log.Fatal(err)
	}
	defer client.Disconnect(ctx)
	// DB := client.Database("cities-nighthack")
	// Cities := DB.Collection("city")

}

// model for user endpoint
type User struct {
	Email string `json:"email"`
}

// fake db to temp store users
var users []User

// checks if json is empty or not
func (u *User) IsEmpty() bool {
	return u.Email == ""
}

type App struct {
	Mongo *mongo.Client
}

func main() {
	setup()
	r := mux.NewRouter()
	r.HandleFunc("/user", createUser).Methods("POST")
	// r.HandleFunc("/suggest?city_name={city}", searchCity).Methods("GET")

	fmt.Println("Server running at port 8080")
	log.Fatal(http.ListenAndServe(":8080", r))

}

func createUser(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	if r.Body == nil {
		json.NewEncoder(w).Encode("Must send data")
	}

	var user User
	err := json.NewDecoder(r.Body).Decode(&user)
	if err != nil {
		log.Fatal(err)
	}
	if user.IsEmpty() {
		json.NewEncoder(w).Encode("Invalid! Enter user email.")
		return
	}
	users = append(users, user)
	json.NewEncoder(w).Encode(user)

}

func (a *App) searchCity(w http.ResponseWriter, r *http.Request) {

	vars := mux.Vars(r)
	city := vars["city"]
	
}

我认为我可以简单地这样传递处理程序:

func searchCity(city *mongo.Collection) (w http.ResponseWriter, r *http.Request) {
...
}

然而,gmux不允许这样做,因为它隐式地传递了http.ResponseWriter*http.Request。因此,任何输入都不能作为参数。我尝试将它们声明为全局变量,但那样不起作用,并且不建议这样做。有人告诉我可以尝试使用闭包或结构体来传递它,但我对如何做到这一点不太理解。

英文:

I have a database that I've setup on mongo which is seeded with some data I need to query via a url parameter from an endpoint. In order to use the library, I had defined some handles and did the whole setup for the connection of the db in a separate setup() function, but I can't use the handles I require outside of it.

package main

import (
	&quot;context&quot;
	&quot;encoding/json&quot;
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;net/http&quot;
	&quot;time&quot;

	&quot;github.com/gorilla/mux&quot;
	&quot;go.mongodb.org/mongo-driver/mongo&quot;
	&quot;go.mongodb.org/mongo-driver/mongo/options&quot;
	&quot;go.mongodb.org/mongo-driver/mongo/readpref&quot;
)

func setup() {
	clientOptions := options.Client().
		ApplyURI(&quot;mongodb+srv://&lt;username&gt;:&lt;password&gt;@cluster0.um5qb.mongodb.net/&lt;db&gt;?retryWrites=true&amp;w=majority&quot;)
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	client, err := mongo.Connect(ctx, clientOptions)
	if err != nil {
		log.Fatal(err)
	}
	err = client.Ping(ctx, readpref.Primary())
	if err != nil {
		log.Fatal(err)
	}
	defer client.Disconnect(ctx)
	// DB := client.Database(&quot;cities-nighthack&quot;)
	// Cities := DB.Collection(&quot;city&quot;)

}

// model for user endpoint
type User struct {
	Email string `json:&quot;email&quot;`
}

// fake db to temp store users
var users []User

// checks if json is empty or not
func (u *User) IsEmpty() bool {
	return u.Email == &quot;&quot;
}

type App struct {
	Mongo *mongo.Client
}

func main() {
	setup()
	r := mux.NewRouter()
	r.HandleFunc(&quot;/user&quot;, createUser).Methods(&quot;POST&quot;)
	// r.HandleFunc(&quot;/suggest?city_name={city}&quot;, searchCity).Methods(&quot;GET&quot;)

	fmt.Println(&quot;Server running at port 8080&quot;)
	log.Fatal(http.ListenAndServe(&quot;:8080&quot;, r))

}

func createUser(w http.ResponseWriter, r *http.Request) {
	w.Header().Set(&quot;Content-Type&quot;, &quot;application/json&quot;)
	if r.Body == nil {
		json.NewEncoder(w).Encode(&quot;Must send data&quot;)
	}

	var user User
	err := json.NewDecoder(r.Body).Decode(&amp;user)
	if err != nil {
		log.Fatal(err)
	}
	if user.IsEmpty() {
		json.NewEncoder(w).Encode(&quot;Invalid! Enter user email.&quot;)
		return
	}
	users = append(users, user)
	json.NewEncoder(w).Encode(user)

}

func (a *App) searchCity(w http.ResponseWriter, r *http.Request) {

	vars := mux.Vars(r)
	city := vars[&quot;city&quot;]
	
}

I figured I'd be able to simply pass the handler like so:

func searchCity(city *mongo.Collection) (w http.ResponseWriter, r *http.Request) {
...
}

However, gmux doesn't allow you to do that since it implicitly passes in http.ResponseWriter and a *http.Request. Therefore, any input can't be in the arguments. I tried declaring them globally but that didn't work and was recommended not to do so. I was told I could try using a closure or a struct to pass it in but I don't quite understand how I'd go about doing that either.

答案1

得分: 1

一种方法是这样做,首先添加一个服务器类型:

type server struct {
	router *mux.Router
	cities *mongo.Collection
}

在服务器中添加一个路由包装器:

func (s *server) routes() {
	s.router.HandleFunc("/base", s.handleIndex()).Methods("GET")
}

处理函数:

func (s *server) handleIndex() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		cities := s.cities.Find(...) // 类似这样的操作
		// 编写响应等
	}
}

然后在主函数中:

func main() {
	sr := &server{
		router: mux.NewRouter(),
		cities: getMongoDBCollection("cities"), // 实现这个函数 :) 应该返回一个 *mongo.Collection...
	}
	sr.routes()
	// ...
}
英文:

One way to do it is like this, first add a server type

type server struct {
router *mux.Router
cities *mongo.Collection
}

Add a routes wrapper to the server

func (s *server) routes() {
s.router.HandleFunc(&quot;/base&quot;, s.handleIndex()).Methods(&quot;GET&quot;)
}

The handler function

func (s *server) handleIndex() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
cities := s.cities.Find(...) // something like that
// write your response, etc
}
}

Then in main

func main() {
sr := &amp;server{
router: mux.NewRouter(),
cities: getMongoDBCollection(&#39;cities&#39;) // implement this one :) should return a *mongo.Collection...
}
sr.routes()
...
}

huangapple
  • 本文由 发表于 2021年12月10日 05:16:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/70296820.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定