Handlers and Endpoints 🧢

janedzumerko

ЈанС ЏумСркоски

Posted on October 20, 2022

Handlers and Endpoints 🧢

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
Enter fullscreen mode Exit fullscreen mode

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
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,
    })
}
Enter fullscreen mode Exit fullscreen mode

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
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,
    })
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
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"))
}
Enter fullscreen mode Exit fullscreen mode

πŸ“ 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

πŸ’– πŸ’ͺ πŸ™… 🚩

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related