tiny-url-ex/service/shortener/shortener.go

158 lines
3.6 KiB
Go

package shortener
import (
"database/sql"
"log"
"net/http"
"git.xdrm.io/example/aicra/service/auth"
"git.xdrm.io/example/aicra/storage"
"git.xdrm.io/go/aicra"
"git.xdrm.io/go/aicra/api"
)
// Service manages the url shortener
type Service struct {
storage *sql.DB
authService *auth.Service
repo *repository
}
// New returns a bare service
func New(storage *sql.DB, auth *auth.Service) *Service {
log.Printf("[service.shortener] creating")
service := &Service{
storage: storage,
authService: auth,
}
// init repo
repo, err := newRepo(db)
if err != nil {
log.Printf("[service.shortener] cannot create repo")
return service
}
log.Printf("[service.shortener] creating")
return service
}
// Wire to the aicra server
func (svc *Service) Wire(server *aicra.Server) {
log.Printf("[service.shortener] wired")
server.HandleFunc("GET", "/", svc.redirect)
server.HandleFunc("POST", "/", svc.authService.CheckToken(svc.register))
server.HandleFunc("PUT", "/", svc.authService.CheckToken(svc.update))
server.HandleFunc("DELETE", "/", svc.authService.CheckToken(svc.delete))
}
// redirect from a tiny url to the long url
func (svc *Service) redirect(req api.Request, res *api.Response) {
// 1. extract input
tinyURL, err := req.Param.GetString("url")
if err != nil {
res.SetError(api.ErrorInvalidParam(), "url", err.Error())
return
}
// 2. check in db if exists
longURL := svc.storage.Get(storage.DATA, tinyURL)
if longURL == nil {
res.SetError(api.ErrorNoMatchFound())
return
}
// 3. redirect
res.Status = http.StatusPermanentRedirect
res.Headers.Set("Location", string(longURL))
res.SetError(api.ErrorSuccess())
}
// register registers a new tiny url to a long one
func (svc *Service) register(req api.Request, res *api.Response) {
// 1. extract arguments
longURL, err := req.Param.GetString("target")
if err != nil {
res.SetError(api.ErrorInvalidParam(), "target", err.Error())
return
}
tinyURL, err := req.Param.GetString("url")
if err != nil {
res.SetError(api.ErrorInvalidParam(), "url", err.Error())
return
}
// 2. fail if already used
if svc.storage.Get(storage.DATA, tinyURL) != nil {
res.SetError(api.ErrorAlreadyExists(), "url")
return
}
// 3. store association
if !svc.storage.Set(storage.DATA, tinyURL, longURL) {
res.SetError(api.ErrorFailure())
return
}
res.SetError(api.ErrorSuccess())
}
// update updates an existing tiny url to a new long one
func (svc *Service) update(req api.Request, res *api.Response) {
// 1. extract arguments
longURL, err := req.Param.GetString("target")
if err != nil {
res.SetError(api.ErrorInvalidParam(), "target", err.Error())
return
}
tinyURL, err := req.Param.GetString("url")
if err != nil {
res.SetError(api.ErrorInvalidParam(), "url", err.Error())
return
}
// 2. fail if not already existing
if svc.storage.Get(storage.DATA, tinyURL) == nil {
res.SetError(api.ErrorNoMatchFound())
return
}
// 3. update association
if !svc.storage.Set(storage.DATA, tinyURL, longURL) {
res.SetError(api.ErrorFailure())
return
}
res.SetError(api.ErrorSuccess())
}
// delete removes a new tiny url
func (svc *Service) delete(req api.Request, res *api.Response) {
// 1. extract arguments
tinyURL, err := req.Param.GetString("url")
if err != nil {
res.SetError(api.ErrorInvalidParam(), "url", err.Error())
return
}
// 2. fail if not already existing
if svc.storage.Get(storage.DATA, tinyURL) == nil {
res.SetError(api.ErrorNoMatchFound())
return
}
// 3. update association
if !svc.storage.Del(storage.DATA, tinyURL) {
res.SetError(api.ErrorFailure())
return
}
res.SetError(api.ErrorSuccess())
}