refactor(smalltrip,problems): define RetryAfter header parsing into separated type
This commit is contained in:
@@ -1,9 +1,6 @@
|
|||||||
package problem
|
package problem
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"encoding/xml"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -304,71 +301,11 @@ func NewTooManyRequests[T time.Time | time.Duration](retryAfter T, opts ...Optio
|
|||||||
|
|
||||||
type TooManyRequests[T time.Time | time.Duration] struct {
|
type TooManyRequests[T time.Time | time.Duration] struct {
|
||||||
Problem
|
Problem
|
||||||
RetryAfter T `json:"retryAfter" xml:"retry-after"`
|
RetryAfter RetryAfter[T] `json:"retryAfter" xml:"retry-after"`
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
_ json.Marshaler = TooManyRequests[time.Time]{}
|
|
||||||
_ xml.Marshaler = TooManyRequests[time.Time]{}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (p TooManyRequests[T]) MarshalJSON() ([]byte, error) {
|
|
||||||
switch t := any(p.RetryAfter).(type) {
|
|
||||||
case time.Time:
|
|
||||||
return json.Marshal(struct {
|
|
||||||
Problem
|
|
||||||
RetryAfter string `json:"retryAfter,omitempty"`
|
|
||||||
}{
|
|
||||||
Problem: p.Problem,
|
|
||||||
RetryAfter: t.Format(time.RFC3339),
|
|
||||||
})
|
|
||||||
case time.Duration:
|
|
||||||
return json.Marshal(struct {
|
|
||||||
Problem
|
|
||||||
RetryAfter int `json:"retryAfter,omitempty"`
|
|
||||||
}{
|
|
||||||
Problem: p.Problem,
|
|
||||||
RetryAfter: int(t.Seconds()),
|
|
||||||
})
|
|
||||||
default:
|
|
||||||
return nil, errors.New("problems-not-implemented: RetryAfter is not of type time.Time or time.Duration")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p TooManyRequests[T]) MarshalXML(e *xml.Encoder, _ xml.StartElement) error {
|
|
||||||
switch t := any(p.RetryAfter).(type) {
|
|
||||||
case time.Time:
|
|
||||||
return e.Encode(struct {
|
|
||||||
Problem
|
|
||||||
RetryAfter string `xml:"retry-after,omitempty"`
|
|
||||||
}{
|
|
||||||
Problem: p.Problem,
|
|
||||||
RetryAfter: t.Format(time.RFC3339),
|
|
||||||
})
|
|
||||||
case time.Duration:
|
|
||||||
return e.Encode(struct {
|
|
||||||
Problem
|
|
||||||
RetryAfter int `xml:"retry-after,omitempty"`
|
|
||||||
}{
|
|
||||||
Problem: p.Problem,
|
|
||||||
RetryAfter: int(t.Seconds()),
|
|
||||||
})
|
|
||||||
default:
|
|
||||||
return errors.New("problems-not-implemented: RetryAfter is not of type time.Time or time.Duration")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p TooManyRequests[T]) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (p TooManyRequests[T]) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
switch t := any(p.RetryAfter).(type) {
|
w.Header().Set("Retry-After", p.RetryAfter.String())
|
||||||
case time.Time:
|
|
||||||
if !t.IsZero() {
|
|
||||||
w.Header().Set("Retry-After", t.Format(http.TimeFormat))
|
|
||||||
}
|
|
||||||
case time.Duration:
|
|
||||||
if t != 0 {
|
|
||||||
w.Header().Set("Retry-After", fmt.Sprintf("%.0f", t.Seconds()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p.handler(p).ServeHTTP(w, r)
|
p.handler(p).ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
package problem
|
package problem
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -67,71 +65,11 @@ func NewNotImplemented[T time.Time | time.Duration](retryAfter T, opts ...Option
|
|||||||
|
|
||||||
type NotImplemented[T time.Time | time.Duration] struct {
|
type NotImplemented[T time.Time | time.Duration] struct {
|
||||||
Problem
|
Problem
|
||||||
RetryAfter T `json:"retryAfter" xml:"retry-after"`
|
RetryAfter RetryAfter[T] `json:"retryAfter" xml:"retry-after"`
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
_ json.Marshaler = NotImplemented[time.Time]{}
|
|
||||||
_ xml.Marshaler = NotImplemented[time.Time]{}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (p NotImplemented[T]) MarshalJSON() ([]byte, error) {
|
|
||||||
switch t := any(p.RetryAfter).(type) {
|
|
||||||
case time.Time:
|
|
||||||
return json.Marshal(struct {
|
|
||||||
Problem
|
|
||||||
RetryAfter string `json:"retryAfter,omitempty"`
|
|
||||||
}{
|
|
||||||
Problem: p.Problem,
|
|
||||||
RetryAfter: t.Format(time.RFC3339),
|
|
||||||
})
|
|
||||||
case time.Duration:
|
|
||||||
return json.Marshal(struct {
|
|
||||||
Problem
|
|
||||||
RetryAfter int `json:"retryAfter,omitempty"`
|
|
||||||
}{
|
|
||||||
Problem: p.Problem,
|
|
||||||
RetryAfter: int(t.Seconds()),
|
|
||||||
})
|
|
||||||
default:
|
|
||||||
return nil, errors.New("problems-not-implemented: RetryAfter is not of type time.Time or time.Duration")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p NotImplemented[T]) MarshalXML(e *xml.Encoder, _ xml.StartElement) error {
|
|
||||||
switch t := any(p.RetryAfter).(type) {
|
|
||||||
case time.Time:
|
|
||||||
return e.Encode(struct {
|
|
||||||
Problem
|
|
||||||
RetryAfter string `xml:"retry-after,omitempty"`
|
|
||||||
}{
|
|
||||||
Problem: p.Problem,
|
|
||||||
RetryAfter: t.Format(time.RFC3339),
|
|
||||||
})
|
|
||||||
case time.Duration:
|
|
||||||
return e.Encode(struct {
|
|
||||||
Problem
|
|
||||||
RetryAfter int `xml:"retry-after,omitempty"`
|
|
||||||
}{
|
|
||||||
Problem: p.Problem,
|
|
||||||
RetryAfter: int(t.Seconds()),
|
|
||||||
})
|
|
||||||
default:
|
|
||||||
return errors.New("problems-not-implemented: RetryAfter is not of type time.Time or time.Duration")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p NotImplemented[T]) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (p NotImplemented[T]) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
switch t := any(p.RetryAfter).(type) {
|
w.Header().Set("Retry-After", p.RetryAfter.String())
|
||||||
case time.Time:
|
|
||||||
if !t.IsZero() {
|
|
||||||
w.Header().Set("Retry-After", t.Format(http.TimeFormat))
|
|
||||||
}
|
|
||||||
case time.Duration:
|
|
||||||
if t != 0 {
|
|
||||||
w.Header().Set("Retry-After", fmt.Sprintf("%.0f", t.Seconds()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p.handler(p).ServeHTTP(w, r)
|
p.handler(p).ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,71 +86,11 @@ func NewServiceUnavailable[T time.Time | time.Duration](retryAfter T, opts ...Op
|
|||||||
|
|
||||||
type ServiceUnavailable[T time.Time | time.Duration] struct {
|
type ServiceUnavailable[T time.Time | time.Duration] struct {
|
||||||
Problem
|
Problem
|
||||||
RetryAfter T `json:"retryAfter" xml:"retry-after"`
|
RetryAfter RetryAfter[T] `json:"retryAfter" xml:"retry-after"`
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
_ json.Marshaler = ServiceUnavailable[time.Time]{}
|
|
||||||
_ xml.Marshaler = ServiceUnavailable[time.Time]{}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (p ServiceUnavailable[T]) MarshalJSON() ([]byte, error) {
|
|
||||||
switch t := any(p.RetryAfter).(type) {
|
|
||||||
case time.Time:
|
|
||||||
return json.Marshal(struct {
|
|
||||||
Problem
|
|
||||||
RetryAfter string `json:"retryAfter,omitempty"`
|
|
||||||
}{
|
|
||||||
Problem: p.Problem,
|
|
||||||
RetryAfter: t.Format(time.RFC3339),
|
|
||||||
})
|
|
||||||
case time.Duration:
|
|
||||||
return json.Marshal(struct {
|
|
||||||
Problem
|
|
||||||
RetryAfter int `json:"retryAfter,omitempty"`
|
|
||||||
}{
|
|
||||||
Problem: p.Problem,
|
|
||||||
RetryAfter: int(t.Seconds()),
|
|
||||||
})
|
|
||||||
default:
|
|
||||||
return nil, errors.New("problems-not-implemented: RetryAfter is not of type time.Time or time.Duration")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p ServiceUnavailable[T]) MarshalXML(e *xml.Encoder, _ xml.StartElement) error {
|
|
||||||
switch t := any(p.RetryAfter).(type) {
|
|
||||||
case time.Time:
|
|
||||||
return e.Encode(struct {
|
|
||||||
Problem
|
|
||||||
RetryAfter string `xml:"retry-after,omitempty"`
|
|
||||||
}{
|
|
||||||
Problem: p.Problem,
|
|
||||||
RetryAfter: t.Format(time.RFC3339),
|
|
||||||
})
|
|
||||||
case time.Duration:
|
|
||||||
return e.Encode(struct {
|
|
||||||
Problem
|
|
||||||
RetryAfter int `xml:"retry-after,omitempty"`
|
|
||||||
}{
|
|
||||||
Problem: p.Problem,
|
|
||||||
RetryAfter: int(t.Seconds()),
|
|
||||||
})
|
|
||||||
default:
|
|
||||||
return errors.New("problems-not-implemented: RetryAfter is not of type time.Time or time.Duration")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p ServiceUnavailable[T]) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (p ServiceUnavailable[T]) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
switch t := any(p.RetryAfter).(type) {
|
w.Header().Set("Retry-After", p.RetryAfter.String())
|
||||||
case time.Time:
|
|
||||||
if !t.IsZero() {
|
|
||||||
w.Header().Set("Retry-After", t.Format(http.TimeFormat))
|
|
||||||
}
|
|
||||||
case time.Duration:
|
|
||||||
if t != 0 {
|
|
||||||
w.Header().Set("Retry-After", fmt.Sprintf("%.0f", t.Seconds()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p.handler(p).ServeHTTP(w, r)
|
p.handler(p).ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
33
smalltrip/problem/headers.go
Normal file
33
smalltrip/problem/headers.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package problem
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RetryAfter[T time.Time | time.Duration] struct {
|
||||||
|
time T
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ encoding.TextMarshaler = RetryAfter[time.Time]{}
|
||||||
|
_ fmt.Stringer = RetryAfter[time.Time]{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h RetryAfter[T]) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(h.String()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h RetryAfter[T]) String() string {
|
||||||
|
switch t := any(h.time).(type) {
|
||||||
|
case time.Time:
|
||||||
|
if !t.IsZero() {
|
||||||
|
return t.Format(http.TimeFormat)
|
||||||
|
}
|
||||||
|
case time.Duration:
|
||||||
|
return fmt.Sprintf("%.0f", t.Seconds())
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user