{"id":20554910,"url":"https://github.com/night-codes/tokay","last_synced_at":"2025-08-30T12:15:44.264Z","repository":{"id":57511370,"uuid":"107032943","full_name":"night-codes/tokay","owner":"night-codes","description":"Fast and small (but powerful) fasthttp web framework written on Go (Golang)","archived":false,"fork":false,"pushed_at":"2023-01-13T02:39:58.000Z","size":71,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-06T06:33:28.756Z","etag":null,"topics":["fasthttp","fasthttprouter","framework","gin","go","golang","router","server","tokay","web"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/night-codes.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":"2017-10-15T17:20:43.000Z","updated_at":"2022-08-01T09:05:17.000Z","dependencies_parsed_at":"2023-02-09T14:16:04.430Z","dependency_job_id":null,"html_url":"https://github.com/night-codes/tokay","commit_stats":null,"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"purl":"pkg:github/night-codes/tokay","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/night-codes%2Ftokay","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/night-codes%2Ftokay/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/night-codes%2Ftokay/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/night-codes%2Ftokay/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/night-codes","download_url":"https://codeload.github.com/night-codes/tokay/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/night-codes%2Ftokay/sbom","scorecard":{"id":686674,"data":{"date":"2025-08-11","repo":{"name":"github.com/night-codes/tokay","commit":"90dc3958328ea3c4fcfe17170151ff0ed16f857b"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.2,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Code-Review","score":1,"reason":"Found 3/25 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: BSD 3-Clause \"New\" or \"Revised\" License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 8 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T01:05:53.356Z","repository_id":57511370,"created_at":"2025-08-22T01:05:53.357Z","updated_at":"2025-08-22T01:05:53.357Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272847291,"owners_count":25003165,"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","status":"online","status_checked_at":"2025-08-30T02:00:09.474Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["fasthttp","fasthttprouter","framework","gin","go","golang","router","server","tokay","web"],"created_at":"2024-11-16T03:14:25.343Z","updated_at":"2025-08-30T12:15:44.249Z","avatar_url":"https://github.com/night-codes.png","language":"Go","readme":"![Tokay](https://cdn.rawgit.com/night-codes/9160052050046367b8cd329c0250531d/raw/8460a8be8978e5375ee566decde92e73e2ccb581/tokey.svg)\n\n\n[![GoDoc](https://img.shields.io/badge/godoc-reference-2299dd.svg)](https://pkg.go.dev/github.com/night-codes/tokay?tab=doc)\n[![Go Report](https://img.shields.io/badge/go%20report-A+-brightgreen.svg?style=flat)](http://goreportcard.com/report/night-codes/tokay)\n[![github issues](https://img.shields.io/github/issues/night-codes/tokay.svg)](https://github.com/night-codes/tokay/issues?q=is%3Aopen+is%3Aissue)\n[![github closed issues](https://img.shields.io/github/issues-closed-raw/night-codes/tokay.svg)](https://github.com/night-codes/tokay/issues?q=is%3Aissue+is%3Aclosed)\n[![release](https://img.shields.io/github/release/night-codes/tokay.svg)](https://github.com/night-codes/tokay/releases)\n\n\n## Description\n\n**Tokay** is small and fast web framework written in Go (Golang) for the high-performance [fasthttp](https://github.com/valyala/fasthttp) server.\nThe package has the following features:\n\n* middleware pipeline architecture, similar to that of the **Gin-gonic** framework.\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* HTML, XML, JSON etc. rendering based on package [night-codes/tokay-render](https://github.com/night-codes/tokay-render)\n\n## Requirements\n\nGo 1.13 or above.\n\n## Installation\n\nRun the following command to install the package:\n\n```\ngo get github.com/night-codes/tokay\n```\n\n## Getting Started\n\nCreate a `server.go` file with the following content:\n\n```go\npackage main\n\nimport (\n\t\"github.com/night-codes/tokay\"\n)\n\nfunc main() {\n\tapp := tokay.New()\n\n\t// Methods:   GET, POST\n\t// Resource: http://localhost:8080/\n\tapp.To(\"GET,POST\", \"/\", func(c *tokay.Context) {\n\t\tc.String(200, \"Hello world!\")\n\t})\n\n\t// same as app.To(\"GET\", \"/ping\", [...])\n\t// Method:   GET\n\t// Resource: http://localhost:8080/ping\n\tapp.GET(\"/ping\", func(c *tokay.Context) {\n\t\tc.String(200, \"pong\")\n\t})\n\n\t// Method:   GET\n\t// Resource: http://localhost:8080/hello\n\tapp.GET(\"/hello\", func(c *tokay.Context) {\n\t\tc.JSON(200, map[string]interface{}{\"message\": \"Hello world!\"})\n\t})\n\n\t// http://localhost:8080\n\t// http://localhost:8080/ping\n\t// http://localhost:8080/hello\n\tapp.Run(\":8080\", \"Application started at http://localhost%s\")\n}\n```\n\nNow run the following command to start the Web server:\n\n```\ngo run server.go\n```\n\nYou should be able to access URLs such as `http://localhost:8080`.\n\n\n### Routes\n\nRouting 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\nr := tokay.New()\nr.To(\"GET\", \"/users\", m1, m2, h1)\nr.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\nr.GET(\"/users\", m1, m2, h1)\nr.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\nr.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\nr.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/\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\nr := tokay.New()\n\nr.GET(\"/users/\u003cusername\u003e\", func (c *tokay.Context) {\n\tfmt.Fprintf(c, \"Name: %v\", c.Param(\"username\"))\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\nr := tokay.New()\napi := r.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 routing 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\nrouting 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\nr := tokay.New()\nr.Use(m1)\n\napi := r.Group(\"/api\")\napi.Use(m2)\n\nusers := api.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 routing table and dispatches incoming requests to appropriate handlers. A router instance is created\nby calling the `tokay.New()` method.\n\nTo hook up engine with fasthttp, use the following code:\n\n```go\nr := tokay.New()\npanic(r.Run(\":8080\"))\n```\n\n\n### Handlers\n\nA handler is a function with the signature `func(*tokay.Context)`. A handler is executed by the router if\nthe incoming request URL path matches the route that the handler is associated with. Through the `tokay.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 method. \nA handler calls `Context.Abort()`: the router will simply skip the rest of the handlers. \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### BasicAuth() middleware\nBasicAuth method returns a Basic HTTP Authorization middleware. It takes even number of string arguments (username1, password1, username2, password2, etc...)\n\n```go\nr := tokay.New()\n\n// Group using tokay.BasicAuth() middleware\nauthorized := r.Group(\"/admin\", tokay.BasicAuth(\"foo\", \"bar\", \"austin\", \"1234\", \"lena\", \"hello2\"))\n\nauthorized.GET(\"/secrets\", func(c *tokay.Context) {\n    // get user, it was set by the BasicAuth middleware\n    user := c.Get(tokay.AuthUserKey).(string)\n    c.String(200, \"Hello \"+user+\"!\")\n})\n\n// Listen and serve on 0.0.0.0:8080\npanic(r.Run(\":8000\"))\n\n```\n\n### Context\n\nFor each incoming request, a `tokay.Context` object is passed through the relevant handlers. Because `tokay.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\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* `tokay.MethodNotAllowedHandler`: a handler that sends an `Allow` HTTP header indicating the allowed HTTP methods for a requested URL\n* `tokay.NotFoundHandler`: a handler triggering 404 HTTP error\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnight-codes%2Ftokay","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnight-codes%2Ftokay","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnight-codes%2Ftokay/lists"}