Skip to content

Commit 6964a94

Browse files
joeybloggsjoeybloggs
authored andcommitted
Update README
1 parent 39d2fd5 commit 6964a94

File tree

4 files changed

+37
-229
lines changed

4 files changed

+37
-229
lines changed

README.md

Lines changed: 11 additions & 227 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,17 @@ LARS is a fast radix-tree based, zero allocation, HTTP router for Go. [ view ex
1111

1212
Why Another HTTP Router?
1313
------------------------
14-
Have you ever been painted into a corner by a framework, **ya me too!** and I've noticed that allot of routers out there, IMHO, are adding so much functionality that they are turning into Web Frameworks, (which is fine, frameworks are important) however, not at the expense of flexibility and configurability. So with no further ado, introducing LARS an HTTP router that can be your launching pad in creating a framework for your needs. How? Context is an interface [see example here](https://github.com/go-playground/lars/blob/master/examples/all-in-one/main.go), where you can add as little or much as you want or need and most importantly...under your control. ( I will be creating a full example app in the near future that can be used as a starting point for any project. )
14+
Have you ever been painted into a corner by a framework, **ya me too!** and I've noticed that allot of routers out there, IMHO, are adding so much functionality that they are turning into Web Frameworks, (which is fine, frameworks are important) however, not at the expense of flexibility and configurability. So with no further ado, introducing LARS an HTTP router that can be your launching pad in creating a framework for your needs. How? Context is an interface [see example here](https://github.com/go-playground/lars/blob/master/examples/all-in-one/main.go), where you can add as little or much as you want or need and most importantly...**under your control**.
1515

1616
Key & Unique Features
1717
--------------
1818
- [x] Context is an interface allowing passing of framework/globals/application specific variables. [example](https://github.com/go-playground/lars/blob/master/examples/all-in-one/main.go)
19-
- [x] Contains helpful logic to help prevent adding bad routes, keeping your url's consistent.
20-
* i.e. /user/:id and /user/:user_id - the second one will fail to add letting you know that :user_id should be :id
19+
- [x] Contains helpful logic to help prevent adding bad routes, keeping your url's consistent. i.e. /user/:id and /user/:user_id - the second one will fail to add letting you know that :user_id should be :id
2120
- [x] Has an uber simple middleware + handler definitions!!! middleware and handlers actually have the exact same definition!
22-
- [x] Can register custom handlers for making other middleware + handler patterns usable with this router
23-
* best part about this is can register one for your custom context and not have to do type casting everywhere [see here](https://github.com/go-playground/lars/blob/master/examples/custom-handler/main.go)
24-
- [x] Full support for standard/native http Handler + HandlerFunc [see here](https://github.com/go-playground/lars/blob/master/examples/native/main.go)
21+
- [x] Can register custom handlers for making other middleware + handler patterns usable with this router; the best part about this is can register one for your custom context and not have to do type casting everywhere [see here](https://github.com/go-playground/lars/blob/master/examples/custom-handler/main.go)
22+
- [x] Full support for standard/native http Handler + HandlerFunc + some others [see here](https://github.com/go-playground/lars/blob/master/examples/native/main.go)
2523
* When Parsing a form call Context's ParseForm amd ParseMulipartForm functions and the URL params will be added into the Form object, just like query parameters are, so no extra work
26-
- [x] lars uses a custom version of [httprouter](https://github.com/julienschmidt/httprouter)
24+
- [x] lars uses a custom version of [httprouter](https://github.com/julienschmidt/httprouter) so incredibly fast and efficient.
2725

2826

2927
**Note:** Since this router has only explicit matches, you can not register static routes and parameters for the same path segment. For example you can not register the patterns /user/new and /user/:user for the same request method at the same time. The routing of different request methods is independent from each other. I was initially against this, and this router allowed it in a previous version, however it nearly cost me in a big app where the dynamic param value say :type actually could have matched another static route and that's just too dangerous, so it is no longer allowed.
@@ -35,248 +33,34 @@ Use go get
3533

3634
```go
3735
go get github.com/go-playground/lars
38-
```
39-
40-
or to update
41-
42-
```go
43-
go get -u github.com/go-playground/lars
44-
```
45-
46-
Then import lars package into your code.
47-
48-
```go
49-
import "github.com/go-playground/lars"
50-
```
36+
```
5137

5238
Usage
5339
------
54-
Below is a full example, for a simpler example [see here](https://github.com/go-playground/lars/blob/master/examples/groups/main.go)
40+
Below is a simple example, for a full example [see here](https://github.com/go-playground/lars/blob/master/examples/all-in-one/main.go)
5541
```go
5642
package main
5743

5844
import (
59-
"log"
6045
"net/http"
61-
"os"
62-
"time"
6346

6447
"github.com/go-playground/lars"
48+
mw "github.com/go-playground/lars/examples/middleware/logging-recovery"
6549
)
6650

67-
// This is a contrived example of how I would use in production
68-
// I would break things into separate files but all here for simplicity
69-
70-
// ApplicationGlobals houses all the application info for use.
71-
type ApplicationGlobals struct {
72-
// DB - some database connection
73-
Log *log.Logger
74-
// Translator - some i18n translator
75-
// JSON - encoder/decoder
76-
// Schema - gorilla schema
77-
// .......
78-
}
79-
80-
// Reset gets called just before a new HTTP request starts calling
81-
// middleware + handlers
82-
func (g *ApplicationGlobals) Reset() {
83-
// DB = new database connection or reset....
84-
//
85-
// We don't touch translator + log as they don't change per request
86-
}
87-
88-
// Done gets called after the HTTP request has completed right before
89-
// Context gets put back into the pool
90-
func (g *ApplicationGlobals) Done() {
91-
// DB.Close()
92-
}
93-
94-
func newGlobals() *ApplicationGlobals {
95-
96-
logger := log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
97-
// translator := ...
98-
// db := ... base db connection or info
99-
// json := ...
100-
// schema := ...
101-
102-
return &ApplicationGlobals{
103-
Log: logger,
104-
// Translator: translator,
105-
// DB: db,
106-
// JSON: json,
107-
// schema:schema,
108-
}
109-
}
110-
111-
// MyContext is a custom context
112-
type MyContext struct {
113-
*lars.Ctx // a little dash of Duck Typing....
114-
AppContext *ApplicationGlobals
115-
}
116-
117-
// RequestStart overriding
118-
func (mc *MyContext) RequestStart(w http.ResponseWriter, r *http.Request) {
119-
120-
// call lars context reset, must be done
121-
mc.Ctx.RequestStart(w, r)
122-
mc.AppContext.Reset()
123-
}
124-
125-
// RequestEnd overriding
126-
func (mc *MyContext) RequestEnd() {
127-
mc.AppContext.Done()
128-
mc.Ctx.RequestEnd()
129-
}
130-
131-
func newContext(l *lars.LARS) lars.Context {
132-
return &MyContext{
133-
Ctx: lars.NewContext(l),
134-
AppContext: newGlobals(),
135-
}
136-
}
137-
138-
func castCustomContext(c lars.Context, handler lars.Handler) {
139-
140-
// could do it in all one statement, but in long form for readability
141-
h := handler.(func(*MyContext))
142-
ctx := c.(*MyContext)
143-
144-
h(ctx)
145-
}
146-
14751
func main() {
14852

14953
l := lars.New()
150-
l.RegisterContext(newContext) // all gets cached in pools for you
151-
l.RegisterCustomHandler(func(*MyContext) {}, castCustomContext)
152-
l.Use(Logger)
153-
154-
l.Get("/", Home)
155-
156-
users := l.Group("/users")
157-
users.Get("", Users)
158-
159-
// you can break it up however you with, just demonstrating that you can
160-
// have groups of group
161-
user := users.Group("/:id")
162-
user.Get("", User)
163-
user.Get("/profile", UserProfile)
164-
165-
http.ListenAndServe(":3007", l.Serve())
166-
}
167-
168-
// Home ...
169-
func Home(c *MyContext) {
170-
171-
var username string
172-
173-
// username = c.AppContext.DB.find(user by .....)
174-
175-
c.AppContext.Log.Println("Found User")
176-
177-
c.Response().Write([]byte("Welcome Home " + username))
178-
}
179-
180-
// Users ...
181-
func Users(c *MyContext) {
182-
183-
c.AppContext.Log.Println("In Users Function")
184-
185-
c.Response().Write([]byte("Users"))
186-
}
187-
188-
// User ...
189-
func User(c *MyContext) {
190-
191-
id := c.Param("id")
192-
193-
var username string
194-
195-
// username = c.AppContext.DB.find(user by id.....)
196-
197-
c.AppContext.Log.Println("Found User")
198-
199-
c.Response().Write([]byte("Welcome " + username + " with id " + id))
200-
}
201-
202-
// UserProfile ...
203-
func UserProfile(c *MyContext) {
204-
205-
id := c.Param("id")
206-
207-
var profile string
208-
209-
// profile = c.AppContext.DB.find(user profile by .....)
210-
211-
c.AppContext.Log.Println("Found User Profile")
212-
213-
c.Response().Write([]byte("Here's your profile " + profile + " user " + id))
214-
}
215-
216-
// Logger ...
217-
func Logger(c lars.Context) {
218-
219-
start := time.Now()
220-
221-
c.Next()
222-
223-
stop := time.Now()
224-
path := c.Request().URL.Path
225-
226-
if path == "" {
227-
path = "/"
228-
}
229-
230-
log.Printf("%s %d %s %s", c.Request().Method, c.Response().Status(), path, stop.Sub(start))
231-
}
232-
```
233-
234-
Native Handler Support
235-
```go
236-
package main
237-
238-
import (
239-
"log"
240-
"net/http"
241-
"time"
242-
243-
"github.com/go-playground/lars"
244-
)
245-
246-
func main() {
247-
248-
l := lars.New()
249-
l.Use(Logger)
54+
l.Use(mw.LoggingAndRecovery) // LoggingAndRecovery is just an example copy paste and modify to your needs
25055

25156
l.Get("/", HelloWorld)
25257

25358
http.ListenAndServe(":3007", l.Serve())
25459
}
25560

25661
// HelloWorld ...
257-
func HelloWorld(w http.ResponseWriter, r *http.Request) {
258-
259-
// lars's context! get it and ROCK ON!
260-
ctx := lars.GetContext(w)
261-
262-
ctx.Response().Write([]byte("Hello World"))
263-
}
264-
265-
// Logger ...
266-
func Logger(c lars.Context) {
267-
268-
start := time.Now()
269-
270-
c.Next()
271-
272-
stop := time.Now()
273-
path := c.Request().URL.Path
274-
275-
if path == "" {
276-
path = "/"
277-
}
278-
279-
log.Printf("%s %d %s %s", c.Request().Method, c.Response().Status(), path, stop.Sub(start))
62+
func HelloWorld(c lars.Context) {
63+
c.Response().Write([]byte("Hello World"))
28064
}
28165
```
28266

examples/all-in-one/main.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,15 @@ type MyContext struct {
6363
func (mc *MyContext) RequestStart(w http.ResponseWriter, r *http.Request) {
6464

6565
// call lars context reset, must be done
66-
mc.Ctx.RequestStart(w, r)
66+
67+
mc.Ctx.RequestStart(w, r) // MUST be called!
6768
mc.AppContext.Reset()
6869
}
6970

7071
// RequestEnd overriding
7172
func (mc *MyContext) RequestEnd() {
7273
mc.AppContext.Done()
73-
mc.Ctx.RequestEnd()
74+
mc.Ctx.RequestEnd() // MUST be called!
7475
}
7576

7677
func newContext(l *lars.LARS) lars.Context {

examples/hello-world/main.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package main
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/go-playground/lars"
7+
mw "github.com/go-playground/lars/examples/middleware/logging-recovery"
8+
)
9+
10+
func main() {
11+
12+
l := lars.New()
13+
l.Use(mw.LoggingAndRecovery) // LoggingAndRecovery is just an example copy paste and modify to your needs
14+
15+
l.Get("/", HelloWorld)
16+
17+
http.ListenAndServe(":3007", l.Serve())
18+
}
19+
20+
// HelloWorld ...
21+
func HelloWorld(c lars.Context) {
22+
c.Response().Write([]byte("Hello World"))
23+
}

0 commit comments

Comments
 (0)