Skip to content

Instantly share code, notes, and snippets.

@mayankchoubey
Last active October 19, 2023 01:43
Show Gist options
  • Save mayankchoubey/738bfaf51faf5f690c12f879e01908fe to your computer and use it in GitHub Desktop.
Save mayankchoubey/738bfaf51faf5f690c12f879e01908fe to your computer and use it in GitHub Desktop.
Go - Gin URL shortener service using PostgreSQL
package main
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
type ShortenUrlRequestBody struct {
SrcUrl string `json:"srcUrl"`
}
type ShortenUrlResponseBody struct {
SrcUrl string `json:"srcUrl"`
ShortenedUrl string `json:"shortenedUrl"`
}
func HandleRequest(c *gin.Context) {
var reqBody ShortenUrlRequestBody
if err := c.BindJSON(&reqBody); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Request is not a valid JSON"})
return
}
srcUrl := reqBody.SrcUrl
if len(srcUrl) > 250 {
c.JSON(http.StatusBadRequest, gin.H{"error": "Parameter 'srcUrl' must not be more than 250 characters"})
return
}
if !(strings.HasPrefix(srcUrl, "http://") || strings.HasPrefix(srcUrl, "https://")) {
c.JSON(http.StatusBadRequest, gin.H{"error": "Parameter 'srcUrl' must start with http:// or https://"})
return
}
shortenedUrl := Shorten(srcUrl)
if len(shortenedUrl) == 0 {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to shorten"})
return
}
rspBody := &ShortenUrlResponseBody{
SrcUrl: srcUrl,
ShortenedUrl: shortenedUrl,
}
c.JSON(http.StatusOK, rspBody)
}
package main
import (
"context"
"database/sql"
"os"
"time"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/driver/pgdriver"
)
type ShortenedUrl struct {
bun.BaseModel `bun:"table:shortenedurls"`
Id string `bun:"id,pk"`
SrcUrl string `bun:"srcurl"`
Created time.Time `bun:"created"`
LastAccessed time.Time `bun:"lastaccessed"`
}
var sqldb = sql.OpenDB(pgdriver.NewConnector(
pgdriver.WithNetwork("tcp"),
pgdriver.WithAddr("localhost:5432"),
pgdriver.WithUser(os.Getenv("dbUser")),
pgdriver.WithPassword(os.Getenv("dbUserPass")),
pgdriver.WithDatabase(os.Getenv("dbName")),
pgdriver.WithInsecure(true),
))
var db = bun.NewDB(sqldb, pgdialect.New())
func init() {
sqldb.SetMaxOpenConns(10)
sqldb.SetMaxIdleConns(10)
}
func Save(id string, srcUrl string) bool {
ctx := context.Background()
shortenedUrl := &ShortenedUrl{
Id: id,
SrcUrl: srcUrl,
Created: time.Now(),
LastAccessed: time.Now(),
}
_, err := db.NewInsert().Model(shortenedUrl).Exec(ctx)
if err != nil {
return false
}
return true
}
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
r := gin.New()
r.POST("/shorten", HandleRequest)
r.Run(":3000")
}
package main
import gonanoid "github.com/matoous/go-nanoid/v2"
var baseUrl = "http://test.short/"
func Shorten(srcUrl string) string {
id, _ := gonanoid.New(10)
shortenedUrl := baseUrl + id
Save(id, srcUrl)
return shortenedUrl
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment