README.md
1# parth
2
3 go get -u github.com/h2non/parth
4
5Package parth provides path parsing for segment unmarshaling and slicing. In
6other words, parth provides simple and flexible access to (URL) path parameters.
7
8Along with string, all basic non-alias types are supported. An interface is
9available for implementation by user-defined types. When handling an int, uint,
10or float of any size, the first valid value within the specified segment will be
11used.
12
13## Usage
14
15```go
16Variables
17func Segment(path string, i int, v interface{}) error
18func Sequent(path, key string, v interface{}) error
19func Span(path string, i, j int) (string, error)
20func SubSeg(path, key string, i int, v interface{}) error
21func SubSpan(path, key string, i, j int) (string, error)
22type Parth
23 func New(path string) *Parth
24 func NewBySpan(path string, i, j int) *Parth
25 func NewBySubSpan(path, key string, i, j int) *Parth
26 func (p *Parth) Err() error
27 func (p *Parth) Segment(i int, v interface{})
28 func (p *Parth) Sequent(key string, v interface{})
29 func (p *Parth) Span(i, j int) string
30 func (p *Parth) SubSeg(key string, i int, v interface{})
31 func (p *Parth) SubSpan(key string, i, j int) string
32type Unmarshaler
33```
34
35### Setup ("By Index")
36
37```go
38import (
39 "fmt"
40
41 "github.com/codemodus/parth"
42)
43
44func handler(w http.ResponseWriter, r *http.Request) {
45 var s string
46 if err := parth.Segment(r.URL.Path, 4, &s); err != nil {
47 fmt.Fprintln(os.Stderr, err)
48 }
49
50 fmt.Println(r.URL.Path)
51 fmt.Printf("%v (%T)\n", s, s)
52
53 // Output:
54 // /some/path/things/42/others/3
55 // others (string)
56}
57```
58
59### Setup ("By Key")
60
61```go
62import (
63 "fmt"
64
65 "github.com/codemodus/parth"
66)
67
68func handler(w http.ResponseWriter, r *http.Request) {
69 var i int64
70 if err := parth.Sequent(r.URL.Path, "things", &i); err != nil {
71 fmt.Fprintln(os.Stderr, err)
72 }
73
74 fmt.Println(r.URL.Path)
75 fmt.Printf("%v (%T)\n", i, i)
76
77 // Output:
78 // /some/path/things/42/others/3
79 // 42 (int64)
80}
81```
82
83### Setup (Parth Type)
84
85```go
86import (
87 "fmt"
88
89 "github.com/codemodus/parth"
90)
91
92func handler(w http.ResponseWriter, r *http.Request) {
93 var s string
94 var f float32
95
96 p := parth.New(r.URL.Path)
97 p.Segment(2, &s)
98 p.SubSeg("key", 1, &f)
99 if err := p.Err(); err != nil {
100 fmt.Fprintln(os.Stderr, err)
101 }
102
103 fmt.Println(r.URL.Path)
104 fmt.Printf("%v (%T)\n", s, s)
105 fmt.Printf("%v (%T)\n", f, f)
106
107 // Output:
108 // /zero/one/two/key/four/5.5/six
109 // two (string)
110 // 5.5 (float32)
111}
112```
113
114### Setup (Unmarshaler)
115
116```go
117import (
118 "fmt"
119
120 "github.com/codemodus/parth"
121)
122
123func handler(w http.ResponseWriter, r *http.Request) {
124 /*
125 type mytype []byte
126
127 func (m *mytype) UnmarshalSegment(seg string) error {
128 *m = []byte(seg)
129 }
130 */
131
132 var m mytype
133 if err := parth.Segment(r.URL.Path, 4, &m); err != nil {
134 fmt.Fprintln(os.Stderr, err)
135 }
136
137 fmt.Println(r.URL.Path)
138 fmt.Printf("%v == %q (%T)\n", m, m, m)
139
140 // Output:
141 // /zero/one/two/key/four/5.5/six
142 // [102 111 117 114] == "four" (mypkg.mytype)
143}
144```
145
146## More Info
147
148### Keep Using http.HandlerFunc And Minimize context.Context Usage
149
150The most obvious use case for parth is when working with any URL path such as
151the one found at http.Request.URL.Path. parth is fast enough that it can be used
152multiple times in place of a single use of similar router-parameter schemes or
153even context.Context. There is no need to use an alternate http handler function
154definition in order to pass data that is already being passed. The http.Request
155type already holds URL data and parth is great at handling it. Additionally,
156parth takes care of parsing selected path segments into the types actually
157needed. Parth not only does more, it's usually faster and less intrusive than
158the alternatives.
159
160### Indexes
161
162If an index is negative, the negative count begins with the last segment.
163Providing a 0 for the second index is a special case which acts as an alias for
164the end of the path. An error is returned if: 1. Any index is out of range of
165the path; 2. When there are two indexes, the first index does not precede the
166second index.
167
168### Keys
169
170If a key is involved, functions will only handle the portion of the path
171subsequent to the provided key. An error is returned if the key cannot be found
172in the path.
173
174### First Whole, First Decimal (Restated - Important!)
175
176When handling an int, uint, or float of any size, the first valid value within
177the specified segment will be used.
178
179## Documentation
180
181View the [GoDoc](http://godoc.org/github.com/codemodus/parth)
182
183## Benchmarks
184
185 Go 1.11
186 benchmark iter time/iter bytes alloc allocs
187 --------- ---- --------- ----------- ------
188 BenchmarkSegmentString-8 30000000 39.60 ns/op 0 B/op 0 allocs/op
189 BenchmarkSegmentInt-8 20000000 65.60 ns/op 0 B/op 0 allocs/op
190 BenchmarkSegmentIntNegIndex-8 20000000 86.60 ns/op 0 B/op 0 allocs/op
191 BenchmarkSpan-8 100000000 18.20 ns/op 0 B/op 0 allocs/op
192 BenchmarkStdlibSegmentString-8 5000000 454.00 ns/op 50 B/op 2 allocs/op
193 BenchmarkStdlibSegmentInt-8 3000000 526.00 ns/op 50 B/op 2 allocs/op
194 BenchmarkStdlibSpan-8 3000000 518.00 ns/op 69 B/op 2 allocs/op
195 BenchmarkContextLookupSetGet-8 1000000 1984.00 ns/op 480 B/op 6 allocs/op
196
197