Now it's time to put the components we built previously to good use, so during this part, we will be making sure those previously built components work together as expected.
We are going to build two endpoints to our API service :
- One endpoint that will be used to generate a short URL and return it, when the initial long URL is provided. /encode
- The other one will be used to return the original long URL when the short URL is provided. /decode/:short-url
Let's go ahead and create the handler package and define our handler's functions there. Create a folder called handler and create a file called handlers.go inside the folder. After that our project directory should look like the tree below :
├── go.mod
├── go.sum
├── main.go
└── shortener
├── shortener.go
└── shortener_test.go
└── store
├── store.go
└── store_test.go
└── handler
└── handlers.go
Now let’s define and implement our handlers.
We will be starting with implementing the CreateShortURL() handler function, this should be very straightforward :
- We will get the creation request body, parse it and extract the initial longURL and userId.
- Call our shortener.GenerateShortURL that we implemented in PART II and generate our shortened hash.
- Finally store the mapping of our output hash / shortURL with the initial longURL, here, we will be using the store.SaveURLInRedis() we implemented back in PART III
package handler
import (
"github.com/labstack/echo/v4"
"go-redis-url-shortener/shortener"
"go-redis-url-shortener/store"
)
const host = "http://localhost:1323/"
// URLCreationRequest is request model definition
type URLCreationRequest struct {
LongURL string `json:"long_url" binding:"required"`
UserId string `json:"user_id" binding:"required"`
}
func CreateShortURL(c echo.Context) error {
cr := new(URLCreationRequest)
if err := c.Bind(cr); err != nil {
return err
}
shortUrl := shortener.GenerateShortURL(cr.LongURL, cr.UserId)
store.SaveURLInRedis(shortUrl, cr.LongURL)
return c.JSON(200, map[string]interface{}{
"short_url": host + shortUrl,
})
}
The next step will be about returning the original URL, ReturnLongURL(), it will consist of :
- Getting the short URL from the path parameter /:shortUrl
- Call the store to retrieve the initial URL that corresponds to the short one provided in the path.
- And finally, return the long URL
func ReturnLongURL(c echo.Context) error {
shortUrl := c.Param("short-url")
initialUrl := store.RetrieveInitialURLFromRedis(shortUrl)
return c.JSON(200, map[string]interface{}{
"short_url": host + shortUrl,
"long_url": initialUrl,
})
}
After implementing our handlers, we should go straight to the main.go file to add the needed endpoints and initialize the store.
📝 Also don't forget to add the middleware library from Echo that we will use to solve our CORS issues. Middleware is a function chained in the HTTP request-response cycle with access to Echo#Context which it uses to perform a specific action, for example, logging every request or limiting the number of requests. Handler is processed in the end after all middleware are finished executing.
go get github.com/labstack/echo/v4/middleware
package main
import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"go-redis-url-shortener/handlers"
"go-redis-url-shortener/store"
"net/http"
)
func main() {
e := echo.New()
e.Use(middleware.CORS())
e.GET("/", func(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]interface{}{
"message": "Welcome to Go URL Shortener with Redis !🚀",
})
})
e.POST("/encode", func(c echo.Context) error {
return handler.CreateShortURL(c)
})
e.GET("/decode/:short-url", func(c echo.Context) error {
return handler.ReturnLongURL(c)
})
// Store initialization happens here
store.InitializeStore()
e.Logger.Fatal(e.Start(":1323"))
}
📝 In more complex applications, the endpoints should live in a separate file, but for the sake of simplicity and since they are just two endpoints, we will be having them in the main.go file
Originally published at projectex.dev
Top comments (0)