1
0
Fork 0

Add search endpoint

main
Ambrose Chua 2020-11-22 16:42:35 +08:00
parent 28ca48667f
commit 7b5aeeb87e
6 changed files with 69 additions and 2 deletions

37
app.go
View File

@ -41,6 +41,7 @@ func NewDatetime() (*Datetime, error) {
mux.Handle("/js/", http.FileServer(http.Dir("assets")))
mux.Handle("/css/", http.FileServer(http.Dir("assets")))
mux.Handle("/favicon.ico", http.FileServer(http.Dir("assets")))
mux.HandleFunc("/search", app.search)
mux.HandleFunc("/", app.index)
return app, nil
@ -51,6 +52,11 @@ type appRequest struct {
Req Request
}
type appSearch struct {
App Datetime
Req map[string]string
}
// index handles all incoming page requests
func (app Datetime) index(w http.ResponseWriter, req *http.Request) {
var err error
@ -86,3 +92,34 @@ func (app Datetime) index(w http.ResponseWriter, req *http.Request) {
return
}
}
// search handles zone search queries
func (app Datetime) search(w http.ResponseWriter, req *http.Request) {
var err error
if req.Method != http.MethodGet && req.Method != http.MethodHead {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
tmpl := app.loadTemplate("search", w, req)
if tmpl == nil {
return
}
if req.Method == http.MethodHead {
return
}
// TODO: do search
search := map[string]string{
"hi": "hello",
}
l.Debug("rendering template", zap.Reflect("search", search))
err = tmpl.Execute(w, appSearch{app, search})
if err != nil {
l.Error("templating failed", zap.Error(err))
app.templateError(HTTPError{http.StatusInternalServerError, err}, w, req)
return
}
}

View File

@ -57,6 +57,7 @@ type responseType int
const (
responsePlain responseType = iota
responseHTML responseType = iota
responseJSON responseType = iota
responseAny responseType = iota
responseUnknown responseType = iota
)
@ -64,6 +65,7 @@ const (
const (
responsePlainMime = "text/plain"
responseHTMLMime = "text/html"
responseJSONMime = "application/json"
responseAnyMime = "*/*"
)
@ -77,6 +79,9 @@ func chooseResponseType(accept string) responseType {
if m.media == responseHTMLMime {
return responseHTML
}
if m.media == responseJSONMime {
return responseJSON
}
if m.media == responseAnyMime {
return responseAny
}

View File

@ -1,12 +1,18 @@
package main
import (
"errors"
"fmt"
"html/template"
"net/http"
"go.uber.org/zap"
)
// ErrTemplateNotFound is thrown when a template with the requested MIME type
// is not found.
var ErrTemplateNotFound = errors.New("unable to find template")
// loadTemplate returns a matching template for the request. It also causes an
// error if the template is not found or the Accept parameters are incorrect.
func (app Datetime) loadTemplate(name string, w http.ResponseWriter, req *http.Request) *template.Template {
@ -17,8 +23,10 @@ func (app Datetime) loadTemplate(name string, w http.ResponseWriter, req *http.R
return nil
}
if tmpl == nil {
l.Error("unable to find template", zap.String("name", name), zap.String("accept", accept))
app.simpleError(HTTPError{http.StatusInternalServerError, ErrNoTemplate}, w, req)
err := fmt.Errorf("%w \"%s\" for \"%s\"", ErrTemplateNotFound, name, accept)
l.Warn("unable to find template", zap.Error(err), zap.String("name", name), zap.String("accept", accept))
app.simpleError(HTTPError{http.StatusNotAcceptable, err}, w, req)
//app.simpleError(HTTPError{http.StatusInternalServerError, ErrNoTemplate}, w, req)
return nil
}
w.Header().Set("Content-Type", contentType)
@ -36,6 +44,9 @@ func (app Datetime) chooseTemplate(accept string, name string) (t *template.Temp
case responseHTML:
t = app.tmpl.Lookup(name + ".html")
contentType = "text/html"
case responseJSON:
t = app.tmpl.Lookup(name + ".json")
contentType = "application/json"
case responseAny:
t = app.tmpl.Lookup(name + ".txt")
contentType = "text/plain"

View File

@ -1,6 +1,7 @@
package main
import (
"encoding/json"
"html/template"
"net/http"
@ -10,6 +11,8 @@ import (
var templateFuncs = map[string]interface{}{
"statusText": templateFuncStatusText,
"thisIsSafe": templateFuncThisIsSafe,
// Encoding
"jsonMarshal": templateFuncJSONMarshal,
// Formatting
"formatOffset": templateFuncFormatOffset,
// Logic
@ -23,6 +26,14 @@ func templateFuncThisIsSafe(s string) template.HTML {
return template.HTML(s)
}
func templateFuncJSONMarshal(v interface{}) string {
b, err := json.Marshal(v)
if err != nil {
return ""
}
return string(b)
}
func templateFuncFormatOffset(offset int) string {
return FormatZoneOffset(offset)
}

View File

@ -53,7 +53,9 @@
{{template "interactive-icons.html"}}
<!--
<script src="/js/third-party/luxon.min.js"></script>
<script src="/js/interactive.js" async></script>
-->
</body>
</html>

1
templates/search.json Normal file
View File

@ -0,0 +1 @@
{{.Req | jsonMarshal | thisIsSafe }}