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 } }