📬Routing
First impression from the framework. Just act cool
The list of methods cannot be extended
Interface
The inbuilt
router is instantiated easily using the inbuilt.New()
function. It implements the router.Builder
interface, which should be used when abstracting a router, as the application instance receives it.
Registering routes
There's a single general way to register a handler:
r.Route(method.GET, "/", myHandler, middlewares...)
However, this isn't that much handy in daily life. Therefore, a few shortcuts are available:
r.Get("/user", getUser)
r.Post("/user", createUser)
r.Put("/user", updateUser)
r.Delete("/user", deleteUser)
The full list of supported methods (and thereby shortcuts):
GET
HEAD
POST
PUT
DELETE
CONNECT
OPTIONS
TRACE
PATCH
The example above could be made even shorter using the Resource
feature:
r.Resource("user").
Get(getUser).
Post(createUser).
Put(updateUser).
Delete(deleteUser)
But how do we identify the user we want to get a look at, create, update or delete? User ID is implied to be passed somehow via either path parameters, headers or request body (as JSON or form data, probably). However, we could state it explicitly using dynamic routing:
r.Get("/user/{id}", getUser)
r.Post("/user/{id}", createUser)
r.Put("/user/{id}", updateUser)
r.Delete("/user/{id}", deleteUser)
Dynamic path consists of wildcards encased by curly braces. Important that a wildcard must be a whole path segment, i.e. from slash to slash (unless stays at the end.) The following example panics at application startup:
r.Get("/user/id{id}", getUser)
Wildcard values
// r.Get("/user/{id}", getUser)
func getUser(req *http.Request) *http.Response {
// request.Vars holds all the wildcards.
// It shares the same structure as headers or params
// do, thereby the identical set of methods is available.
id := req.Vars.Value("id")
userModel := getUserByID(id) // some ephemeral function
return http.JSON(req, userModel)
}
Middlewares
Middlewares can be applied either globally or locally. Globally-applied middleware is group-wide, therefore it'll be applied on each handler defined inside the group (and on handlers of all the subgroups). Locally-applied are middlewares, which are applied on specific handlers exclusively.
All middlewares are called in strict order of their registration (call chain can be represented as a FIFO queue). Globally-applied middlewares are called strictly before locally-applied ones.
Global middleware can be defined using Use()
method:
// import "github.com/indigo-web/indigo/router/inbuilt/middleware"
r.Use(middleware.Recover)
Meanwhile, locally-applied can be added in the following manner:
r.Get("/", myHandler, middleware.Recover, middleware.HTTPSOnly)
Groups
Groups are basically sub-routers. Each group is a dedicated router instance, that implicitly registers itself in the parent router. As an application starts, all the groups will be merged into one big router, but this is well-hidden from a user.
All the route paths are concatenated with the group's name. Nested groups are holding parent's prefix plus their own.
r.Group(prefix string)
Resources
Resources allows you to easily set multiple methods on the same location.
r.Resource("/").
Get(indexGet).
Post(indexPost).
Patch(indexPatch)
Resources are supporting everything groups do. This includes:
Static content distribution
Middlewares (resource-wide and locally-applied)
Path catchers
Static content distribution
Static content distribution maps static directory contents to requests' paths and uploads files automatically. MIME types are derived automatically, too, however it may be missing heuristics. Unlike net/http
, MIME isn't guessed via first bytes of data.
r.Static("/static", "./static_dir")
The first argument corresponds to the prefix, by which static files are accessible. The second corresponds to the directory to the static files, respectively. Subdirectories are working, too.
Implicit redirection
Implicit redirection replaces the request's path before the actual routing starts. This may be useful, for example, in order to redirect /favicon.ico
to /static/favicon.ico
r.Alias("/favicon.ico", "/static/favicon.ico")
Routing errors
Custom error handlers can be set via the following method:
r.RouteError(ordinaryHandler, status.NotFound, status.MethodNotAllowed)
Here, we set the ordinaryHandler
to handle all the status.NotFound
and status.MethodNotAllowed
errors. By default, a response with only a code is returned, letting a user-agent to draw an error-page manually. By setting custom error handler, you can return custom error pages. In order to set the handler handle ALL the errors, just make it process inbuilt.AllErrors
error:
r.RouteError(ordinaryHandler, status.AllErrors)
Original error object is stored in request.Env.Error
:
return http.Error(request, request.Env.Error)
Path catchers
Path catchers are ordinary handlers, which are called if no other handler was picked.
r.Catch("/static/", staticHandler, middlewares...)
In this example, all requests with path starting with /static/
will be passed into the staticHandler
. Trailing slash may be avoided, but then paths like /staticky
will also satisfy the condition.
Last updated