{"id":46064471,"url":"https://github.com/gowww/app","last_synced_at":"2026-03-01T12:06:08.359Z","repository":{"id":57505765,"uuid":"91794195","full_name":"gowww/app","owner":"gowww","description":"🚀 Full featured HTTP framework for web apps","archived":false,"fork":false,"pushed_at":"2024-04-17T14:19:37.000Z","size":104,"stargazers_count":17,"open_issues_count":2,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-06-20T12:46:29.696Z","etag":null,"topics":["framework","fullstack","go","gohtml","golang","gowww","handler","http","internationalization","middleware","regular-expression","router","server","web","webapp"],"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/gowww.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-05-19T10:17:09.000Z","updated_at":"2024-04-17T14:19:40.000Z","dependencies_parsed_at":"2024-06-20T12:00:32.402Z","dependency_job_id":"194f4a8b-1e01-42b2-94a7-d540b07e3169","html_url":"https://github.com/gowww/app","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/gowww/app","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gowww%2Fapp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gowww%2Fapp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gowww%2Fapp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gowww%2Fapp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gowww","download_url":"https://codeload.github.com/gowww/app/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gowww%2Fapp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29969243,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T11:43:06.159Z","status":"ssl_error","status_checked_at":"2026-03-01T11:43:03.887Z","response_time":124,"last_error":"SSL_read: 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":["framework","fullstack","go","gohtml","golang","gowww","handler","http","internationalization","middleware","regular-expression","router","server","web","webapp"],"created_at":"2026-03-01T12:06:07.898Z","updated_at":"2026-03-01T12:06:08.354Z","avatar_url":"https://github.com/gowww.png","language":"Go","readme":"\u003cp align=\"center\"\u003e\n\t\u003cimg src=\"https://gist.githubusercontent.com/xthezealot/0956f6a409162f6fd11bd5631f3a6537/raw/1c4d5faa559ecfd5ff7e21d394ce730478a67fc1/logo.svg\" alt=\"gowww/app\"\u003e\n\u003c/p\u003e\n\n**gowww/app** is a full featured HTTP framework for any web app.  \nIt greatly increases productivity by providing helpers at all levels while maintaining best performance.\n\n- [Start](#start)\n- [Routing](#routing)\n  - [Path parameters](#path-parameters)\n    - [Named](#named)\n    - [Regular expressions](#regular-expressions)\n    - [Wildcard](#wildcard)\n  - [Groups](#groups)\n  - [Errors](#errors)\n- [Context](#context)\n  - [Request](#request)\n  - [Response](#response)\n  - [Values](#values)\n- [Views](#views)\n  - [Data](#data)\n    - [Built-in](#built-in)\n  - [Functions](#functions)\n    - [Built-in](#built-in-1)\n- [Validation](#validation)\n- [Internationalization](#internationalization)\n- [Static files](#static-files)\n- [Running](#running)\n- [Middlewares](#middlewares)\n\n## Start\n\n1. [Install Go](https://golang.org/doc/install)\n\n2. Install gowww/app:\n\n   ```Shell\n   go get github.com/gowww/app\n   ```\n\n3. Import it in your new app:\n\n   ```Go\n   import \"github.com/gowww/app\"\n   ```\n\n## Routing\n\nThere are methods for common HTTP methods:\n\n```Go\napp.Get(\"/\", func(c *app.Context) {\n\t// Write response for GET /\n})\n\napp.Post(\"/\", func(c *app.Context) {\n\t// Write response for POST /\n})\n\napp.Put(\"/\", func(c *app.Context) {\n\t// Write response for PUT /\n})\n\napp.Patch(\"/\", func(c *app.Context) {\n\t// Write response for PATCH /\n})\n\napp.Delete(\"/\", func(c *app.Context) {\n\t// Write response for DELETE /\n})\n```\n\n### Path parameters\n\n#### Named\n\nA named parameter begins with `:` and matches any value until the next `/` in path.\n\nTo retrieve the value, ask [Context.PathValue](https://godoc.org/github.com/gowww/app#Context.PathValue).  \nIt will return the value as a string (empty if the parameter doesn't exist).\n\nExample, with a parameter `id`:\n\n```Go\napp.Get(\"/users/:id\", func(c *app.Context) {\n\tid := c.PathValue(\"id\")\n\tfmt.Fprintf(w, \"Page of user #%s\", id)\n}))\n```\n\n#### Regular expressions\n\nIf a parameter must match an exact pattern (digits only, for example), you can also set a [regular expression](https://golang.org/pkg/regexp/syntax) constraint just after the parameter name and another `:`:\n\n```Go\napp.Get(`/users/:id:^\\d+$`, func(c *app.Context) {\n\tid := c.PathValue(\"id\")\n\tfmt.Fprintf(w, \"Page of user #%s\", id)\n}))\n```\n\nIf you don't need to retrieve the parameter value but only use a regular expression, you can omit the parameter name.\n\n#### Wildcard\n\nA trailing slash behaves like a wildcard by matching the beginning of the request path and keeping the rest as a parameter value, under `*`:\n\n```Go\nrt.Get(\"/files/\", func(c *app.Context) {\n\tfilepath := c.PathValue(\"*\")\n\tfmt.Fprintf(w, \"Get file %s\", filepath)\n}))\n```\n\nFor more details, see [gowww/router](https://github.com/gowww/router).\n\n### Groups\n\nA routing group works like the top-level router but prefixes all subroute paths:\n\n```Go\napi := app.Group(\"/api\")\n{\n\tv1 := api.Group(\"/v1\")\n\t{\n\t\tv1.Get(\"/user\", func(c *app.Context) { /* Write response for GET /api/v1/user */ })\n\t\tv1.Get(\"/item\", func(c *app.Context) { /* Write response for GET /api/v1/item */ })\n\t}\n\n\tv2 := api.Group(\"/v2\")\n\t{\n\t\tv2.Get(\"/user\", func(c *app.Context) { /* Write response for GET /api/v2/user */ })\n\t\tv2.Get(\"/item\", func(c *app.Context) { /* Write response for GET /api/v2/item */ })\n\t}\n}\n```\n\n### Errors\n\nYou can set a custom \"not found\" handler with [NotFound](https://godoc.org/github.com/gowww/app#NotFound):\n\n```Go\napp.NotFound(func(c *app.Context) {\n\tc.Status(http.StatusNotFound)\n\tc.View(\"notFound\")\n})\n```\n\nThe app is also recovered from panics so you can set a custom \"serving error\" handler (which is used only when the response is not already written) with [Error](https://godoc.org/github.com/gowww/app#NotFound) and retrieve the recovered error value with [Context.Error](https://godoc.org/github.com/gowww/app#Context.Error):\n\n```Go\napp.Error(func(c *app.Context) {\n\tc.Status(http.StatusInternalServerError)\n\tif c.Error() == ErrCannotOpenFile {\n\t\tc.View(\"errorStorage\")\n\t\treturn\n\t}\n\tc.View(\"error\")\n})\n```\n\n## Context\n\nA [Context](https://godoc.org/github.com/gowww/app#Context) is always used inside a [Handler](https://godoc.org/github.com/gowww/app#Handler).  \nIt contains the original request and response writer but provides all the necessary helpers to access them:\n\n### Request\n\nUse [Context.Req](https://godoc.org/github.com/gowww/app#Context.Req) to access the original request:\n\n```Go\napp.Get(\"/\", func(c *app.Context) {\n\tr := c.Req\n})\n```\n\nUse [Context.FormValue](https://godoc.org/github.com/gowww/app#Context.FormValue) to access a value from URL or body.  \nYou can also use [Context.HasFormValue](https://godoc.org/github.com/gowww/app#Context.HasFormValue) to check its existence:\n\n```Go\napp.Get(\"/\", func(c *app.Context) {\n\tif c.HasFormValue(\"id\") {\n\t\tid := c.FormValue(\"id\")\n\t}\n})\n```\n\n### Response\n\nUse [Context.Res](https://godoc.org/github.com/gowww/app#Context.Res) to access the original response writer:\n\n```Go\napp.Get(\"/\", func(c *app.Context) {\n\tw := c.Res\n})\n```\n\nUse [Context.Text](https://godoc.org/github.com/gowww/app#Context.Text) or [Context.Bytes](https://godoc.org/github.com/gowww/app#Context.Bytes) to send a string:\n\n```Go\napp.Get(\"/\", func(c *app.Context) {\n\tc.Text(\"Hello\")\n\tc.Bytes([]byte(\"World\"))\n})\n```\n\nUse [Context.JSON](https://godoc.org/github.com/gowww/app#Context.JSON) to send a JSON formatted response (if implemented by argument, `JSON() interface{}` will be used):\n\n```Go\napp.Get(`/users/:id:^\\d+$/files/`, func(c *app.Context) {\n\tc.JSON(map[string]interface{}{\n\t\t\"userID\":   c.PathValue(\"id\"),\n\t\t\"filepath\": c.PathValue(\"*\"),\n\t})\n})\n```\n\nUse [Context.Status](https://godoc.org/github.com/gowww/app#Context.Status) to set the response status code:\n\n```Go\napp.Get(\"/\", func(c *app.Context) {\n\tc.Status(http.StatusCreated)\n})\n```\n\nUse [Context.NotFound](https://godoc.org/github.com/gowww/app#Context.NotFound) to send a \"not found\" response:\n\n```Go\napp.Get(\"/\", func(c *app.Context) {\n\tc.NotFound()\n})\n```\n\nUse [Context.Panic](https://godoc.org/github.com/gowww/app#Context.Panic) to log an error and send a \"serving error\" response:\n\n```Go\napp.Get(\"/\", func(c *app.Context) {\n\tc.Panic(\"database connection failed\")\n})\n```\n\nUse [Context.Redirect](https://godoc.org/github.com/gowww/app#Context.Redirect) to redirect the client:\n\n```Go\napp.Get(\"/old\", func(c *app.Context) {\n\tc.Redirect(\"/new\", http.StatusMovedPermanently)\n})\n```\n\nUse [Context.Push](https://godoc.org/github.com/gowww/app#Context.Push) to initiate an HTTP/2 server push:\n\n```Go\napp.Get(\"/\", func(c *app.Context) {\n\tc.Push(\"/static/main.css\", nil)\n})\n```\n\n### Values\n\nYou can use context values kept inside the context for future usage downstream (like views or subhandlers).\n\nUse [Context.Set](https://godoc.org/github.com/gowww/app#Context.Set) to set a value:\n\n```Go\napp.Get(\"/\", func(c *app.Context) {\n\tc.Set(\"clientCountry\", \"UK\")\n})\n```\n\nUse [Context.Get](https://godoc.org/github.com/gowww/app#Context.Get) to retrieve a value:\n\n```Go\napp.Get(\"/\", func(c *app.Context) {\n\tclientCountry := c.Get(\"clientCountry\")\n})\n```\n\n## Views\n\nViews are standard [Go HTML templates](https://golang.org/pkg/html/template/) and must be stored inside the `views` directory.  \nThey are automatically parsed during launch.\n\nUse [Context.View](https://godoc.org/github.com/gowww/app#Context.View) to send a view:\n\n```Go\napp.Get(\"/\", func(c *app.Context) {\n\tc.View(\"home\")\n})\n```\n\n### Data\n\nUse a [ViewData](https://godoc.org/github.com/gowww/app#ViewData) map to pass data to a view.\n\nYou can also use [GlobalViewData](https://godoc.org/github.com/gowww/app#GlobalViewData) to set data for all views:\n\n```Go\napp.GlobalViewData(app.ViewData{\n\t\"appName\": \"My app\",\n})\n\napp.Get(\"/\", func(c *app.Context) {\n\tuser := \u0026User{\n\t\tID:   1,\n\t\tName: \"John Doe\",\n\t}\n\tc.View(\"home\", app.ViewData{\n\t\t\"user\": user,\n\t})\n})\n```\n\nIn _views/home.gohtml_:\n\n```HTML\n{{define \"home\"}}\n\t\u003ch1\u003eHello {{.user.Name}} ({{.c.Req.RemoteAddr}}) and welcome on {{.appName}}!\u003c/h1\u003e\n{{end}}\n```\n\n#### Built-in\n\nThis data is always passed to the views, out of the box:\n\n| Data             | Description                                                            |\n| ---------------- | ---------------------------------------------------------------------- |\n| `.c`             | The current [Context](https://godoc.org/github.com/gowww/app#Context). |\n| `.envProduction` | Tells if the app is run with the production flag.                      |\n| `.errors`        | See [validation](#validation).                                         |\n\n### Functions\n\nUse [GlobalViewFuncs](https://godoc.org/github.com/gowww/app#GlobalViewFuncs) to set functions for all views:\n\n```Go\napp.GlobalViewFuncs(app.ViewFuncs{\n\t\"pathescape\": url.PathEscape,\n})\n\napp.Get(\"/posts/new\", func(c *app.Context) {\n\tc.View(\"postsNew\")\n})\n```\n\nIn _views/posts.gohtml_:\n\n```HTML\n{{define \"postsNew\"}}\n\t\u003ca href=\"/sign-in?return-to={{pathescape \"/posts/new\"}}\"\u003eSign in\u003c/a\u003e\n{{end}}\n```\n\n#### Built-in\n\nIn addition to the functions provided by the standard [template](https://golang.org/pkg/text/template/#hdr-Functions) package, these function are also available out of the box:\n\n| Function      | Description                                                                              | Usage                                           |\n| ------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------- |\n| `asset`       | Appends the file hash to the name of a static file from the `static` directory.          | `{{asset \"videos/loop.mp4\"}}`                   |\n| `googlefonts` | Sets HTML tag for [Google Fonts](https://fonts.google.com) stylesheet and given font(s). | `{{googlefonts \"Open+Sans:400,700\\|Spectral\"}}` |\n| `nl2br`       | Converts `\\n` to HTML `\u003cbr\u003e`.                                                            | `{{nl2br \"line one\\nline two\"}}`                |\n| `safehtml`    | Prevents string to be escaped. Be careful.                                               | `{{safehtml \"\u003cstrong\u003eword\u003c/strong\u003e\"}}`          |\n| `script`      | Sets HTML tag for a script from the `static/script` directory.                           | `{{script \"main.js\"}}`                          |\n| `style`       | Sets HTML tag for a stylesheet from the `static/style` directory.                        | `{{style \"main.css\"}}`                          |\n\n## Validation\n\nValidation is handled by [gowww/check](https://godoc.org/github.com/gowww/check).\n\nFirstly, make a [Checker](https://godoc.org/github.com/gowww/check#Checker) with [rules](https://github.com/gowww/check#rules) for keys:\n\n```Go\nuserChecker := check.Checker{\n\t\"email\":   {check.Required, check.Email, check.Unique(db, \"users\", \"email\", \"?\")},\n\t\"phone\":   {check.Phone},\n\t\"picture\": {check.MaxFileSize(5000000), check.Image},\n}\n```\n\nThe rules order is significant so for example, it's smarter to check the format of a value before its uniqueness, avoiding some useless database requests.\n\nUse [Context.Check](https://godoc.org/github.com/gowww/app#Context.Check) to check the request against a checker:\n\n```Go\nerrs := c.Check(userChecker)\n```\n\nUse [Errors.Empty](https://godoc.org/github.com/gowww/check#Errors.Empty) or [Errors.NotEmpty](https://godoc.org/github.com/gowww/check#Errors.NotEmpty) to know if there are errors and handle them like you want.  \nYou can also translate error messages with [Context.TErrors](https://godoc.org/github.com/gowww/app#Context.TErrors):\n\n```Go\nif errs.NotEmpty() {\n\tc.Status(http.StatusBadRequest)\n\tc.View(view, app.ViewData{\"errors\": errs})\n\treturn\n}\n```\n\nBut usually, when a check fails, you only want to send a response with error messages.  \nHere comes the [BadRequest](https://godoc.org/github.com/gowww/app#BadRequest) shortcut which receives a checker and a view name.  \nIf you don't provide a view name (empty string), the response will be a JSON errors map.\n\nIf the check fails, it sets the status to \"400 Bad Request\", sends the response (view or JSON) and returns `true`, allowing you to exit from the handler:\n\n```Go\napp.Post(\"/join\", func(c *app.Context) {\n\tif c.BadRequest(userChecker, \"join\") {\n\t\treturn\n\t}\n\t// Handle request confidently\n})\n```\n\nIn views, you can retrieve the [TranslatedErrors](https://godoc.org/github.com/gowww/check#TranslatedErrors) map under key `errors` which is never `nil` in view data:\n\n```HTML\n\u003cinput type=\"email\" name=\"email\" value=\"{{.email}}\"\u003e\n{{if .errors.Has \"email\"}}\n\t\u003cdiv class=\"error\"\u003e{{.errors.First \"email\"}}\u003c/div\u003e\n{{end}}\n```\n\n## Internationalization\n\nInternationalization is handled by [gowww/i18n](https://godoc.org/github.com/gowww/i18n).\n\nFirstly, make your translations map (string to string, for each language):\n\n```Go\nlocales := i18n.Locales{\n\tlanguage.English: {\n\t\t\"hello\": \"Hello!\",\n\t},\n\tlanguage.French: {\n\t\t\"hello\": \"Bonjour !\",\n\t},\n}\n```\n\nUse [Localize](https://godoc.org/github.com/gowww/app#Localize) to register it and set the default locale (used as a fallback):\n\n```Go\napp.Localize(locales, language.English)\n```\n\nMethods [Context.T](https://godoc.org/github.com/gowww/app#Context.T), [Context.Tn](https://godoc.org/github.com/gowww/app#Context.Tn), [Context.THTML](https://godoc.org/github.com/gowww/app#Context.THTML) and [Context.TnHTML](https://godoc.org/github.com/gowww/app#Context.TnHTML) are now operational.  \nAs the [Context](https://godoc.org/github.com/gowww/app#Context) is always part of the view data, you can use these methods in views:\n\n```HTML\n\u003ch1\u003e{{.c.T \"hello\"}}\u003c/h1\u003e\n```\n\n## Static files\n\nStatic files must be stored inside the `static` directory.  \nThey are automatically accessible from the `/static/` path prefix.\n\n## Running\n\nCall [Run](https://godoc.org/github.com/gowww/app#Run) at the end of your main function:\n\n```Go\napp.Run()\n```\n\nBy default, your app will listen and serve on `:8080`.  \nBut you can change this address by using flag `-a` when running your app:\n\n```Shell\n./myapp -a :1234\n```\n\n## Middlewares\n\nCustom middlewares can be used if they are compatible with standard interface [net/http.Handler](https://golang.org/pkg/net/http/#Handler).  \nThey can be set for:\n\n- The entire app:\n\n  ```Go\n  app.Run(hand1, hand2, hand3)\n  ```\n\n- A group:\n\n  ```Go\n  api := app.Group(\"/api\", hand1, hand2, hand3)\n  ```\n\n- A single route:\n\n  ```Go\n  api := app.Get(\"/\", func(c *app.Context) {\n  \t// Write response for GET /\n  }, hand1, hand2, hand3)\n  ```\n\nFirst handler wraps the second and so on.\n\n\u003cp align=\"center\"\u003e\n\t\u003cbr\u003e\u003cbr\u003e\n\t\u003ca href=\"https://godoc.org/github.com/gowww/app\"\u003e\u003cimg src=\"https://godoc.org/github.com/gowww/app?status.svg\" alt=\"GoDoc\"\u003e\u003c/a\u003e\n\t\u003ca href=\"https://travis-ci.org/gowww/app\"\u003e\u003cimg src=\"https://travis-ci.org/gowww/app.svg?branch=master\" alt=\"Build\"\u003e\u003c/a\u003e\n\t\u003ca href=\"https://coveralls.io/github/gowww/app?branch=master\"\u003e\u003cimg src=\"https://coveralls.io/repos/github/gowww/app/badge.svg?branch=master\" alt=\"Coverage\"\u003e\u003c/a\u003e\n\t\u003ca href=\"https://goreportcard.com/report/github.com/gowww/app\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/gowww/app\" alt=\"Go Report\"\u003e\u003c/a\u003e\n\t\u003cimg src=\"https://img.shields.io/badge/status-unstable-red.svg\" alt=\"Status Unstable\"\u003e\n\t\u003cbr\u003e\u003cbr\u003e\n\u003c/p\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgowww%2Fapp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgowww%2Fapp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgowww%2Fapp/lists"}