holiday-api/handlers.go

160 lines
4.2 KiB
Go

package main
import (
"encoding/xml"
"fmt"
"github.com/google/uuid"
"holiday-api/holiday"
"log"
"net/http"
"strconv"
"time"
)
func getHolidays(service holiday.Service) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
log.Printf("Failed parsing params: %v", err)
}
paging := holiday.Paging{
PageSize: readInt(r, "pageSize", 1000),
Page: readInt(r, "page", 0),
}
search := holiday.Search{
Country: r.Form.Get("country"),
Year: readIntNullable(r, "year"),
Date: readDateNullable(r, "date"),
RangeStart: readDateNullable(r, "rangeStart"),
RangeEnd: readDateNullable(r, "rangeEnd"),
StateHoliday: readBoolNullable(r, "stateHoliday"),
ReligiousHoliday: readBoolNullable(r, "religiousHoliday"),
}
holidays, err := service.Find(search, paging)
if err != nil {
render(w, r, 404, ErrorResponse{Created: time.Now(), Message: "failed fetching holidays"})
} else {
render(w, r, 200, mapHolidays(holidays))
}
}
}
type DateResponse struct{ time.Time }
func (d DateResponse) MarshalJSON() ([]byte, error) {
return []byte("\"" + d.String() + "\""), nil
}
func (d DateResponse) String() string {
return fmt.Sprintf(`%04d-%02d-%02d`, d.Year(), d.Month(), d.Day())
}
type ErrorResponse struct {
XMLName xml.Name `json:"-" xml:"Error"`
Created time.Time `json:"created" xml:"created"`
Message string `json:"message" xml:"message"`
Code int `json:"-" xml:"-"`
}
type HolidayResponse struct {
XMLName xml.Name `json:"-" xml:"Holidays"`
Holidays []HolidayItemResponse `json:"holidays"`
}
type HolidayItemResponse struct {
XMLName xml.Name `json:"-" xml:"Holiday"`
Id uuid.UUID `json:"id" xml:"id,attr"`
Date DateResponse `json:"date" xml:"date,attr"`
Name string `json:"name" xml:"name"`
Description string `json:"description" xml:"description,omitempty"`
IsStateHoliday bool `json:"isStateHoliday" xml:"isState,attr"`
IsReligiousHoliday bool `json:"isReligiousHoliday" xml:"isReligious,attr"`
}
type HolidaySingleResponse struct {
Id *uuid.UUID
Country string
Date DateResponse
Name string
Description string
IsStateHoliday bool
IsReligiousHoliday bool
}
type HolidaySingleRequest struct {
Id *uuid.UUID
Country string
Date DateResponse
Name string
Description string
IsStateHoliday bool
IsReligiousHoliday bool
}
func mapHolidays(holidays []holiday.Holiday) HolidayResponse {
var response = make([]HolidayItemResponse, 0, len(holidays))
for _, h := range holidays {
response = append(response, HolidayItemResponse{
Id: h.Id,
Date: DateResponse{h.Date},
Name: h.Name,
Description: h.Description,
IsStateHoliday: h.IsStateHoliday,
IsReligiousHoliday: h.IsReligiousHoliday,
})
}
return HolidayResponse{
Holidays: response,
}
}
func readDateNullable(r *http.Request, param string) *time.Time {
if r.Form.Has(param) {
var year, month, date int
count, err := fmt.Sscanf(r.Form.Get(param), "%d-%d-%d", &year, &month, &date)
if count < 3 {
log.Printf("failed reading %s: %v", param, err)
return nil
} else {
readDate := time.Date(year, time.Month(month), date, 0, 0, 0, 0, time.UTC)
return &readDate
}
} else {
return nil
}
}
func readIntNullable(r *http.Request, param string) *int {
if r.Form.Has(param) {
if value, err := strconv.Atoi(r.Form.Get(param)); err == nil {
return &value
} else {
return nil
}
} else {
return nil
}
}
func readBoolNullable(r *http.Request, param string) *bool {
if r.Form.Has(param) {
if value, err := strconv.ParseBool(r.Form.Get(param)); err == nil {
return &value
} else {
return nil
}
} else {
return nil
}
}
func readInt(r *http.Request, param string, defaultValue int) int {
if r.Form.Has(param) {
if value, err := strconv.Atoi(r.Form.Get(param)); err == nil {
return value
} else {
return defaultValue
}
} else {
return defaultValue
}
}