1

I am trying to create a url shortener with golang, redis and mognodb but facing issues with the actual database connection.

In my application I have several packages:

base62
|
|_base62.go
config
|
|__redis.go
models
|
|__url.go
request
|
|__shorten_request.go
response
|
|__shorten_response.go
routes
|
|__shorten.go
    main.go

In my shorten.go file:

func  Shorten(context *gin.Context){
    var request request.ShortenURLRequest
    if err := context.BindJSON(&request); err != nil {
        return
    }

    if !IsUrl(request.URL){
        context.IndentedJSON(http.StatusBadRequest, "Error")
        return 
    }
    // encode the long url
    short_url := base62.Encode(request.URL)

    // URL model
    var url models.URL
    url.ID = 1234567890
    url.LONG_URL = request.URL
    url.SHORT_URL = short_url

    // insert the data in redis db

    // create the response to send back to client
    var response response.ShortenURLResponse
    response.URL = request.URL
    response.SHORT_URL = short_url
    response.CREATED_AT = time.Now()

    context.IndentedJSON(http.StatusOK, response)
}

Now I want to create the db connection in such a way that shorten and resolve files have access to database.

All the resources that I am getting has a single file for connection and all the routes and controllers are defined in that.

Help will be appreciated

The source code can be found here: github

Arnob
  • 195
  • 3
  • 14

1 Answers1

1

Based on your main.go file I think you could do:

func main() {
    rdb, err := redis.NewClient()
    if err != nil {
        log.Fatal(err)
    }

    router := gin.Default()
    router.POST("/api/v1/shorten", routes.Shorten(rdb))
    router.GET("/api/v1/:url", routes.Resolve(rdb))
    router.Run("localhost:9000")
}

func Shorten(rdb *redis.Client) gin.HandlerFunc {
    return func(context *gin.Context) {
        ctx := context.Request.Context()
        ...
        
        if err := rdb.Set(ctx, key, value); err != nil {
            context.IndentedJSON(http.StatusInternalServerError, "Error")
            return 
        }
        ....
    }
}

Or even better, you could create a struct that contains the redis client and acts as a router of your requests, like so:

type Router struct {
    rdb *redis.Client
}

func NewRouter(rdb *redis.Client) *Router {
    return &Router{rdb: rdb}
}

func (r *Router) Shorten() gin.HandlerFunc {
    return func(context *gin.Context) {
        ...
        r.rdb.Set()
        ...
    }
}

func (r *Router) Resolve() gin.HandlerFunc {
    return func(context *gin.Context) {
        ...
        r.rdb.Get()
        ...
    }
}

func main() {
    rdb, err := redis.NewClient()
    if err != nil {
        log.Fatal(err)
    }

    r := NewRouter(rdb)

    router := gin.Default()
    router.POST("/api/v1/shorten", r.Shorten)
    router.GET("/api/v1/:url", r.Resolve)
    router.Run("localhost:9000")
}
GGP
  • 314
  • 5
  • 6
  • thanks but is it possible to separate them in different files like I did in my project? Quite new to go so I have little knowledge – Arnob Oct 28 '22 at 06:55
  • Yes, you can put the router code in a separate folder and import it in the main file like you did with the other ones, make sure the struct and all methods are exported (their name starts with a uppercase letter) – GGP Oct 28 '22 at 11:55
  • Here's an answer that may help you https://stackoverflow.com/a/68877864/12574067 – GGP Oct 28 '22 at 11:57
  • I tried to separate the files but still cannot connect the routes. I have connection in `config/redis.go` and the shortening logic in `routes/shorten.go`. Will you please check what went wrong? https://github.com/fahimhoque/shorty – Arnob Oct 28 '22 at 13:12
  • The struct `Router` and its methods must be in the same folder, you could create the file `routes/router.go` and put the router there instead of in `config` – GGP Oct 28 '22 at 13:59
  • 1
    Thanks. I can't keep the whole application public. So I will create another simplified application and post the link on my question. Should help others. – Arnob Oct 28 '22 at 21:06