mirror of
https://github.com/jimeh/ozu.io.git
synced 2026-02-19 08:06:39 +00:00
Split Handler into Handler and APIHandler
This commit is contained in:
69
web/api_handler.go
Normal file
69
web/api_handler.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/jimeh/ozu.io/shortener"
|
||||
"github.com/qiangxue/fasthttp-routing"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// NewAPIHandler creates a new Handler object.
|
||||
func NewAPIHandler(s shortener.Shortener) *APIHandler {
|
||||
return &APIHandler{s}
|
||||
}
|
||||
|
||||
// APIHandler handle HTTP requests.
|
||||
type APIHandler struct {
|
||||
shortener shortener.Shortener
|
||||
}
|
||||
|
||||
// Shorten shortens given URL.
|
||||
func (h *APIHandler) Shorten(c *routing.Context) error {
|
||||
uid, url, err := h.shortener.Shorten(c.FormValue("url"))
|
||||
if err != nil {
|
||||
return h.respondWithError(c, err)
|
||||
}
|
||||
|
||||
r := makeURLResponse(c, uid, url)
|
||||
return h.respond(c, &r)
|
||||
}
|
||||
|
||||
// Lookup shortened UID.
|
||||
func (h *APIHandler) Lookup(c *routing.Context) error {
|
||||
uid := c.FormValue("uid")
|
||||
url, err := h.shortener.Lookup(uid)
|
||||
if err != nil {
|
||||
return h.respondWithError(c, err)
|
||||
}
|
||||
|
||||
r := makeURLResponse(c, uid, url)
|
||||
return h.respond(c, &r)
|
||||
}
|
||||
|
||||
func (h *APIHandler) respond(c *routing.Context, r *URLResponse) error {
|
||||
resp, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.SetContentType("application/json")
|
||||
c.Write(resp)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *APIHandler) respondWithError(c *routing.Context, err error) error {
|
||||
r := ErrorResponse{
|
||||
Error: err.Error(),
|
||||
}
|
||||
|
||||
resp, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.SetStatusCode(fasthttp.StatusNotFound)
|
||||
c.SetContentType("application/json")
|
||||
c.Write(resp)
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package web
|
||||
|
||||
//go:generate easyjson -all responses.go
|
||||
//go:generate easyjson -all api_responses.go
|
||||
|
||||
// URLResponse contains shortened URL info.
|
||||
type URLResponse struct {
|
||||
@@ -9,7 +9,7 @@ type URLResponse struct {
|
||||
Target string `json:"target"`
|
||||
}
|
||||
|
||||
// ErrorJSONResponse contains error info.
|
||||
// ErrorResponse contains error info.
|
||||
type ErrorResponse struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
var _ = json.RawMessage{} // suppress unused package warning
|
||||
|
||||
func easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ErrorResponse(in *jlexer.Lexer, out *ErrorResponse) {
|
||||
func easyjson_ab45bbb7_decode_github_com_jimeh_ozu_io_web_ErrorResponse(in *jlexer.Lexer, out *ErrorResponse) {
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
return
|
||||
@@ -34,7 +34,7 @@ func easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ErrorResponse(in *jlex
|
||||
}
|
||||
in.Delim('}')
|
||||
}
|
||||
func easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ErrorResponse(out *jwriter.Writer, in ErrorResponse) {
|
||||
func easyjson_ab45bbb7_encode_github_com_jimeh_ozu_io_web_ErrorResponse(out *jwriter.Writer, in ErrorResponse) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
@@ -48,21 +48,21 @@ func easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ErrorResponse(out *jwr
|
||||
}
|
||||
func (v ErrorResponse) MarshalJSON() ([]byte, error) {
|
||||
w := jwriter.Writer{}
|
||||
easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ErrorResponse(&w, v)
|
||||
easyjson_ab45bbb7_encode_github_com_jimeh_ozu_io_web_ErrorResponse(&w, v)
|
||||
return w.Buffer.BuildBytes(), w.Error
|
||||
}
|
||||
func (v ErrorResponse) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ErrorResponse(w, v)
|
||||
easyjson_ab45bbb7_encode_github_com_jimeh_ozu_io_web_ErrorResponse(w, v)
|
||||
}
|
||||
func (v *ErrorResponse) UnmarshalJSON(data []byte) error {
|
||||
r := jlexer.Lexer{Data: data}
|
||||
easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ErrorResponse(&r, v)
|
||||
easyjson_ab45bbb7_decode_github_com_jimeh_ozu_io_web_ErrorResponse(&r, v)
|
||||
return r.Error()
|
||||
}
|
||||
func (v *ErrorResponse) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ErrorResponse(l, v)
|
||||
easyjson_ab45bbb7_decode_github_com_jimeh_ozu_io_web_ErrorResponse(l, v)
|
||||
}
|
||||
func easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ShortenedResponse(in *jlexer.Lexer, out *URLResponse) {
|
||||
func easyjson_ab45bbb7_decode_github_com_jimeh_ozu_io_web_URLResponse(in *jlexer.Lexer, out *URLResponse) {
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
return
|
||||
@@ -90,7 +90,7 @@ func easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ShortenedResponse(in *
|
||||
}
|
||||
in.Delim('}')
|
||||
}
|
||||
func easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ShortenedResponse(out *jwriter.Writer, in URLResponse) {
|
||||
func easyjson_ab45bbb7_encode_github_com_jimeh_ozu_io_web_URLResponse(out *jwriter.Writer, in URLResponse) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
@@ -116,17 +116,17 @@ func easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ShortenedResponse(out
|
||||
}
|
||||
func (v URLResponse) MarshalJSON() ([]byte, error) {
|
||||
w := jwriter.Writer{}
|
||||
easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ShortenedResponse(&w, v)
|
||||
easyjson_ab45bbb7_encode_github_com_jimeh_ozu_io_web_URLResponse(&w, v)
|
||||
return w.Buffer.BuildBytes(), w.Error
|
||||
}
|
||||
func (v URLResponse) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ShortenedResponse(w, v)
|
||||
easyjson_ab45bbb7_encode_github_com_jimeh_ozu_io_web_URLResponse(w, v)
|
||||
}
|
||||
func (v *URLResponse) UnmarshalJSON(data []byte) error {
|
||||
r := jlexer.Lexer{Data: data}
|
||||
easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ShortenedResponse(&r, v)
|
||||
easyjson_ab45bbb7_decode_github_com_jimeh_ozu_io_web_URLResponse(&r, v)
|
||||
return r.Error()
|
||||
}
|
||||
func (v *URLResponse) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ShortenedResponse(l, v)
|
||||
easyjson_ab45bbb7_decode_github_com_jimeh_ozu_io_web_URLResponse(l, v)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"html/template"
|
||||
"mime"
|
||||
"net/url"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
@@ -38,13 +36,13 @@ func NewHandler(s shortener.Shortener) *Handler {
|
||||
|
||||
// Handler handle HTTP requests.
|
||||
type Handler struct {
|
||||
s shortener.Shortener
|
||||
t *template.Template
|
||||
shortener shortener.Shortener
|
||||
template *template.Template
|
||||
}
|
||||
|
||||
// Index handles requests for root.
|
||||
func (h *Handler) Index(c *routing.Context) error {
|
||||
h.template(c, "index.html", nil)
|
||||
h.respond(c, "index.html", nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -74,40 +72,17 @@ func (h *Handler) Static(c *routing.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shorten shortens given URL.
|
||||
func (h *Handler) Shorten(c *routing.Context) error {
|
||||
uid, url, err := h.s.Shorten(c.FormValue("url"))
|
||||
if err != nil {
|
||||
return h.respondWithError(c, err)
|
||||
}
|
||||
|
||||
r := h.makeURLResponse(c, uid, url)
|
||||
return h.respond(c, &r)
|
||||
}
|
||||
|
||||
// Lookup shortened UID.
|
||||
func (h *Handler) Lookup(c *routing.Context) error {
|
||||
uid := c.FormValue("uid")
|
||||
url, err := h.s.Lookup(uid)
|
||||
if err != nil {
|
||||
return h.respondWithError(c, err)
|
||||
}
|
||||
|
||||
r := h.makeURLResponse(c, uid, url)
|
||||
return h.respond(c, &r)
|
||||
}
|
||||
|
||||
// LookupAndRedirect looks up given UID and redirects to it's URL.
|
||||
func (h *Handler) LookupAndRedirect(c *routing.Context) error {
|
||||
uid := []byte(c.Param("uid"))
|
||||
|
||||
url, err := h.s.Lookup(uid)
|
||||
url, err := h.shortener.Lookup(uid)
|
||||
if err != nil {
|
||||
h.NotFound(c)
|
||||
return nil
|
||||
}
|
||||
|
||||
r := h.makeURLResponse(c, uid, url)
|
||||
r := makeURLResponse(c, uid, url)
|
||||
|
||||
c.Response.Header.Set("Pragma", "no-cache")
|
||||
c.Response.Header.Set("Expires", "Mon, 01 Jan 1990 00:00:00 GMT")
|
||||
@@ -121,56 +96,11 @@ func (h *Handler) LookupAndRedirect(c *routing.Context) error {
|
||||
c.Response.Header.Set("X-Frame-Options", "SAMEORIGIN")
|
||||
c.Response.Header.Set("Vary", "Accept-Encoding")
|
||||
|
||||
h.template(c, "redirect.html", r)
|
||||
h.respond(c, "redirect.html", r)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) template(c *routing.Context, name string, data interface{}) {
|
||||
func (h *Handler) respond(c *routing.Context, name string, data interface{}) {
|
||||
c.SetContentType("text/html; charset=UTF-8")
|
||||
h.t.ExecuteTemplate(c, name, data)
|
||||
}
|
||||
|
||||
func (h *Handler) respond(c *routing.Context, r *URLResponse) error {
|
||||
resp, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.SetContentType("application/json")
|
||||
c.Write(resp)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) respondWithError(c *routing.Context, err error) error {
|
||||
r := ErrorResponse{
|
||||
Error: err.Error(),
|
||||
}
|
||||
|
||||
resp, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.SetStatusCode(fasthttp.StatusNotFound)
|
||||
c.SetContentType("application/json")
|
||||
c.Write(resp)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) makeURLResponse(c *routing.Context, uid []byte, url []byte) URLResponse {
|
||||
return URLResponse{
|
||||
UID: string(uid),
|
||||
URL: h.makeShortURL(c, uid),
|
||||
Target: string(url),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) makeShortURL(c *routing.Context, uid []byte) string {
|
||||
shortURL := &url.URL{
|
||||
Scheme: "http",
|
||||
Host: string(c.Host()),
|
||||
Path: "/" + string(uid),
|
||||
}
|
||||
|
||||
return shortURL.String()
|
||||
h.template.ExecuteTemplate(c, name, data)
|
||||
}
|
||||
|
||||
25
web/handler_helpers.go
Normal file
25
web/handler_helpers.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"github.com/qiangxue/fasthttp-routing"
|
||||
)
|
||||
|
||||
func makeURLResponse(c *routing.Context, uid []byte, url []byte) URLResponse {
|
||||
return URLResponse{
|
||||
UID: string(uid),
|
||||
URL: makeShortURL(c, uid),
|
||||
Target: string(url),
|
||||
}
|
||||
}
|
||||
|
||||
func makeShortURL(c *routing.Context, uid []byte) string {
|
||||
shortURL := &url.URL{
|
||||
Scheme: "http",
|
||||
Host: string(c.Host()),
|
||||
Path: "/" + string(uid),
|
||||
}
|
||||
|
||||
return shortURL.String()
|
||||
}
|
||||
@@ -8,14 +8,16 @@ import (
|
||||
// NewRouter creates a new routing.Router with all handlers registered.
|
||||
func NewRouter(s shortener.Shortener) *routing.Router {
|
||||
r := routing.New()
|
||||
h := NewHandler(s)
|
||||
|
||||
r.Get("/", h.Index)
|
||||
r.Get("/api/shorten", h.Shorten)
|
||||
r.Get("/api/lookup", h.Lookup)
|
||||
r.Get("/static/*", h.Static)
|
||||
r.Get("/<uid>", h.LookupAndRedirect)
|
||||
r.Get("/*", h.NotFound)
|
||||
api := NewAPIHandler(s)
|
||||
r.Get("/api/shorten", api.Shorten)
|
||||
r.Get("/api/lookup", api.Lookup)
|
||||
|
||||
handler := NewHandler(s)
|
||||
r.Get("/", handler.Index)
|
||||
r.Get("/static/*", handler.Static)
|
||||
r.Get("/<uid>", handler.LookupAndRedirect)
|
||||
r.Get("/*", handler.NotFound)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user