Get basic HTTP server working

This commit is contained in:
2016-07-11 00:51:48 +01:00
parent 0ddf94c504
commit 76145b3969
4 changed files with 251 additions and 5 deletions

12
main.go
View File

@@ -1,12 +1,13 @@
package main
import (
"fmt"
"log"
"os"
"github.com/jimeh/ozu.io/shortner"
"github.com/jimeh/ozu.io/storage/goleveldbstore"
"github.com/jimeh/ozu.io/web"
"github.com/valyala/fasthttp"
)
func main() {
@@ -14,8 +15,15 @@ func main() {
if err != nil {
log.Fatal(err)
}
defer store.Close()
shortner := shortner.New(store)
router := web.NewRouter(shortner)
fmt.Println(router)
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
log.Fatal(fasthttp.ListenAndServe(":"+port, router.HandleRequest))
}

15
web/responses.go Normal file
View File

@@ -0,0 +1,15 @@
package web
//go:generate easyjson -all responses.go
// ShortenedResponse contains shortened URL info.
type ShortenedResponse struct {
UID string `json:"uid"`
ShortURL string `json:"short_url"`
URL string `json:"url"`
}
// ErrorResponse contains error info.
type ErrorResponse struct {
Error string `json:"error"`
}

132
web/responses_easyjson.go Normal file
View File

@@ -0,0 +1,132 @@
// AUTOGENERATED FILE: easyjson marshaller/unmarshallers.
package web
import (
json "encoding/json"
jlexer "github.com/mailru/easyjson/jlexer"
jwriter "github.com/mailru/easyjson/jwriter"
)
var _ = json.RawMessage{} // suppress unused package warning
func easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ErrorResponse(in *jlexer.Lexer, out *ErrorResponse) {
if in.IsNull() {
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeString()
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "error":
out.Error = string(in.String())
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
}
func easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ErrorResponse(out *jwriter.Writer, in ErrorResponse) {
out.RawByte('{')
first := true
_ = first
if !first {
out.RawByte(',')
}
first = false
out.RawString("\"error\":")
out.String(string(in.Error))
out.RawByte('}')
}
func (v ErrorResponse) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjson_559270ae_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)
}
func (v *ErrorResponse) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjson_559270ae_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)
}
func easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ShortenedResponse(in *jlexer.Lexer, out *ShortenedResponse) {
if in.IsNull() {
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeString()
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "uid":
out.UID = string(in.String())
case "short_url":
out.ShortURL = string(in.String())
case "url":
out.URL = string(in.String())
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
}
func easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ShortenedResponse(out *jwriter.Writer, in ShortenedResponse) {
out.RawByte('{')
first := true
_ = first
if !first {
out.RawByte(',')
}
first = false
out.RawString("\"uid\":")
out.String(string(in.UID))
if !first {
out.RawByte(',')
}
first = false
out.RawString("\"short_url\":")
out.String(string(in.ShortURL))
if !first {
out.RawByte(',')
}
first = false
out.RawString("\"url\":")
out.String(string(in.URL))
out.RawByte('}')
}
func (v ShortenedResponse) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ShortenedResponse(&w, v)
return w.Buffer.BuildBytes(), w.Error
}
func (v ShortenedResponse) MarshalEasyJSON(w *jwriter.Writer) {
easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ShortenedResponse(w, v)
}
func (v *ShortenedResponse) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ShortenedResponse(&r, v)
return r.Error()
}
func (v *ShortenedResponse) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ShortenedResponse(l, v)
}

View File

@@ -1,12 +1,103 @@
package web
import (
"github.com/buaazp/fasthttprouter"
"encoding/json"
"fmt"
"net/url"
"github.com/jimeh/ozu.io/shortner"
"github.com/qiangxue/fasthttp-routing"
"github.com/valyala/fasthttp"
)
func NewRouter(shortner *shortner.Shortner) *fasthttprouter.Router {
router := fasthttprouter.New()
// NewRouter creates a new fasthttprouter.Router with all handlers registered.
func NewRouter(shortner *shortner.Shortner) *routing.Router {
router := routing.New()
handlers := Handlers{shortner}
router.Get("/", handlers.Index)
router.Get("/api/shorten", handlers.Shorten)
router.Get("/api/lookup", handlers.Lookup)
router.Get("/<uid>", handlers.LookupAndRedirect)
return router
}
// Handlers handle HTTP requests.
type Handlers struct {
s *shortner.Shortner
}
// Index handles requests for root.
func (h *Handlers) Index(c *routing.Context) error {
c.WriteString("Welcome to ozu.io, a shitty URL shortner.")
return nil
}
// Shorten shortens given URL.
func (h *Handlers) Shorten(c *routing.Context) error {
c.SetContentType("application/json")
uid, url, err := h.s.Shorten(c.FormValue("url"))
if err != nil {
c.SetStatusCode(fasthttp.StatusBadRequest)
response, _ := json.Marshal(ErrorResponse{err.Error()})
c.Write(response)
return nil
}
h.respondWithShortened(c, uid, url)
return nil
}
// Lookup shortened UID.
func (h *Handlers) Lookup(c *routing.Context) error {
c.SetContentType("application/json")
uid := c.FormValue("uid")
url, err := h.s.Lookup(uid)
if err != nil {
c.SetStatusCode(fasthttp.StatusNotFound)
respBytes, _ := json.Marshal(ErrorResponse{err.Error()})
c.Write(respBytes)
return nil
}
h.respondWithShortened(c, uid, url)
return nil
}
// LookupAndRedirect looks up given UID and redirects to it's URL.
func (h *Handlers) LookupAndRedirect(c *routing.Context) error {
uid := c.Param("uid")
url, err := h.s.Lookup([]byte(uid))
if err != nil {
c.SetStatusCode(fasthttp.StatusNotFound)
fmt.Fprint(c, "404 Not Found")
return nil
}
c.Redirect(string(url), fasthttp.StatusMovedPermanently)
return nil
}
func (h *Handlers) respondWithShortened(c *routing.Context, uid []byte, url []byte) {
c.SetStatusCode(fasthttp.StatusOK)
response := ShortenedResponse{
UID: string(uid),
ShortURL: h.makeShortURL(c, uid),
URL: string(url),
}
respBytes, _ := json.Marshal(response)
c.Write(respBytes)
}
func (h *Handlers) makeShortURL(c *routing.Context, uid []byte) string {
shortURL := &url.URL{
Scheme: "http",
Host: string(c.Host()),
Path: "/" + string(uid),
}
return shortURL.String()
}