{"id":19292417,"url":"https://github.com/foolin/gomvc","last_synced_at":"2026-06-11T01:31:39.708Z","repository":{"id":148654368,"uuid":"55583706","full_name":"foolin/gomvc","owner":"foolin","description":"go mvc via utron","archived":false,"fork":false,"pushed_at":"2016-04-06T07:14:02.000Z","size":22,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-15T18:04:10.538Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/foolin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2016-04-06T07:11:16.000Z","updated_at":"2017-11-24T23:14:00.000Z","dependencies_parsed_at":"2023-05-20T19:00:17.149Z","dependency_job_id":null,"html_url":"https://github.com/foolin/gomvc","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/foolin/gomvc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foolin%2Fgomvc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foolin%2Fgomvc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foolin%2Fgomvc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foolin%2Fgomvc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/foolin","download_url":"https://codeload.github.com/foolin/gomvc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foolin%2Fgomvc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34178819,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-10T02:00:07.152Z","response_time":89,"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":[],"created_at":"2024-11-09T22:30:44.357Z","updated_at":"2026-06-11T01:31:39.692Z","avatar_url":"https://github.com/foolin.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# utron [![GoDoc](https://godoc.org/github.com/gernest/utron?status.svg)](https://godoc.org/github.com/gernest/utron) [![Coverage Status](https://coveralls.io/repos/gernest/utron/badge.svg?branch=master\u0026service=github)](https://coveralls.io/github/gernest/utron?branch=master) [![Build Status](https://travis-ci.org/gernest/utron.svg)](https://travis-ci.org/gernest/utron) [![Join the chat at https://gitter.im/gernest/utron](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gernest/utron?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\n\n`utron` is a lightweight MVC framework in Go ([Golang](https://golang.org)) for building fast, scalable and robust database-driven web applications.\n\n# Features\n* [x] Postgres, MySQL and Foundation database support\n* [x] Modular (you can choose which components to use)\n* [x] Middleware support. All [alice](https://github.com/justinas/alice) compatible Middleware works out of the box\n* [x] Gopher spirit (write golang, use all the golang libraries you like)\n* [x] Lightweight. Only MVC\n* [x] Multiple configuration files support (currently json, yaml and toml)\n\n\n\n# Overview\n`utron` is a lightweight MVC framework. It is based on the principles of simplicity, relevance and elegance.\n\n* Simplicity. The design is simple, easy to understand and doesn't introduce many layers between you and the standard library. It is a goal of the project that users should be able to understand the whole framework in a single day.\n\n* Relevance. `utron` doesn't assume anything. We focus on things that matter, this way we are able to ensure easy maintenance and keep the system well-organized, well-planned and sweet.\n\n* Elegance. `utron` uses golang best practises. We are not afraid of heights, it's just that we need a parachute in our backpack. The source code is heavily documented, any functionality should be well explained and well tested.\n\n## Motivation\nAfter two years of playing with golang, I have looked on some of my projects and asked myself: \"How golang is that?\"\n\nSo, `utron` is my reimagining of lightweight MVC, that maintains the golang spirit, and works seamlessly with the current libraries.\n\n\n## Installation\n\nThis works for Go 1.4+\n\n\t$ go get github.com/gernest/utron\n\n## The MVC\nThere is nothing revolutionary about MVC that `utron` brings to the table.\n\n* M is for models, they are the data structures that help with data persistence, utron uses [gorm](https://github.com/jinzhu/gorm) an existing Object Relational Mapper for golang. So if you are familiar with gorm then you are good on the M part.\n\n* V is for Views. Views are templates that render the final output. `utron` uses golang standard templates. You don't have to learn anything new, just the text/template package to master views.\n\n* C is for controllers. This is where the application logic lives. In order to achieve modularity, there are some things that utron requires of controllers. This subject is explained in more detail below.\n\nWith the power of composition and inheritance, `utron` achieves a beautiful MVC workflow. I recommend you read the source code, it is well documented so as to demystify any magical unicorns.\n\n\nWe will create a TODO List application in `utron` to explore all components that makes `utron` MVC tick. The source code of the final application is included in this repository and can be found here [utron todoMVC](fixtures/todo)\n\n# TODO list application with `utron`\n\n## Project structure\nThis is the structure of the `todo` list application that will showcase how you can build web apps with `utron`:\n\n```shell\ntodo\n├── config\n│   ├── app.json\n│   ├── app.toml\n│   └── app.yml\n├── controllers\n│   └── todo.go\n├── models\n│   └── todo.go\n├── static\n│   └── todo.css\n├── views\n│   ├── error.html\n│   └── index.html\n└── main.go\n\n5 directories, 9 files\n```\n\nI have included three configuration files to show how they work, but you are better off with just one.\n\n## Configurations\nutron support yaml, json and toml configurations files. In our todo app, we put the configuration files in the config directory. I have included all three formats for clarity, you can be just fine with either one of them.\n\n`utron` searches for a file named `app.json`, or `app.yml` or `app.toml` in the config directory. The first to be found is the one to be used.\n\nThis is the content of `config/app.json` file:\n\n```json\n{\n\t\"app_name\": \"utron web app\",\n\t\"base_url\": \"http://localhost:8090\",\n\t\"port\": 8090,\n\t\"verbose\": false,\n\t\"static_dir\": \"static\",\n\t\"view_dir\": \"views\",\n\t\"database\": \"postgres\",\n\t\"database_conn\": \"postgres://postgres:postgres@localhost/todo\",\n  \"automigrate\": true\n}\n```\n\nYou can override the values from the config file by setting environment variables. The names of the environment variables are shown below (with their details)\n\nsetting       | environment name | details\n--------------|------------------|----------------\napp_name      | APP_NAME         | application name\nbase_url      | BASE_URL         | the base url to use in your views\nport          | PORT             | port number the server will listen on\nverbose       | VERBOSE          | if set to true, will make all state information log to stdout\nstatic_dir    | STATIC_DIR       | directory to serve static files e.g. images, js or css\nview_dir      | VIEWS_DIR        | directory to look for views\ndatabase      | DATABASE         | the name of the database you use, e.g. postgres, mysql, foundation\ndatabase_conn | DATABASE_CONN    | connection string to your database\nautomigrate   | AUTOMIGRATE      | creates the tables for models automatically.\n\nIf you haven't specified explicitly the location of the configuration directory, it defaults to the directory named `config` in the current working directory.\n\n## Models\n`utron` uses the [gorm](https://github.com/jinzhu/gorm) library as its Object Relational Mapper, so you won't need to learn anything fancy. In our todo app, we need to define a `Todo` model that will be used to store our todo details.\n\nIn the file `models/todo.go` we define our todo model like this\n\n```go\npackage models\n\nimport (\n\t\"time\"\n\n\t\"github.com/gernest/utron\"\n)\n\ntype Todo struct {\n\tID        int       `schema: \"-\"`\n\tBody      string    `schema:\"body\"`\n\tCreatedAt time.Time `schema:\"-\"`\n\tUpdatedAt time.Time `schema:\"-\"`\n}\n\nfunc init() {\n\tutron.RegisterModels(\u0026Todo{})\n}\n```\n\nNotice that we need to register our model by calling `utron.RegisterModels(\u0026Todo{})` in the `init` function otherwise `utron` won't be aware of the model.\n\n`utron` will automatically create the table `todos` if it doesn't exist.\n\nDon't be confused by the `schema` tag, I just added them since we will use the [schema](https://github.com/gorilla/schema) package to decode form values(this has nothing to do with `utron`, you can use whatever form library you fancy.)\n\n\n## Controllers\n`utron` controllers are structs that implement the `Controller` interface. To help make `utron` usable, `utron` provides a `BaseController` which implements the `Controller` interface and offers additional conveniences to help in composing reusable code.\n\nYou get all the benefits of `BaseController` by embedding it in your struct. Our `TODO` Controller is in the `controller/todo.go`\n\n```go\npackage controllers\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gernest/utron\"\n\t\"github.com/gernest/utron/fixtures/todo/models\"\n\t\"github.com/gorilla/schema\"\n)\n\nvar decoder = schema.NewDecoder()\n\ntype TODO struct {\n\t*utron.BaseController\n\tRoutes []string\n}\n\nfunc (t *TODO) Home() {\n\ttodos := []*models.Todo{}\n\tt.Ctx.DB.Order(\"created_at desc\").Find(\u0026todos)\n\tt.Ctx.Data[\"List\"] = todos\n\tt.Ctx.Template = \"index\"\n\tt.HTML(http.StatusOK)\n}\nfunc (t *TODO) Create() {\n\ttodo := \u0026models.Todo{}\n\treq := t.Ctx.Request()\n\treq.ParseForm()\n\tif err := decoder.Decode(todo, req.PostForm); err != nil {\n\t\tt.Ctx.Data[\"Message\"] = err.Error()\n\t\tt.Ctx.Template = \"error\"\n\t\tt.HTML(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tt.Ctx.DB.Create(todo)\n\tt.Ctx.Redirect(\"/\", http.StatusFound)\n}\n\nfunc (t *TODO) Delete() {\n\ttodoID := t.Ctx.Params[\"id\"]\n\tID, err := strconv.Atoi(todoID)\n\tif err != nil {\n\t\tt.Ctx.Data[\"Message\"] = err.Error()\n\t\tt.Ctx.Template = \"error\"\n\t\tt.HTML(http.StatusInternalServerError)\n\t\treturn\n\t}\n\tt.Ctx.DB.Delete(\u0026models.Todo{ID: ID})\n\tt.Ctx.Redirect(\"/\", http.StatusFound)\n}\n\nfunc NewTODO() *TODO {\n\treturn \u0026TODO{\n\t\tRoutes: []string{\n\t\t\t\"get;/;Home\",\n\t\t\t\"post;/create;Create\",\n\t\t\t\"get;/delete/{id};Delete\",\n\t\t},\n\t}\n}\n\nfunc init() {\n\tutron.RegisterController(NewTODO())\n}\n```\n\nNote that we registered our controller by calling `utron.RegisterController(NewTODO())` in the `init` function\nso as to make `utron` aware of our controller. See Routing section below for more explanation of what the controller is doing.\n\n\n## Routing\n\nBy registering a controller, there are two ways of assigning routes.\n\n### case 1- vanilla routing\nBy registering a Controller, routes are auto-generated for the controller methods. The format is `/:controller/:method` where `:controller` is the lowercase name of the Controller, and `:method` is its method in lowercase.\n\nso `(*TODO) Hello()` will map to `/todo/hello`\n\n### case 2- Specifying Routes field\nThe user controller can define a field named `Routes` it should be of type `[]string`, then you can assign routes by appending route string to the Routes field.\n\nThis is a better explanation from comments on the `router.go` file.\n\n```go\n\t\t// if there is any field named Routes, and it is of signature []string\n\t\t// then the field's value is used to overide the patterns defined earlier.\n\t\t//\n\t\t// It is not necessary for every user implementation to define method named Routes\n\t\t// If we cant find it then we just ignore its use( fallback to defaults).\n\t\t//\n\t\t// Route strings, are of the form \"httpMethods;path;method\"\n\t\t// where httpMethods: is a comma separated list of http method strings\n\t\t//                  e.g GET,POST,PUT.\n\t\t//                  The case does not matter, you can use lower case or upper case characters\n\t\t//                  or even mixed case, that is get,GET,gET and GeT will all be treated as GET\n\t\t//\n\t\t//        path:     Is a url path or pattern, utron uses the gorilla mux package. So, everything you can do\n\t\t//                  with gorilla mux url path then you can do here.\n\t\t//                  e.g /hello/{world}\n\t\t//                  Don't worry about the params, they will be accessible via .Ctx.Params field in your\n\t\t//                  controller.\n\t\t//\n\t\t//        method:   The name of the user Controller method to execute for this route.\n```\n\nSo, that explains the following lines in our `todo` app in `controllers/todo.go`\n\n```go\nfunc NewTODO() *TODO {\n\treturn \u0026TODO{\n\t\tRoutes: []string{\n\t\t\t\"get;/;Home\",\n\t\t\t\"post;/create;Create\",\n\t\t\t\"get;/delete/{id};Delete\",\n\t\t},\n\t}\n}\n```\n### case 3: using routes file\nYou can define routes in a file in the `config` directory. The supported formats are json, toml and yaml.\n\n`utron` will look for file named `routes.json`, `routes.toml` or `routes.yml` in that order, the first to be found is the one to be used.\n\nI have included a sample routes file in [fixtures/config/routes.json](fixtures/config/routes.json).\n\nThe difference with case 2 above is you will need to specify the name of the controller explicitly. That is for `TODO` controller, we can define the home route string in routes file like `get;/;TODO.Home`.\n\nWe won't use this in our TODO list app, but you can find it useful in your use case.'\n\n## Views\n`utron` views are golang templates. This is the content of `views/index.html`:\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead lang=\"en\"\u003e\n    \u003cmeta charset=\"UTF-8\"\u003e\n    \u003ctitle\u003eUtron Todo MVC\u003c/title\u003e\n\t\u003clink href=\"/static/todo.css\" rel=\"stylesheet\"\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\u003cform method=\"post\" action=\"/create\"\u003e\n    \u003ctable\u003e\n        \u003ctr\u003e\n           \u003cth\u003e\n               Create A TODO\n           \u003c/th\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003cinput name=\"body\"\u003e\n            \u003c/td\u003e\n            \u003ctd\u003e\n                \u003cbutton type=\"submit\"\u003ecreate\u003c/button\u003e\n            \u003c/td\u003e\n        \u003c/tr\u003e\n    \u003c/table\u003e\n\u003c/form\u003e\n\u003ctable\u003e\n    \u003ctr\u003e\n        \u003cth\u003e\n            My TODO LIST\n        \u003c/th\u003e\n    \u003c/tr\u003e\n    {{range $k,$v:=.List}}\n    \u003ctr\u003e\n        \u003ctd\u003e\n            {{$v.ID}}\n        \u003c/td\u003e\n        \u003ctd\u003e\n            {{$v.Body}}\n        \u003c/td\u003e\n        \u003ctd\u003e\n            \u003ca href=\"/delete/{{$v.ID}}\"\u003e\n                \u003cbutton\u003eDelete\u003c/button\u003e\n            \u003c/a\u003e\n        \u003c/td\u003e\n    \u003c/tr\u003e\n    {{end}}\n\u003c/table\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n\nNote that we have access to `.List` in our view. This is set in the controller, additionally you can access the application configuration via `.Config` context.\n\nAbove is a simple golang template to render our `todo` list application.\n\n## The main.go file\n\n```go\npackage main\n\nimport (\n\t\"github.com/gernest/utron\"\n\t_ \"github.com/gernest/utron/fixtures/todo/controllers\"\n\t_ \"github.com/gernest/utron/fixtures/todo/models\"\n)\n\nfunc main() {\n\tutron.Run()\n}\n```\n\n## Running the TODO app\nIn case you want to run the app we just created, it is included in this repository in [fixtures/todo](fixtures/todo)\n\n* Prerequisite\n - a working database connection (postgres, mysql or foundation)\n - golang toolchain installed and the `go` command in your system $PATH.\n\nstep 1 Install `utron` which will also include the todo app\n\n\t$ go get github.com/gernest/utron\n\nstep 2 cd into the todo app directory\n\n\t$ cd $GOPATH/src/github.com/gernest/utron/fixtures/todo\n\nstep 3 install dependency\n\n\t$ go get github.com/gorilla/schema\n\nstep 4 edit `config/app.json` by setting database and database_conn to your values\n\nstep 5 run the app\n\n\tgo run main.go\n\nIf you see something like this\n\n\t$ 2015/09/15 18:27:24 \u003e\u003eINFO\u003e\u003e starting server at http://localhost:8090\n\nThen everything is okay, open `http://localhost:8090` in your browser to start writing your todos.\nIf you experience anything different, redo the steps and make sure you did them in order and with no errors. If so, and it still doesn't work, open an [issue](https://github.com/gernest/utron/issues).\n\n## Screenshot\n![todo app with utron](fixtures/todo.png)\n\n# Contributing\n\nStart with clicking the star button to make the author and his neighbors happy. Then fork the repository and submit a pull request for whatever change you want to be added to this project.\n\nIf you have any questions, just open an issue.\n\n# Author\nGeofrey Ernest\n\nTwitter  : [@gernesti](https://twitter.com/gernesti)\n\n\n\n# Acknowledgements\nThese amazing projects have made `utron` possible:\n\n* [gorilla mux](https://github.com/gorilla/mux)\n* [ita](https://github.com/gernest/ita)\n* [gorm](https://github.com/jinzhu/gorm)\n* [alice](https://github.com/justinas/alice)\n* [golang](http://golang.org)\n\n\n# Roadmap\n\n*  Fix a lot of typos (English is my third language).\n\n# Licence\n\nThis project is released under the MIT licence. See [LICENCE](LICENCE) for more details.\n\"# gomvc\" \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoolin%2Fgomvc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffoolin%2Fgomvc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoolin%2Fgomvc/lists"}