Add search endpoint
parent
28ca48667f
commit
7b5aeeb87e
37
app.go
37
app.go
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
5
mime.go
5
mime.go
|
@ -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
|
||||
}
|
||||
|
|
15
template.go
15
template.go
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{{.Req | jsonMarshal | thisIsSafe }}
|
Loading…
Reference in New Issue