diff --git a/README.md b/README.md index e0c5e59..e6143c3 100755 --- a/README.md +++ b/README.md @@ -21,217 +21,4 @@ go get amuz.es/src/go/logging ``` ## Getting Started - -Create a `server.go` file with the following content: - -```go -package main - -import ( - "fmt" - - "github.com/qiangxue/fasthttp-routing" - "github.com/valyala/fasthttp" -) - -func main() { - router := routing.New() - - router.Get("/", func(c *routing.Context) error { - fmt.Fprintf(c, "Hello, world!") - return nil - }) - - panic(fasthttp.ListenAndServe(":8080", router.HandleRequest)) -} -``` - -Now run the following command to start the Web server: - -``` -go run server.go -``` - -You should be able to access URLs such as `http://localhost:8080`. - - -### Routes - -ozzo-routing works by building a routing table in a router and then dispatching HTTP requests to the matching handlers -found in the routing table. An intuitive illustration of a routing table is as follows: - - -Routes | Handlers ---------------------|----------------- -`GET /users` | m1, m2, h1, ... -`POST /users` | m1, m2, h2, ... -`PUT /users/` | m1, m2, h3, ... -`DELETE /users/`| m1, m2, h4, ... - - -For an incoming request `GET /users`, the first route would match and the handlers m1, m2, and h1 would be executed. -If the request is `PUT /users/123`, the third route would match and the corresponding handlers would be executed. -Note that the token `` can match any number of non-slash characters and the matching part can be accessed as -a path parameter value in the handlers. - -**If an incoming request matches multiple routes in the table, the route added first to the table will take precedence. -All other matching routes will be ignored.** - -The actual implementation of the routing table uses a variant of the radix tree data structure, which makes the routing -process as fast as working with a hash table, thanks to the inspiration from [httprouter](https://github.com/julienschmidt/httprouter). - -To add a new route and its handlers to the routing table, call the `To` method like the following: - -```go -router := routing.New() -router.To("GET", "/users", m1, m2, h1) -router.To("POST", "/users", m1, m2, h2) -``` - -You can also use shortcut methods, such as `Get`, `Post`, `Put`, etc., which are named after the HTTP method names: - -```go -router.Get("/users", m1, m2, h1) -router.Post("/users", m1, m2, h2) -``` - -If you have multiple routes with the same URL path but different HTTP methods, like the above example, you can -chain them together as follows, - -```go -router.Get("/users", m1, m2, h1).Post(m1, m2, h2) -``` - -If you want to use the same set of handlers to handle the same URL path but different HTTP methods, you can take -the following shortcut: - -```go -router.To("GET,POST", "/users", m1, m2, h) -``` - -A route may contain parameter tokens which are in the format of ``, where `name` stands for the parameter -name, and `pattern` is a regular expression which the parameter value should match. A token `` is equivalent -to ``, i.e., it matches any number of non-slash characters. At the end of a route, an asterisk character -can be used to match any number of arbitrary characters. Below are some examples: - -* `/users/`: matches `/users/admin` -* `/users/accnt-`: matches `/users/accnt-123`, but not `/users/accnt-admin` -* `/users//*`: matches `/users/admin/profile/address` - -When a URL path matches a route, the matching parameters on the URL path can be accessed via `Context.Param()`: - -```go -router := routing.New() - -router.Get("/users/", func (c *routing.Context) error { - fmt.Fprintf(c, "Name: %v", c.Param("username")) - return nil -}) -``` - - -### Route Groups - -Route group is a way of grouping together the routes which have the same route prefix. The routes in a group also -share the same handlers that are registered with the group via its `Use` method. For example, - -```go -router := routing.New() -api := router.Group("/api") -api.Use(m1, m2) -api.Get("/users", h1).Post(h2) -api.Put("/users/", h3).Delete(h4) -``` - -The above `/api` route group establishes the following routing table: - - -Routes | Handlers -------------------------|------------- -`GET /api/users` | m1, m2, h1, ... -`POST /api/users` | m1, m2, h2, ... -`PUT /api/users/` | m1, m2, h3, ... -`DELETE /api/users/`| m1, m2, h4, ... - - -As you can see, all these routes have the same route prefix `/api` and the handlers `m1` and `m2`. In other similar -routing frameworks, the handlers registered with a route group are also called *middlewares*. - -Route groups can be nested. That is, a route group can create a child group by calling the `Group()` method. The router -serves as the top level route group. A child group inherits the handlers registered with its parent group. For example, - -```go -router := routing.New() -router.Use(m1) - -api := router.Group("/api") -api.Use(m2) - -users := group.Group("/users") -users.Use(m3) -users.Put("/", h1) -``` - -Because the router serves as the parent of the `api` group which is the parent of the `users` group, -the `PUT /api/users/` route is associated with the handlers `m1`, `m2`, `m3`, and `h1`. - - -### Router - -Router manages the routing table and dispatches incoming requests to appropriate handlers. A router instance is created -by calling the `routing.New()` method. - -To hook up router with fasthttp, use the following code: - -```go -router := routing.New() -fasthttp.ListenAndServe(":8080", router.HandleRequest) -``` - - -### Handlers - -A handler is a function with the signature `func(*routing.Context) error`. A handler is executed by the router if -the incoming request URL path matches the route that the handler is associated with. Through the `routing.Context` -parameter, you can access the request information in handlers. - -A route may be associated with multiple handlers. These handlers will be executed in the order that they are registered -to the route. The execution sequence can be terminated in the middle using one of the following two methods: - -* A handler returns an error: the router will skip the rest of the handlers and handle the returned error. -* A handler calls `Context.Abort()`: the router will simply skip the rest of the handlers. There is no error to be handled. - -A handler can call `Context.Next()` to explicitly execute the rest of the unexecuted handlers and take actions after -they finish execution. For example, a response compression handler may start the output buffer, call `Context.Next()`, -and then compress and send the output to response. - - -### Context - -For each incoming request, a `routing.Context` object is passed through the relevant handlers. Because `routing.Context` -embeds `fasthttp.RequestCtx`, you can access all properties and methods provided by the latter. - -Additionally, the `Context.Param()` method allows handlers to access the URL path parameters that match the current route. -Using `Context.Get()` and `Context.Set()`, handlers can share data between each other. For example, an authentication -handler can store the authenticated user identity by calling `Context.Set()`, and other handlers can retrieve back -the identity information by calling `Context.Get()`. - -Context also provides a handy `WriteData()` method that can be used to write data of arbitrary type to the response. -The `WriteData()` method can also be overridden (by replacement) to achieve more versatile response data writing. - - -### Error Handling - -A handler may return an error indicating some erroneous condition. Sometimes, a handler or the code it calls may cause -a panic. Both should be handled properly to ensure best user experience. It is recommended that you use -the `fault.Recover` handler or a similar error handler to handle these errors. - -If an error is not handled by any handler, the router will handle it by calling its `handleError()` method which -simply sets an appropriate HTTP status code and writes the error message to the response. - -When an incoming request has no matching route, the router will call the handlers registered via the `Router.NotFound()` -method. All the handlers registered via `Router.Use()` will also be called in advance. By default, the following two -handlers are registered with `Router.NotFound()`: - -* `routing.MethodNotAllowedHandler`: a handler that sends an `Allow` HTTP header indicating the allowed HTTP methods for a requested URL -* `routing.NotFoundHandler`: a handler triggering 404 HTTP error +TBD