Refactored the application structure to better separate concerns between files and packages
Some checks failed
ci/woodpecker/push/build-image Pipeline failed
Some checks failed
ci/woodpecker/push/build-image Pipeline failed
This commit is contained in:
@@ -1,119 +1,14 @@
|
||||
// endpoints.go registers all HTTP endpoint definitions for weatherapi.
|
||||
// Layer: adapters/inbound/httpapi endpoint registry only.
|
||||
package httpapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"gitea.maximumdirect.net/ejr/feedapi/bind"
|
||||
"gitea.maximumdirect.net/ejr/feedapi/endpoint"
|
||||
"gitea.maximumdirect.net/ejr/feedapi/render"
|
||||
"gitea.maximumdirect.net/ejr/feedapi/response"
|
||||
"gitea.maximumdirect.net/ejr/weatherapi/internal/core"
|
||||
"gitea.maximumdirect.net/ejr/weatherfeeder/model"
|
||||
)
|
||||
|
||||
// Service describes the weather use-cases needed by the HTTP adapter.
|
||||
type Service interface {
|
||||
LatestObservation(ctx context.Context) (*model.WeatherObservation, error)
|
||||
LatestHourlyForecast(ctx context.Context) (*model.WeatherForecastRun, error)
|
||||
LatestActiveAlerts(ctx context.Context) (*model.WeatherAlertRun, error)
|
||||
CurrentConditions(ctx context.Context) (*core.CurrentConditions, error)
|
||||
}
|
||||
|
||||
type queryRequest struct {
|
||||
Units core.Units
|
||||
}
|
||||
import "gitea.maximumdirect.net/ejr/feedapi/endpoint"
|
||||
|
||||
func Definitions(svc Service) []endpoint.Definition {
|
||||
return []endpoint.Definition{
|
||||
endpoint.GET(
|
||||
"/observations",
|
||||
bindQuery,
|
||||
func(ctx context.Context, req queryRequest) (any, error) {
|
||||
obs, err := svc.LatestObservation(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response.Envelope{Data: core.ObservationPayload(obs, req.Units)}, nil
|
||||
},
|
||||
endpoint.WithProduces(render.FormatJSON, render.FormatXML, render.FormatText),
|
||||
endpoint.WithTemplate("observations.txt.tmpl"),
|
||||
),
|
||||
endpoint.GET(
|
||||
"/forecast/hourly",
|
||||
bindQuery,
|
||||
func(ctx context.Context, req queryRequest) (any, error) {
|
||||
run, err := svc.LatestHourlyForecast(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response.Envelope{Data: core.ForecastPayload(run, req.Units)}, nil
|
||||
},
|
||||
endpoint.WithProduces(render.FormatJSON, render.FormatXML, render.FormatText),
|
||||
endpoint.WithTemplate("forecast_hourly.txt.tmpl"),
|
||||
),
|
||||
endpoint.GET(
|
||||
"/alerts/active",
|
||||
bindQuery,
|
||||
func(ctx context.Context, req queryRequest) (any, error) {
|
||||
run, err := svc.LatestActiveAlerts(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response.Envelope{Data: core.AlertsPayload(run, req.Units)}, nil
|
||||
},
|
||||
endpoint.WithProduces(render.FormatJSON, render.FormatXML, render.FormatText),
|
||||
endpoint.WithTemplate("alerts_active.txt.tmpl"),
|
||||
),
|
||||
endpoint.GET(
|
||||
"/conditions/current",
|
||||
bindQuery,
|
||||
func(ctx context.Context, req queryRequest) (any, error) {
|
||||
conditions, err := svc.CurrentConditions(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response.Envelope{Data: core.CurrentConditionsPayload(conditions, req.Units)}, nil
|
||||
},
|
||||
endpoint.WithProduces(render.FormatJSON, render.FormatXML, render.FormatText),
|
||||
endpoint.WithTemplate("conditions_current.txt.tmpl"),
|
||||
),
|
||||
observationDefinition(svc),
|
||||
forecastDefinition(svc),
|
||||
alertsDefinition(svc),
|
||||
conditionsDefinition(svc),
|
||||
}
|
||||
}
|
||||
|
||||
func bindQuery(r *http.Request) (queryRequest, error) {
|
||||
normalizeCommonQueryValue(r, "units")
|
||||
normalizeCommonQueryValue(r, "format")
|
||||
|
||||
common, err := bind.CommonQueryParams(r, bind.QueryPolicy{
|
||||
AllowUnits: true,
|
||||
AllowFormat: true,
|
||||
DefaultUnits: string(core.UnitsMetric),
|
||||
RejectUnknown: true,
|
||||
})
|
||||
if err != nil {
|
||||
return queryRequest{}, err
|
||||
}
|
||||
|
||||
units := core.Units(strings.ToLower(strings.TrimSpace(common.Units)))
|
||||
if units == "" {
|
||||
units = core.UnitsMetric
|
||||
}
|
||||
return queryRequest{Units: units}, nil
|
||||
}
|
||||
|
||||
func normalizeCommonQueryValue(r *http.Request, key string) {
|
||||
q := r.URL.Query()
|
||||
values, ok := q[key]
|
||||
if !ok || len(values) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
normalized := strings.ToLower(strings.TrimSpace(values[0]))
|
||||
if normalized == values[0] {
|
||||
return
|
||||
}
|
||||
q.Set(key, normalized)
|
||||
r.URL.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user