A very naive, simple and not so robust HTTP API responder implementation.

This commit is contained in:
2020-11-29 06:09:35 +05:00
parent f5d898b025
commit afad4f5d7f
5 changed files with 67 additions and 5 deletions

View File

@@ -1,20 +1,53 @@
package httpserver
import (
"context"
"net/http"
"strings"
"go.dev.pztrn.name/metricator/internal/common"
)
// HTTP requests handler.
type handler struct {
handler common.HTTPHandlerFunc
handlers map[string]common.HTTPHandlerFunc
}
// Registers request's handler.
func (h *handler) register(hndl common.HTTPHandlerFunc) {
h.handler = hndl
func (h *handler) register(name string, hndl common.HTTPHandlerFunc) {
h.handlers[name] = hndl
}
// ServeHTTP handles every HTTP request.
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {}
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if !strings.HasPrefix(r.URL.Path, "/api") {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte("400 Bad Request - invalid path"))
return
}
// Request validation.
pathSplitted := strings.Split(r.URL.Path, "/")
if len(pathSplitted) < 3 {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte("400 Bad Request - invalid path"))
}
handler, found := h.handlers[pathSplitted[2]]
if !found {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte("400 Bad Request - invalid application name"))
return
}
requestContext := r.Context()
// Compose metric name.
metricName := strings.Join(pathSplitted[3:], "/")
ctx := context.WithValue(requestContext, common.ContextKeyMetric, metricName)
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(handler(ctx)))
}

View File

@@ -8,6 +8,7 @@ import (
"strings"
"time"
"go.dev.pztrn.name/metricator/internal/common"
"go.dev.pztrn.name/metricator/internal/configuration"
)
@@ -39,7 +40,9 @@ func (h *HTTPServer) getRequestContext(_ net.Listener) context.Context {
// Initializes handler and HTTP server structure.
func (h *HTTPServer) initialize() {
h.handler = &handler{}
h.handler = &handler{
handlers: make(map[string]common.HTTPHandlerFunc),
}
// We do not need to specify all possible parameters for HTTP server, so:
// nolint:exhaustivestruct
h.server = &http.Server{
@@ -53,6 +56,11 @@ func (h *HTTPServer) initialize() {
}
}
// RegisterHandlerForApplication registers HTTP handler for application.
func (h *HTTPServer) RegisterHandlerForApplication(name string, handler common.HTTPHandlerFunc) {
h.handler.register(name, handler)
}
// Start starts HTTP server in another goroutine and one more goroutine which
// is listening to main context's Cancel() call to stop HTTP server.
func (h *HTTPServer) Start() {