Handlers and Endpoints 🧶
Tags: go, redis, api, microservices
Published: 2022-10-20 13:16:22

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 :
1. We will get the creation request body, parse it and extract the initial longURL and userId.
2. Call our shortener.GenerateShortURL that we implemented in PART II and generate our shortened hash.
3. 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

```go
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 :
1. Getting the short URL from the path parameter /:shortUrl
2. Call the store to retrieve the initial URL that corresponds to the short one provided in the path.
3. And finally, return the long URL

```go
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](https://echo.labstack.com/middleware/) 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
```

```go
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](https://projectex.dev/challenges/how-to-build-a-url-shortener-in-go-with-redis/)