{"id":13367434,"url":"https://github.com/Go-playground/lars","last_synced_at":"2025-03-12T18:32:46.729Z","repository":{"id":57481105,"uuid":"48551683","full_name":"go-playground/lars","owner":"go-playground","description":":rotating_light: Is a lightweight, fast and extensible zero allocation HTTP router for Go used to create customizable frameworks.","archived":false,"fork":false,"pushed_at":"2019-05-15T21:58:32.000Z","size":487,"stargazers_count":387,"open_issues_count":1,"forks_count":26,"subscribers_count":18,"default_branch":"master","last_synced_at":"2024-08-01T01:44:26.807Z","etag":null,"topics":["customizable-context","http-router","zero-allocation"],"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/go-playground.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":"2015-12-24T17:28:45.000Z","updated_at":"2024-06-24T05:43:02.000Z","dependencies_parsed_at":"2022-09-04T01:40:10.967Z","dependency_job_id":null,"html_url":"https://github.com/go-playground/lars","commit_stats":null,"previous_names":["go-experimental/lars","go-experimental/lcars"],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-playground%2Flars","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-playground%2Flars/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-playground%2Flars/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-playground%2Flars/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/go-playground","download_url":"https://codeload.github.com/go-playground/lars/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221309982,"owners_count":16795838,"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":["customizable-context","http-router","zero-allocation"],"created_at":"2024-07-30T00:01:48.792Z","updated_at":"2024-10-24T11:31:19.873Z","avatar_url":"https://github.com/go-playground.png","language":"Go","readme":"## LARS\n\u003cimg align=\"right\" src=\"https://raw.githubusercontent.com/go-playground/lars/master/_examples/README/test.gif\"\u003e![Project status](https://img.shields.io/badge/version-4.0.1-green.svg)\n[![Build Status](https://semaphoreci.com/api/v1/projects/4351aa2d-2f94-40be-a6ef-85c248490378/679708/badge.svg)](https://semaphoreci.com/joeybloggs/lars)\n[![Coverage Status](https://coveralls.io/repos/github/go-playground/lars/badge.svg?branch=master)](https://coveralls.io/github/go-playground/lars?branch=master)\n[![Go Report Card](https://goreportcard.com/badge/go-playground/lars)](https://goreportcard.com/report/go-playground/lars)\n[![GoDoc](https://godoc.org/github.com/go-playground/lars?status.svg)](https://godoc.org/github.com/go-playground/lars)\n![License](https://img.shields.io/dub/l/vibe-d.svg)\n[![Gitter](https://badges.gitter.im/go-playground/lars.svg)](https://gitter.im/go-playground/lars?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge)\n\nLARS is a fast radix-tree based, zero allocation, HTTP router for Go.  [ view examples](https://github.com/go-playground/lars/tree/master/_examples). If looking for a more pure Go solution, be sure to check out [pure](https://github.com/go-playground/pure) which is essentially a pure version of lars\n\nWhy Another HTTP Router?\n------------------------\nHave 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**.\n\nKey \u0026 Unique Features \n--------------\n- [x] **Context is an interface** - this allows passing of framework/globals/application specific variables. [example](https://github.com/go-playground/lars/blob/master/_examples/all-in-one/main.go)\n- [x] **Smart Route Logic** - 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\n- [x] **Uber simple middleware + handlers** - middleware and handlers actually have the exact same definition!\n- [x] **Custom Handlers** - 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)\n- [x] **Diverse handler support** - Full support for standard/native http Handler + HandlerFunc + some others [see here](https://github.com/go-playground/lars/blob/master/_examples/native/main.go)\n  * 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\n- [x] **Fast \u0026 Efficient** - lars uses a custom version of [httprouter](https://github.com/julienschmidt/httprouter) so incredibly fast and efficient.\n\nInstallation\n-----------\n\n```shell\ngo get -u github.com/go-playground/lars\n```\n\nUsage\n------\nBelow is a simple example, for a full example [see here](https://github.com/go-playground/lars/blob/master/_examples/all-in-one/main.go)\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/go-playground/lars\"\n\tmw \"github.com/go-playground/lars/_examples/middleware/logging-recovery\"\n)\n\nfunc main() {\n\tl := lars.New()\n\t// LoggingAndRecovery is just an example copy paste and modify to your needs\n\tl.Use(mw.LoggingAndRecovery)\n\n\tl.Get(\"/\", HelloWorld)\n\n\thttp.ListenAndServe(\":3007\", l.Serve())\n}\n\n// HelloWorld ...\nfunc HelloWorld(c lars.Context) {\n\tc.Response().Write([]byte(\"Hello World\"))\n\n\t// this will also work, Response() complies with http.ResponseWriter interface\n\tfmt.Fprint(c.Response(), \"Hello World\")\n}\n```\n\nURL Params\n----------\n\n```go\nl := l.New()\n\n// the matching param will be stored in the Context's params with name \"id\"\nl.Get(\"/user/:id\", UserHandler)\n\n// serve css, js etc.. c.Param(lars.WildcardParam) will return the remaining path if \n// you need to use it in a custom handler...\nl.Get(\"/static/*\", http.StripPrefix(\"/static/\", http.FileServer(http.Dir(\"static\")))) \n\n...\n```\n\n**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.\n\nGroups\n-----\n```go\n\nl.Use(LoggingAndRecovery)\n...\nl.Post(\"/users/add\", ...)\n\n// creates a group for user + inherits all middleware registered using l.Use()\nuser := l.Group(\"/user/:userid\")\nuser.Get(\"\", ...)\nuser.Post(\"\", ...)\nuser.Delete(\"/delete\", ...)\n\ncontactInfo := user.Group(\"/contact-info/:ciid\")\ncontactinfo.Delete(\"/delete\", ...)\n\n// creates a group for others + inherits all middleware registered using l.Use() + adds \n// OtherHandler to middleware\nothers := l.GroupWithMore(\"/others\", OtherHandler)\n\n// creates a group for admin WITH NO MIDDLEWARE... more can be added using admin.Use()\nadmin := l.GroupWithNone(\"/admin\")\nadmin.Use(SomeAdminSecurityMiddleware)\n...\n```\n\nCustom Context + Avoid Type Casting / Custom Handlers\n------\n```go\n...\n// MyContext is a custom context\ntype MyContext struct {\n\t*lars.Ctx  // a little dash of Duck Typing....\n}\n\n// CustomContextFunction is a function that is specific to your applications needs that you added\nfunc (mc *MyContext) CustomContextFunction() {\n\t// do something\n}\n\n// newContext is the function that creates your custom context +\n// contains lars's default context\nfunc newContext(l *lars.LARS) lars.Context {\n\treturn \u0026MyContext{\n\t\tCtx:        lars.NewContext(l),\n\t}\n}\n\n// casts custom context and calls you custom handler so you don;t have to type cast lars.Context everywhere\nfunc castCustomContext(c lars.Context, handler lars.Handler) {\n\t// could do it in all one statement, but in long form for readability\n\th := handler.(func(*MyContext))\n\tctx := c.(*MyContext)\n\n\th(ctx)\n}\n\nfunc main() {\n\tl := lars.New()\n\tl.RegisterContext(newContext) // all gets cached in pools for you\n\tl.RegisterCustomHandler(func(*MyContext) {}, castCustomContext)\n\tl.Use(Logger)\n\n\tl.Get(\"/\", Home)\n\n\thttp.ListenAndServe(\":3007\", l.Serve())\n}\n\n// Home ...notice the receiver is *MyContext, castCustomContext handled the type casting for us\n// quite the time saver if you ask me.\nfunc Home(c *MyContext) {\n\tc.CustomContextFunction()\n\t...\n}\n```\n\nDecoding Body\n-------------\nFor full example see [here](https://github.com/go-playground/lars/blob/master/_examples/decode/main.go).\ncurrently JSON, XML, FORM + Multipart Form's are support out of the box.\n```go\n\t// first argument denotes yes or no I would like URL query parameter fields\n\t// to be included. i.e. 'id' in route '/user/:id' should it be included.\n\t// run, then change to false and you'll see user.ID is not populated.\n\tif err := c.Decode(true, maxBytes, \u0026user); err != nil {\n\t\tlog.Println(err)\n\t}\n```\n\nMisc\n-----\n```go\n...\n// can register multiple handlers, the last is considered the last in the chain and others \n// considered middleware, but just for this route and not added to middleware like l.Use() does.\nl.Get(/\"home\", AdditionalHandler, HomeHandler)\n\n// set custom 404 ( not Found ) handler\nl.Register404(404Handler)\n\n// Redirect to or from ending slash if route not found, default is true\nl.SetRedirectTrailingSlash(true)\n\n// Handle 405 ( Method Not allowed ), default is false\nl.SetHandle405MethodNotAllowed(false)\n\n// automatically handle OPTION requests; manually configured\n// OPTION handlers take precedence. default true\nl.SetAutomaticallyHandleOPTIONS(set bool)\n\n// register custom context\nl.RegisterContext(ContextFunc)\n\n// Register custom handler type, see https://github.com/go-playground/lars/blob/master/util.go#L62\n// for example handler creation\nl.RegisterCustomHandler(interface{}, CustomHandlerFunc)\n\n// NativeChainHandler is used as a helper to create your own custom handlers, or use custom handlers \n// that already exist an example usage can be found here \n// https://github.com/go-playground/lars/blob/master/util.go#L86, below is an example using nosurf CSRF middleware\n\nl.Use(nosurf.NewPure(lars.NativeChainHandler))\n\n\n// Context has 2 methods of which you should be aware of ParseForm and ParseMulipartForm, they just call the \n// default http functions but provide one more additional feature, they copy the URL params to the request \n// Forms variables, just like Query parameters would have been.\n// The functions are for convenience and are totally optional.\n```\n\nSpecial Note\n-------------\nI don't know if it was an oversight or just an assumption about how middleware would be used with Go 1.7's new\n`context` integration into the `*http.Request` but there are a few quirks. As you know lars handles multiple handler\ntypes, including the native handler, this functionality is possible because of the way lar handles the middleware; lars\ndoes not `chain` the middleware in the normal way, but rather calles each in sequence; because of this all you have to \ndo is call c.Next() or it has already been wrapped to do so for you transparently. OK getting back to the point, if you\nare not using `lars.Context` to set the context information you will have to set the request object so that the information\ngets back to the calling package. eg.\n\n```go\n// because 'r' is a copy of a pointer to allow the information to get\n// back to the caller, need to set the value of 'r' as below with '*r'\nfunc(w http.ResponseWriter, r *http.Request) {\n\t*r = *r.WithContext(context.WithValue(r.Context(), 0, \"testval1\"))\n}\n```\n\nthis is not an issue specific to lars, but a quirk of the way `context` is tied to the `http.Request` object.\n\nMiddleware\n-----------\nThere are some pre-defined middlewares within the middleware folder; NOTE: that the middleware inside will\ncomply with the following rule(s):\n\n* Are completely reusable by the community without modification\n\nOther middleware will be listed under the _examples/middleware/... folder for a quick copy/paste modify. as an example a logging or\nrecovery middleware are very application dependent and therefore will be listed under the _examples/middleware/...\n\nBenchmarks\n-----------\nRun on MacBook Pro (15-inch, 2017) 3.1 GHz Intel Core i7 16GB DDR3 using Go version go1.9.2 darwin/amd64\n\nNOTICE: lars uses a custom version of [httprouter](https://github.com/julienschmidt/httprouter), benchmarks can be found [here](https://github.com/joeybloggs/go-http-routing-benchmark/tree/lars-only)\n\n```go\ngo test -bench=. -benchmem=true\n#GithubAPI Routes: 203\n   LARS: 49032 Bytes\n\n#GPlusAPI Routes: 13\n   LARS: 3640 Bytes\n\n#ParseAPI Routes: 26\n   LARS: 6632 Bytes\n\n#Static Routes: 157\n   LARS: 30120 Bytes\n\ngoos: darwin\ngoarch: amd64\npkg: github.com/joeybloggs/go-http-routing-benchmark\nBenchmarkLARS_Param        \t20000000\t        51.6 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLARS_Param5       \t20000000\t        85.7 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLARS_Param20      \t10000000\t       215 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLARS_ParamWrite   \t20000000\t        94.3 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLARS_GithubStatic \t20000000\t        68.7 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLARS_GithubParam  \t20000000\t       103 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLARS_GithubAll    \t  100000\t     21066 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLARS_GPlusStatic  \t30000000\t        53.1 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLARS_GPlusParam   \t20000000\t        70.3 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLARS_GPlus2Params \t20000000\t        84.4 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLARS_GPlusAll     \t 2000000\t       894 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLARS_ParseStatic  \t20000000\t        53.5 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLARS_ParseParam   \t20000000\t        60.4 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLARS_Parse2Params \t20000000\t        68.7 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLARS_ParseAll     \t 1000000\t      1602 ns/op\t       0 B/op\t       0 allocs/op\nBenchmarkLARS_StaticAll    \t  100000\t     13777 ns/op\t       0 B/op\t       0 allocs/op\n```\n\nPackage Versioning\n----------\nI'm jumping on the vendoring bandwagon, you should vendor this package as I will not\nbe creating different version with gopkg.in like allot of my other libraries.\n\nWhy? because my time is spread pretty thin maintaining all of the libraries I have + LIFE,\nit is so freeing not to worry about it and will help me keep pouring out bigger and better\nthings for you the community.\n\nThis package is inspired by the following \n-----------\n- [httptreemux](https://github.com/dimfeld/httptreemux)\n- [httprouter](https://github.com/julienschmidt/httprouter)\n- [echo](https://github.com/labstack/echo)\n- [gin](https://github.com/gin-gonic/gin)\n\nLicenses\n--------\n- [MIT License](https://raw.githubusercontent.com/go-playground/lars/master/LICENSE) (MIT), Copyright (c) 2015 Dean Karn\n- [BSD License](https://raw.githubusercontent.com/julienschmidt/httprouter/master/LICENSE), Copyright (c) 2013 Julien Schmidt. All rights reserved.\n","funding_links":[],"categories":["XML"],"sub_categories":["路由"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGo-playground%2Flars","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FGo-playground%2Flars","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGo-playground%2Flars/lists"}