英文:
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 (
"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"]
}
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("/base", s.handleIndex()).Methods("GET")
}
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 := &server{
router: mux.NewRouter(),
cities: getMongoDBCollection('cities') // implement this one :) should return a *mongo.Collection...
}
sr.routes()
...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论