{"id":25933332,"url":"https://github.com/robertwhurst/navaros","last_synced_at":"2025-03-04T00:53:28.809Z","repository":{"id":186437736,"uuid":"675170988","full_name":"RobertWHurst/Navaros","owner":"RobertWHurst","description":"A simple and powerful little router framework for go","archived":false,"fork":false,"pushed_at":"2025-02-02T08:51:42.000Z","size":2303,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-02T09:26:04.589Z","etag":null,"topics":["go","http-server","middleware","mux","routing"],"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/RobertWHurst.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["RobertWHurst"]}},"created_at":"2023-08-06T02:58:42.000Z","updated_at":"2025-02-02T08:51:46.000Z","dependencies_parsed_at":"2024-06-21T19:21:18.452Z","dependency_job_id":"37fc7eaf-3843-41e8-a2f5-5897c945c3cb","html_url":"https://github.com/RobertWHurst/Navaros","commit_stats":null,"previous_names":["robertwhurst/navaros"],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobertWHurst%2FNavaros","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobertWHurst%2FNavaros/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobertWHurst%2FNavaros/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobertWHurst%2FNavaros/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RobertWHurst","download_url":"https://codeload.github.com/RobertWHurst/Navaros/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241763726,"owners_count":20016162,"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":["go","http-server","middleware","mux","routing"],"created_at":"2025-03-04T00:53:28.331Z","updated_at":"2025-03-04T00:53:28.798Z","avatar_url":"https://github.com/RobertWHurst.png","language":"Go","funding_links":["https://github.com/sponsors/RobertWHurst"],"categories":[],"sub_categories":[],"readme":"# Navaros\n\n\u003cp\u003e\n  \u003cimg src=\"logo.png\" width=\"400\" align=\"right\" /\u003e\n\u003c/p\u003e\n\n\u003cp\u003e\n  \u003ca href=\"https://pkg.go.dev/github.com/RobertWHurst/navaros\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/godoc-reference-blue.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://goreportcard.com/report/github.com/RobertWHurst/navaros\"\u003e\n    \u003cimg src=\"https://goreportcard.com/badge/github.com/RobertWHurst/navaros\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/RobertWHurst/Navaros/actions/workflows/ci.yml\"\u003e\n    \u003cimg src=\"https://github.com/RobertWHurst/Navaros/actions/workflows/ci.yml/badge.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/sponsors/RobertWHurst\"\u003e\n    \u003cimg src=\"https://img.shields.io/static/v1?label=Sponsor\u0026message=%E2%9D%A4\u0026logo=GitHub\u0026color=%23fe8e86\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003e __If you encounter a bug please [report it][bug-report].__\n\n_Navaros is a simple and fast HTTP router for Go. It's designed to be simple to\nuse and get out of your way so you can focus on building awesome things._\n\n\u003cbr clear=\"right\"\u003e\n\u003cbr\u003e\n\n```go\nimport (\n  \"net/http\"\n  \"github.com/RobertWHurst/navaros\"\n  \"github.com/RobertWHurst/navaros/middleware/json\"\n)\n\nfunc main() {\n  router := navaros.New()\n\n  widgets := []*Widget{}\n\n  router.Use(json.Middleware(nil))\n\n  router.Post(\"/widget\", func (ctx *navaros.Context) {\n    widget := \u0026Widget{}\n    if ctx.UnmarshalRequestBody(widget); err != nil {\n      ctx.Status = 404\n      ctx.Body = map[string]string{\"error\": \"invalid request body\"}\n      return\n    }\n    \n    widget.ID = GenId()\n    widgets = append(widgets, widget)\n\n    ctx.Status = 201\n  })\n\n  router.Get(\"/widget\", func (ctx *navaros.Context) {\n    ctx.Status = 200\n    ctx.Body = widgets\n  })\n\n  router.Get(\"/widget/:id\", func (ctx *navaros.Context) {\n    id := ctx.Params().Get(\"id\")\n\n    for _, widget := range widgets {\n      if widget.ID == id {\n        ctx.Status = 200\n        ctx.Body = widget\n        return\n      }\n    }\n\n    ctx.Status = 404\n  })\n\n  server := http.Server{\n    Addr: \":8080\",\n    Handler: router\n  }\n\n  server.ListenAndServe()\n}\n```\n\n## Features\n\n- Simple and fast\n- Middleware support\n- Parameterized routes\n- Streaming request and response bodies\n- Marshal and unmarshal API for body related middleware\n- Unmarshal request bodies into structs\n- handler panic recovery\n- Request and response data organized into a single context object\n- context support for ending handler logic after cancelled requests\n- No dependencies other than the standard library\n- Powerful route pattern matching\n- Nestable routers\n\n## Installation\n\n```sh\ngo get github.com/RobertWHurst/navaros\n```\n\n## Usage\n\nNavaros is designed to be simple to use and get out of your way so you can focus\non building awesome things. It's API is designed to be simple and intuitive.\n\n### Creating a router\n\nIn order to get started you need to create a router. A router is an http.Handler\nso to use it you just need to assign it as http server's handler.\n\n```go\nrouter := navaros.New()\n\nserver := http.Server{\n  Addr: \":8080\",\n  Handler: router\n}\n\nserver.ListenAndServe()\n```\n\n### Adding middleware\n\nLet's say your going to be building an API and you want to use JSON as your\nrequest and response body format. Navaros comes with JSON middleware for this\npurpose. Now the request body will be buffered, and you will be able to\nunmarshal it into a struct within you handlers.\n\n```go\nrouter.Use(json.Middleware(nil))\n```\n\n### Adding a route and unmarshaling a request body\n\nNow let's add a handler to create a widget. We'll use the `Post` method to\nregister a handler for the `POST` method on the `/widget` path.\n\n```go\ntype Widget struct {\n  Name string `json:\"name\"`\n  ...\n}\n\nrouter.Post(\"/widget\", func (ctx *navaros.Context) {\n  widget := \u0026Widget{}\n  if ctx.UnmarshalRequestBody(widget); err != nil {\n    ctx.Status = 400\n    ctx.Body = map[string]string{\"error\": \"invalid request body\"}\n    return\n  }\n  \n  ...\n\n  ctx.Status = 201\n})\n```\n\n### Adding a parameterized route\n\nNow let's add a handler to get a widget by it's id. We'll use the `Get` method\nto register a handler for the `GET` method on the `/widget/:id` path. The `:id`\nportion of the path is a parameter. Parameters are accessible via the `Params`\nmethod on the context.\n\n```go\nrouter.Get(\"/widget/:id\", func (ctx *navaros.Context) {\n  id := ctx.Params().Get(\"id\")\n\n  ...\n})\n```\n\nNote that you can do much more with route patterns. We'll cover that later in\nthe readme.\n\n### Context cancellation\n\nNow let's say we have a handler that might be doing some expensive work. We\ndon't want to waste resources on requests that have been cancelled. For any\nlogic in your handler that supports go's context API you can actually pass\nthe handler context to it as ctx implements the context interface.\n\n```go\nrouter.Post(\"/report\", func (ctx *navaros.Context) {\n  reportCfg := \u0026ReportConfiguration{}\n  if err := ctx.UnmarshalRequestBody(reportCfg); err != nil {\n    ctx.Status = 400\n    ctx.Body = map[string]string{\"error\": \"invalid request body\"}\n    return\n  }\n  \n  report, err := reportGenerator.GenerateReport(ctx, reportCfg)\n\n  ctx.Status = 200\n  ctx.Body = report\n})\n```\n\nIf the request is cancelled the GenerateReport function can check the context\nfor cancellation and return early.\n\n### Streaming request and response bodies\n\nNavaros supports streaming request and response bodies. This is useful for\nhandling large files or streaming data. Provided you are not using Middleware\nthat buffers the request body you can read the bytes as they come in.\n\n```go\nrouter.Post(\"/upload\", func (ctx *navaros.Context) {\n  ctx.MaxRequestBodySize = 1024 * 1024 * 100 // 100MB\n\n  reader := ctx.RequestBodyReader()\n\n  ...\n})\n```\n\nYou can also stream the response body.\n\n```go\nrouter.Get(\"/download/:id\", func (ctx *navaros.Context) {\n  id := ctx.Params().Get(\"id\")\n  fileReader, err := fileManager.GetFileReader(id)\n  if err != nil {\n    if err == fileManager.ErrFileNotFound {\n      ctx.Status = 404\n      return\n    }\n    panic(err)\n  }\n\n  ctx.Status = 200\n  ctx.Body = fileReader\n})\n```\n\n### Nesting routers\n\nNavaros supports nesting routers. This is useful for breaking up your routes\ninto logical groups. For example you might break your resources into packages -\neach package having it's own router.\n\nYour root router might look something like this.\n\n```go\nrouter := navaros.New()\n\nrouter.Use(json.Middleware(nil))\n\nrouter.Use(widgets.Router)\nrouter.Use(gadgets.Router)\nrouter.Use(gizmos.Router)\n```\nAnd each of your resource routers might look something like this.\n\n```go\npackage widgets\n\nimport (\n  \"github.com/RobertWHurst/navaros\"\n)\n\nvar Router = navaros.New()\n\nfunc init() {\n  Router.Post(\"/widget\", CreateWidget)\n  Router.Get(\"/widget\", GetWidgets)\n  Router.Get(\"/widget/:id\", GetWidgetByID)\n}\n\nfunc CreateWidget(ctx *navaros.Context) {\n  ...\n}\n\nfunc GetWidgets(ctx *navaros.Context) {\n  ...\n}\n\nfunc GetWidgetByID(ctx *navaros.Context) {\n  ...\n}\n```\n\n### Route patterns\n\nNavaros supports fairly powerful route patterns. The following is a list of\nsupported pattern chunk types.\n\n- Static - `/a/b/c` - Matches the exact path\n- Wildcard - `/a/*/c` - Pattern segments with a single `*` match any path segment\n- Dynamic - `/a/:b/c` - Pattern segments prefixed with `:` match any path segment\n  and the value of this segment from the matched path is available via the\n  `Params` method, and will be filled under a key matching the name of the\n  pattern segment, ie: pattern of `/a/:b/c` will match `/a/1/c` and the value\n  of `b` in the params will be `1`\n\nPattern chunks can also be suffixed with additional modifiers.\n\n- `?` - Optional - `/a/:b?/c` - Matches `/a/c` and `/a/1/c`\n- `*` - Greedy - `/a/:b*/c` - Matches `/a/c` and `/a/1/2/3/c`\n- `+` - One or more - `/a/:b+/c` - Matches `/a/1/c` and `/a/1/2/3/c` but not `/a/c`\n\nYou can also provide a regular expression to restrict matches for a pattern chunk.\n\n- `/a/:b(\\d+)/c` - Matches `/a/1/c` and `/a/2/c` but not `/a/b/c`\n\nYou can escape any of the special characters used by these operators by prefixing\nthem with a `\\`.\n\n- `/a/\\:b/c` - Matches `/a/:b/c`\n\nAnd all of these can be combined.\n\n- `/a/:b(\\d+)/*?/(d|e)+` - Matches `/a/1/d`, `/a/1/e`, `/a/2/c/d/e/f/g`, and\n`/a/3/1/d` but not `/a/b/c`, `/a/1`, or `/a/1/c/f`\n\nThis is all most likely overkill, but if you ever need it, it's here.\n\n### Handler and Middleware ordering\n\nHandlers and middleware are executed in the order they are added to the router.\nThis means that a handler added before another will always be checked for a\nmatch against the incoming request first regardless of the path pattern. This\nmeans you can easily predict how your handlers will be executed.\n\nIt also means that your handlers with more specific patterns should be\nadded before any others that may share a common match.\n\n```go\nrouter.Get(\"/album/:id(\\d{24})\", GetWidgetByID)\nrouter.Get(\"/album/:name\", GetWidgetsByName)\n```\n\n### Binding different HTTP methods\n\nThe router has a method for the following HTTP methods.\n\n- `Get` - Handles `GET` requests - Should be used for reading\n- `Post` - Handles `POST` requests - Should be used for creating\n- `Put` - Handles `PUT` requests - Should be used for updating\n- `Patch` - Handles `PATCH` requests - Should be used for updating\n- `Delete` - Handles `DELETE` requests - Should be used for deleting\n- `Head` - Handles `HEAD` requests - Should be used checking for existence\n- `Options` - Handles `OPTIONS` requests - Used for CORS\n\nThere is also a few non HTTP method methods.\n\n- `All` - Handles all requests matching the pattern regardless of method\n- `Use` - Handles all requests like all, but a pattern can be omitted\n\n### Passing a request on to the next handler - middleware\n\nIf you want to pass a request on to the next handler you can call the `Next`\nmethod on the context. This will execute the next handler in the chain.\n\n```go\nrouter.All(\"/admin/**\", func (ctx *navaros.Context) {\n  if !IsAuthenticated(ctx) {\n    ctx.Status = 401\n    return\n  }\n  ctx.Next()\n})\n```\n\nThis is what makes a handler into middleware.\n\nInterestingly you can also add logic after the `Next` call. This is useful for\ndoing things with the response after a handler executed during the `Next` call\nhas a written it.\n\n```go\nrouter.Use(func (ctx *navaros.Context) {\n  ctx.Next()\n  if ctx.Status == 404 \u0026\u0026 ctx.Body == nil {\n    ctx.Status = 404\n    ctx.Body = map[string]string{\"error\": \"not found\"}\n  }\n})\n```\n\n## Roadmap\n\nNow that the core of Navaros is complete I'm going to be focusing on adding more\nmiddleware and adding websocket support.\n\nWebsockets are going to be an important part of this project as I want to\nsupport building realtime applications with Navaros.\n\n## Help Welcome\n\nIf you want to support this project by throwing be some coffee money It's\ngreatly appreciated.\n\n[![sponsor](https://img.shields.io/static/v1?label=Sponsor\u0026message=%E2%9D%A4\u0026logo=GitHub\u0026color=%23fe8e86)](https://github.com/sponsors/RobertWHurst)\n\nIf your interested in providing feedback or would like to contribute please feel\nfree to do so. I recommend first [opening an issue][feature-request] expressing\nyour feedback or intent to contribute a change, from there we can consider your\nfeedback or guide your contribution efforts. Any and all help is greatly\nappreciated since this is an open source effort after all.\n\nThank you!\n\n[bug-report]: https://github.com/RobertWHurst/Navaros/issues/new?template=bug_report.md\n[feature-request]: https://github.com/RobertWHurst/Navaros/issues/new?template=feature_request.md\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobertwhurst%2Fnavaros","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frobertwhurst%2Fnavaros","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobertwhurst%2Fnavaros/lists"}