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()) }