{"id":19292397,"url":"https://github.com/foolin/tigo","last_synced_at":"2025-10-14T17:00:20.553Z","repository":{"id":57484477,"uuid":"70313933","full_name":"foolin/tigo","owner":"foolin","description":"Tigo is a lightweight high performance HTTP request router, fast and powerful routing features for the high-performance.","archived":false,"fork":false,"pushed_at":"2020-08-19T13:04:46.000Z","size":80,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-06T15:53:14.039Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/foolin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-10-08T07:47:03.000Z","updated_at":"2019-01-07T05:45:36.000Z","dependencies_parsed_at":"2022-08-26T14:24:13.808Z","dependency_job_id":null,"html_url":"https://github.com/foolin/tigo","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foolin%2Ftigo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foolin%2Ftigo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foolin%2Ftigo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foolin%2Ftigo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/foolin","download_url":"https://codeload.github.com/foolin/tigo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240395976,"owners_count":19794617,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T22:30:36.477Z","updated_at":"2025-10-14T17:00:15.514Z","avatar_url":"https://github.com/foolin.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tigo\n\n\n[![GoDoc](https://godoc.org/github.com/foolin/tigo?status.png)](https://godoc.org/github.com/foolin/tigo)\n\n## Description\n\nTigo is a tiny framework for go, is forked from [ozzo-routing](https://github.com/go-ozzo/ozzo-routing) which is a lightweight high performance HTTP request router, fast and powerful routing features for the high-performance.\nThe package has the following features:\n\n* middleware pipeline architecture, similar to that of the [Express framework](http://expressjs.com).\n* extremely fast request routing with zero dynamic memory allocation\n* modular code organization through route grouping\n* flexible URL path matching, supporting URL parameters and regular expressions\n* URL creation according to the predefined routes\n\nThis fork adds the following features:\n* add OnError handdler for panic.\n* add render function for view(use html/template)\n* add panic middleware\n* add logger middleware\n* add static middleware\n* add more router functions.\n\n## Requirements\n\nGo 1.7 or above.\n\n## Installation\n\nRun the following command to install the package:\n\n```\ngo get gopkg.in/foolin/tigo.v2\n```\n\nOr last version(developer):\n```\ngo get github.com/foolin/tigo\n```\n\n## Getting Started\n\n#### Default example:\n```go\n\npackage main\n\nimport (\n\t\"github.com/foolin/tigo\"\n\t\"log\"\n)\n\nfunc main()  {\n\n\trouter := tigo.Default()\n\n\trouter.GET(\"/\", func(ctx *tigo.Context) error {\n\t\t//out html\n\t\treturn ctx.HTML(`\n\t\t\tHello tigo!!!\u003chr\u003e\n\t\t\tvisit api: \u003ca href=\"/api/tigo\"\u003eapi/tigo\u003c/a\u003e\n\t\t`)\n\t})\n\n\trouter.GET(\"/api/\u003caction\u003e\", func(ctx *tigo.Context) error {\n\t\t//out json\n\t\treturn ctx.JSON(tigo.M{\n\t\t\t\"name\": \"tigo\",\n\t\t\t\"ip\": ctx.RequestIP(),\n\t\t\t\"action\": ctx.Param(\"action\"),\n\t\t})\n\t})\n\n\t//run\n\tlog.Printf(\"run on :8080\")\n\terr := router.Run(\":8080\")\n\tif err != nil {\n\t\tlog.Fatalf(\"run error: %v\", err)\n\t}\n}\n\t\n```\n\n\n#### New example:\n```go\n\npackage main\n\nimport (\n\t\"github.com/foolin/tigo\"\n\t\"os\"\n\t\"log\"\n)\n\nfunc main()  {\n\t//new router\n\trouter := tigo.New()\n\n\t//logger\n\trouter.Use(tigo.Logger(os.Stdout))\n\n\t//panic\n\trouter.Use(tigo.Panic(os.Stderr))\n\n\t//register router\n\trouter.GET(\"/\", func(ctx *tigo.Context) error {\n\t\treturn ctx.HTML(\"Hello tigo!!!\")\n\t})\n\n\t//run\n\tlog.Printf(\"run on :8080\")\n\terr := router.Run(\":8080\")\n\tif err != nil {\n\t\tlog.Fatalf(\"run error: %v\", err)\n\t}\n}\n\n```\n\n\n#### Render example:\n\nUse context.Render()\n\n```go\n\npackage main\n\nimport (\n\t\"github.com/foolin/tigo\"\n\t\"log\"\n\t\"html/template\"\n)\n\nfunc main() {\n\n\t//new router\n\trouter := tigo.New()\n\n\t//set render, tigo.Default() will default initialize.\n\trouter.Render = tigo.NewViewRender(tigo.ViewRenderConfig{\n\t\tRoot: \"views\",\n\t\tExtension: \".html\",\n\t\tMaster: \"layout/master\",\n\t\tPartials: []string{\"layout/footer\"},\n\t\tFuncs: template.FuncMap{\n\t\t\t\"echo\": func(content string) template.HTML {\n\t\t\t\treturn template.HTML(content)\n\t\t\t},\n\t\t},\n\t\tDisableCache: false,\n\t\tDisableFilePartial: false,\n\t})\n\n\t//register router\n\trouter.GET(\"/\", func(ctx *tigo.Context) error {\n\t\treturn ctx.Render(\"index\", tigo.M{\n\t\t\t\"title\": \"Index title!\",\n\t\t\t\"escape\": func(content string) string {\n\t\t\t\treturn template.HTMLEscapeString(content)\n\t\t\t},\n\t\t})\n\t})\n\n\trouter.GET(\"/page_file\", func(ctx *tigo.Context) error {\n\t\treturn ctx.RenderFile(\"page_file\", tigo.M{\"title\": \"Page file title!!\"})\n\t})\n\n\t//run\n\tlog.Printf(\"run on :8080\")\n\terr := router.Run(\":8080\")\n\tif err != nil {\n\t\tlog.Fatalf(\"run error: %v\", err)\n\t}\n}\n\t\n```\n\n\n/views/layout/master.html\n```html\n    \u003c!-- /views/admin/master.html --\u003e\n    \n    \u003c!doctype html\u003e\n    \n    \u003chtml\u003e\n    \u003chead\u003e\n        \u003cmeta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" /\u003e\n        \u003cmeta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" /\u003e\n        \u003ctitle\u003e{{.title}}\u003c/title\u003e\n        {{template \"head\" .}}\n    \u003c/head\u003e\n    \n    \u003cbody\u003e\n    admin/master.html\n    \n    \u003chr\u003e\n    render page content will at here:\n    {{template \"content\" .}}\n    \n    {{include \"layout/footer\"}}\n    \u003c/body\u003e\n    \u003c/html\u003e\n        \n```\n\n/views/layout/footer.html\n```html\n    \u003c!-- /views/layout/footer.html --\u003e\n    Copyright \u0026copy2016 by \u003ca href=\"https://github.com/foolin/tigo\"\u003etigo\u003c/a\u003e.\n```\n\n/views/index.html\n```html\n    {{define \"head\"}}\n        \u003cstyle\u003e\n            .hello{ color: red;}\n            hr{ border: 1px #ccc dashed;}\n        \u003c/style\u003e\n    {{end}}\n    \n    \n    {{define \"content\"}}\n        \u003ch1 class=\"hello\"\u003eThis is content!!!!\u003c/h1\u003e\n        {{echo `\u003c!-- echo function out, you can see it at source! --\u003e`}}\n        {{call $.escape `\u003c!-- Hello world--\u003e`}}\n        \u003chr\u003e\n        \u003cp\u003e\u003ca href=\"/page_file\"\u003epage file\u003c/a\u003e\u003c/p\u003e\n    {{end}}\n```\n\n/views/page_file.html\n```html\n    \u003c!-- /views/page_file.html --\u003e\n    \u003c!doctype html\u003e\n    \n    \u003chtml\u003e\n    \u003chead\u003e\n        \u003cmeta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" /\u003e\n        \u003cmeta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" /\u003e\n        \u003ctitle\u003e{{.title}}\u003c/title\u003e\n    \u003c/head\u003e\n    \n    \u003cbody\u003e\n    \u003ca href=\"/\"\u003e\u003c- Back home!\u003c/a\u003e\n    \u003chr\u003e\n    \n    page.html\n    {{include \"layout/footer\"}}\n    \u003c/body\u003e\n    \u003c/html\u003e\n```\n\n\n\nNow run the following command to start the Web server:\n\n```\ngo run main.go\n```\n\nYou should be able to access URLs such as `http://localhost:8080`.\n\n\n### Routes\n\ntigo works by building a routing table in a router and then dispatching HTTP requests to the matching handlers \nfound in the routing table. An intuitive illustration of a routing table is as follows:\n\n\nRoutes              |  Handlers\n--------------------|-----------------\n`GET /users`        |  m1, m2, h1, ...\n`POST /users`       |  m1, m2, h2, ...\n`PUT /users/\u003cid\u003e`   |  m1, m2, h3, ...\n`DELETE /users/\u003cid\u003e`|  m1, m2, h4, ...\n\n\nFor an incoming request `GET /users`, the first route would match and the handlers m1, m2, and h1 would be executed.\nIf the request is `PUT /users/123`, the third route would match and the corresponding handlers would be executed.\nNote that the token `\u003cid\u003e` can match any number of non-slash characters and the matching part can be accessed as \na path parameter value in the handlers.\n\n**If an incoming request matches multiple routes in the table, the route added first to the table will take precedence.\nAll other matching routes will be ignored.**\n\nThe actual implementation of the routing table uses a variant of the radix tree data structure, which makes the routing\nprocess as fast as working with a hash table, thanks to the inspiration from [httprouter](https://github.com/julienschmidt/httprouter).\n\nTo add a new route and its handlers to the routing table, call the `To` method like the following:\n  \n```go\nrouter := tigo.New()\nrouter.To(\"GET\", \"/users\", m1, m2, h1)\nrouter.To(\"POST\", \"/users\", m1, m2, h2)\n```\n\nYou can also use shortcut methods, such as `Get`, `Post`, `Put`, etc., which are named after the HTTP method names:\n \n```go\nrouter.Get(\"/users\", m1, m2, h1)\nrouter.Post(\"/users\", m1, m2, h2)\n```\n\nIf you have multiple routes with the same URL path but different HTTP methods, like the above example, you can \nchain them together as follows,\n\n```go\nrouter.Get(\"/users\", m1, m2, h1).Post(m1, m2, h2)\n```\n\nIf you want to use the same set of handlers to handle the same URL path but different HTTP methods, you can take\nthe following shortcut:\n\n```go\nrouter.To(\"GET,POST\", \"/users\", m1, m2, h)\n```\n\nA route may contain parameter tokens which are in the format of `\u003cname:pattern\u003e`, where `name` stands for the parameter\nname, and `pattern` is a regular expression which the parameter value should match. A token `\u003cname\u003e` is equivalent\nto `\u003cname:[^/]*\u003e`, i.e., it matches any number of non-slash characters. At the end of a route, an asterisk character\ncan be used to match any number of arbitrary characters. Below are some examples:\n\n* `/users/\u003cusername\u003e`: matches `/users/admin`\n* `/users/accnt-\u003cid:\\d+\u003e`: matches `/users/accnt-123`, but not `/users/accnt-admin`\n* `/users/api\u003cid:.*\u003e`: matches `/users/api-abc`, `/users/api/list/page/1`\n* `/users/\u003cusername\u003e/*`: matches `/users/admin/profile/address`\n\nWhen a URL path matches a route, the matching parameters on the URL path can be accessed via `Context.Param()`:\n\n```go\nrouter := tigo.New()\n\nrouter.Get(\"/users/\u003cusername\u003e\", func (c *tigo.Context) error {\n\tfmt.Fprintf(c, \"Name: %v\", c.Param(\"username\"))\n\treturn nil\n})\n```\n\n\n### Route Groups\n\nRoute group is a way of grouping together the routes which have the same route prefix. The routes in a group also\nshare the same handlers that are registered with the group via its `Use` method. For example,\n\n```go\nrouter := tigo.New()\napi := router.Group(\"/api\")\napi.Use(m1, m2)\napi.Get(\"/users\", h1).Post(h2)\napi.Put(\"/users/\u003cid\u003e\", h3).Delete(h4)\n```\n\nThe above `/api` route group establishes the following tigo table:\n\n\nRoutes                  |  Handlers\n------------------------|-------------\n`GET /api/users`        |  m1, m2, h1, ...\n`POST /api/users`       |  m1, m2, h2, ...\n`PUT /api/users/\u003cid\u003e`   |  m1, m2, h3, ...\n`DELETE /api/users/\u003cid\u003e`|  m1, m2, h4, ...\n\n\nAs you can see, all these routes have the same route prefix `/api` and the handlers `m1` and `m2`. In other similar\ntigo frameworks, the handlers registered with a route group are also called *middlewares*.\n\nRoute groups can be nested. That is, a route group can create a child group by calling the `Group()` method. The router\nserves as the top level route group. A child group inherits the handlers registered with its parent group. For example, \n\n```go\nrouter := tigo.New()\nrouter.Use(m1)\n\napi := router.Group(\"/api\")\napi.Use(m2)\n\nusers := group.Group(\"/users\")\nusers.Use(m3)\nusers.Put(\"/\u003cid\u003e\", h1)\n```\n\nBecause the router serves as the parent of the `api` group which is the parent of the `users` group, \nthe `PUT /api/users/\u003cid\u003e` route is associated with the handlers `m1`, `m2`, `m3`, and `h1`.\n\n\n### Router\n\nRouter manages the tigo table and dispatches incoming requests to appropriate handlers. A router instance is created\nby calling the `tigo.New()` method.\n\nTo hook up router with fasthttp, use the following code:\n\n```go\nrouter := tigo.New()\nfasthttp.ListenAndServe(\":8080\", router.HandleRequest) \n```\n\n\n### Handlers\n\nA handler is a function with the signature `func(*tigo.Context) error`. A handler is executed by the router if\nthe incoming request URL path matches the route that the handler is associated with. Through the `tigo.Context` \nparameter, you can access the request information in handlers.\n\nA route may be associated with multiple handlers. These handlers will be executed in the order that they are registered\nto the route. The execution sequence can be terminated in the middle using one of the following two methods:\n\n* A handler returns an error: the router will skip the rest of the handlers and handle the returned error.\n* A handler calls `Context.Abort()`: the router will simply skip the rest of the handlers. There is no error to be handled.\n \nA handler can call `Context.Next()` to explicitly execute the rest of the unexecuted handlers and take actions after\nthey finish execution. For example, a response compression handler may start the output buffer, call `Context.Next()`,\nand then compress and send the output to response.\n\n\n### Context\n\nFor each incoming request, a `tigo.Context` object is passed through the relevant handlers. Because `tigo.Context`\nembeds `fasthttp.RequestCtx`, you can access all properties and methods provided by the latter.\n \nAdditionally, the `Context.Param()` method allows handlers to access the URL path parameters that match the current route.\nUsing `Context.Get()` and `Context.Set()`, handlers can share data between each other. For example, an authentication\nhandler can store the authenticated user identity by calling `Context.Set()`, and other handlers can retrieve back\nthe identity information by calling `Context.Get()`.\n\nContext also provides a handy `WriteData()` method that can be used to write data of arbitrary type to the response.\nThe `WriteData()` method can also be overridden (by replacement) to achieve more versatile response data writing. \n\n\n### Error Handling\n\nA handler may return an error indicating some erroneous condition. Sometimes, a handler or the code it calls may cause\na panic. Both should be handled properly to ensure best user experience. It is recommended that you use \nthe `fault.Recover` handler or a similar error handler to handle these errors.\n\nIf an error is not handled by any handler, the router will handle it by calling its `handleError()` method which\nsimply sets an appropriate HTTP status code and writes the error message to the response.\n\nWhen an incoming request has no matching route, the router will call the handlers registered via the `Router.NotFound()`\nmethod. All the handlers registered via `Router.Use()` will also be called in advance. By default, the following two\nhandlers are registered with `Router.NotFound()`:\n\n* `tigo.MethodNotAllowedHandler`: a handler that sends an `Allow` HTTP header indicating the allowed HTTP methods for a requested URL\n* `tigo.NotFoundHandler`: a handler triggering 404 HTTP error\n\n\n## Version\n\n!!! Important, current is v2, v1 is fork Fasthttp-routing, but v2 is fork ozzo-routing.\nif you use v1 version, please use this:\n```\ngo get gopkg.in/foolin/tigo.v1\n```\n\n## Docs\n\nSee http://godoc.org/github.com/foolin/tigo .\n\n## Links\n\n* [tigo-admin: admin template demo with tigo](https://github.com/foolin/tigo-admin \"Tigo admin\")\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoolin%2Ftigo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffoolin%2Ftigo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoolin%2Ftigo/lists"}