-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathurlpath.go
More file actions
132 lines (111 loc) · 3.28 KB
/
urlpath.go
File metadata and controls
132 lines (111 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright (c) CattleCloud LLC
// SPDX-License-Identifier: BSD-3-Clause
package urlpath
import (
"fmt"
"net/http"
"strconv"
"github.com/gorilla/mux"
)
// Typical usage:
//
// // in the mux definition, e.g.
// router.Handle("/v1/{foo}/{bar}, newHandler())
//
// // in the handler implementation, e.g.
// var foo string
// var bar int
// err := urlpath.Parse(request, urlpath.Schema{
// "foo": urlpath.String(&foo),
// "bar": urlpath.Int(&bar),
// })
// A Parameter is a named element of a URL route,
// encoded such that a gorilla router interprets it
// as a path parameter.
type Parameter string
func (p Parameter) String() string {
return "{" + string(p) + "}"
}
// Name returns the name of the parameter.
func (p Parameter) Name() string {
return string(p)
}
// A Schema describes how path variables should be parsed.
// Currently only int and string types are supported.
type Schema map[Parameter]Parser
// MustParse will parse the URL path vars from r given the
// element names and parsers defined in schema. If there is
// a problem parsing the values, a panic is triggered.
//
// This function only works with requests being processed by
// handlers of a gorilla/mux.
func MustParse(r *http.Request, schema Schema) {
if err := Parse(r, schema); err != nil {
panic("urlpath: " + err.Error())
}
}
// Parse will parse the URL path vars from r given the
// element names and parsers defined in schema. If there
// is a problem parsing the values, an error is returned.
//
// This function only works with requests being processed by
// handlers of a gorilla/mux.
func Parse(r *http.Request, schema Schema) error {
return ParseValues(mux.Vars(r), schema)
}
// ParseValues will parse the parameters in vars given the
// element names and parsers defined in schema.
//
// Most use cases will be parsing values coming from an *http.Request,
// which can be done conveniently with Parse.
func ParseValues(values map[string]string, schema Schema) error {
for name, parser := range schema {
value, exists := values[name.Name()]
if !exists {
return fmt.Errorf("url path element not present: %q", name)
}
if err := parser.Parse(value); err != nil {
return fmt.Errorf("could not parse url path variable: %w", err)
}
}
return nil
}
// A Parser parses raw input into a destination variable.
type Parser interface {
Parse(string) error
}
type StringType interface {
~string
}
type stringParser[T StringType] struct {
destination *T
}
func (p *stringParser[T]) Parse(s string) error {
*p.destination = T(s)
return nil
}
// String creates a parser that will parse a path element into s.
func String[T StringType](s *T) Parser {
return &stringParser[T]{destination: s}
}
// IntType represents any type compatible with the Go integer built-in types,
// to be used as a destination for writing the value of an url path element.
type IntType interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
}
type intParser[T IntType] struct {
destination *T
}
func (p *intParser[T]) Parse(s string) error {
i, err := strconv.Atoi(s)
if err != nil {
return err
}
*p.destination = T(i)
return nil
}
// Int creates a Parser that will parse a path element into i.
func Int[T IntType](i *T) Parser {
return &intParser[T]{destination: i}
}