Split Handler into Handler and APIHandler

This commit is contained in:
2016-07-17 17:03:50 +01:00
parent 5065c3178d
commit bb44578173
6 changed files with 125 additions and 99 deletions

69
web/api_handler.go Normal file
View 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
}

View File

@@ -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"`
}

View File

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

View File

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

View File

@@ -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
}