{"id":37136434,"url":"https://github.com/jacobsoderblom/otto","last_synced_at":"2026-01-14T15:53:59.187Z","repository":{"id":57601979,"uuid":"129293836","full_name":"JacobSoderblom/otto","owner":"JacobSoderblom","description":"Otto is an easy way to use HTTP in golang","archived":false,"fork":false,"pushed_at":"2018-06-26T05:29:19.000Z","size":104,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-06-20T20:07:42.751Z","etag":null,"topics":["golang","http","middleware","mux","router"],"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/JacobSoderblom.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":"2018-04-12T18:19:33.000Z","updated_at":"2020-03-14T13:37:20.000Z","dependencies_parsed_at":"2022-09-26T20:00:49.542Z","dependency_job_id":null,"html_url":"https://github.com/JacobSoderblom/otto","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/JacobSoderblom/otto","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JacobSoderblom%2Fotto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JacobSoderblom%2Fotto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JacobSoderblom%2Fotto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JacobSoderblom%2Fotto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JacobSoderblom","download_url":"https://codeload.github.com/JacobSoderblom/otto/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JacobSoderblom%2Fotto/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28425558,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T15:24:48.085Z","status":"ssl_error","status_checked_at":"2026-01-14T15:23:41.940Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["golang","http","middleware","mux","router"],"created_at":"2026-01-14T15:53:58.483Z","updated_at":"2026-01-14T15:53:59.179Z","avatar_url":"https://github.com/JacobSoderblom.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Otto\n\n[![GoDoc](https://godoc.org/github.com/JacobSoderblom/otto?status.svg)](http://godoc.org/github.com/JacobSoderblom/otto)\n[![Build Status](https://travis-ci.org/JacobSoderblom/otto.svg?branch=master)](https://travis-ci.org/JacobSoderblom/otto)\n[![Go Report Card](https://goreportcard.com/badge/github.com/JacobSoderblom/otto)](https://goreportcard.com/report/github.com/JacobSoderblom/otto)\n[![codecov](https://codecov.io/gh/JacobSoderblom/otto/branch/master/graph/badge.svg)](https://codecov.io/gh/JacobSoderblom/otto)\n\nOtto is an easy way to use HTTP in golang. You can either use the Otto App with features like gracefully shutdown on OS signals interrupt and kill, or just use the Otto Router and handle the HTTP Server as you like!\n\nOtto uses [Gorilla/mux](https://github.com/gorilla/mux) to define routes.\n\n## Feature overview\n\n- Group APIs\n- Middleware\n- Functions that makes it easy to send HTTP responses\n- Centralized HTTP error handling\n- Custom error handlers to specific HTTP status codes\n- Possibility to only use the router part\n- A easy way to decode the request body (only json for now, other formats will come later)\n- Automatic TLS via Let’s Encrypt\n\n## Examples\n\nExample of how to use the Otto App\n\n```Go\npackage main\n\nimport (\n  \"log\"\n  \"github.com/JacobSoderblom/otto\"\n)\n\nfunc main() {\n  opts := otto.NewOptions()\n  opts.Addr = \":3000\"\n\n  app := otto.New(opts)\n\n  app.GET(\"/\", func(ctx otto.Context) error {\n    return ctx.String(200, \"Hello world!\")\n  })\n\n  log.Fatal(app.Serve())\n}\n```\n\nExample of how to use Otto with TLS\n\n```Go\npackage main\n\nimport (\n  \"log\"\n  \"github.com/JacobSoderblom/otto\"\n)\n\nfunc main() {\n  opts := otto.NewOptions()\n  opts.Addr = \":443\"\n\n  app := otto.New(opts)\n\n  if err := app.UseTLS(\"path/to/cert\", \"path/to/key\"); err != nil {\n    log.Fatal(err)\n  }\n\n  app.GET(\"/\", func(ctx otto.Context) error {\n    return ctx.String(200, \"Hello world!\")\n  })\n\n  log.Fatal(app.Serve())\n}\n```\n\nExample of how to use Otto with Auto TLS from Let’s Encrypt\n\n```Go\npackage main\n\nimport (\n  \"log\"\n  \"github.com/JacobSoderblom/otto\"\n)\n\nfunc main() {\n  opts := otto.NewOptions()\n  opts.Addr = \":443\"\n\n  app := otto.New(opts)\n\n  app.UseAutoTLS(autocert.DirCache(\"/path/to/cache\"))\n\n  app.GET(\"/\", func(ctx otto.Context) error {\n    return ctx.String(200, \"Hello world!\")\n  })\n\n  log.Fatal(app.Serve())\n}\n```\n\nExample of how to use the Router without the Otto App.\n\nThe Router implements the `http.Handler` so it is easy to use without the `App`!\n\n```Go\npackage main\n\nimport (\n  \"log\"\n  \"github.com/JacobSoderblom/otto\"\n)\n\nfunc main() {\n  r := otto.NewRouter(false)\n\n  r.GET(\"/\", func(ctx otto.Context) error {\n    return ctx.String(200, \"Hello world!\")\n  })\n\n  log.Fatal(http.ListenAndServe(\":3000\", r))\n}\n```\n\nExample of using middlewares\n\n```Go\npackage main\n\nimport (\n  \"log\"\n  \"github.com/JacobSoderblom/otto\"\n)\n\nfunc main() {\n  r := otto.NewRouter(false)\n\n  r.Use(func(next otto.HandlerFunc) otto.HandlerFunc {\n    return func(ctx otto.Context) error {\n      ctx.Set(\"some key\", \"I'm a middleware!\")\n      return next(ctx)\n    }\n  })\n\n  r.GET(\"/\", func(ctx otto.Context) error {\n    return ctx.String(200, \"Hello world!\")\n  })\n\n  log.Fatal(http.ListenAndServe(\":3000\", r))\n}\n```\n\nExample of how to associate error handler to HTTP status code\n\n```Go\npackage main\n\nimport (\n  \"log\"\n  \"github.com/JacobSoderblom/otto\"\n)\n\nfunc main() {\n  r := otto.NewRouter(false)\n\n  errorHandlers := map[int]otto.ErrorHandler{\n    400: func(code int, err error, ctx otto.Context) error {\n      // do some awesome error handling!\n      return ctx.Error(code, err)\n    },\n    401: func(code int, err error, ctx otto.Context) error {\n      // do some awesome error handling!\n      return ctx.Error(code, err)\n    },\n  }\n\n  r.SetErrorHandlers(errorHandlers)\n\n  r.GET(\"/\", func(ctx otto.Context) error {\n    return ctx.String(400, \"Hello world!\")\n  })\n\n  log.Fatal(http.ListenAndServe(\":3000\", r))\n}\n```\n\nExample of how to decode the request body\n\n```Go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/JacobSoderblom/otto\"\n)\n\nfunc main() {\n\tr := otto.NewRouter(false)\n\n\tr.POST(\"/\", func(ctx otto.Context) error {\n\t\tvar body struct {\n\t\t\tMsg string `json:\"msg\"`\n\t\t}\n\n\t\tif err := ctx.Bind(\u0026body); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn ctx.JSON(200, body)\n\t})\n\n\tlog.Fatal(http.ListenAndServe(\":3000\", r))\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjacobsoderblom%2Fotto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjacobsoderblom%2Fotto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjacobsoderblom%2Fotto/lists"}