├── README.md
├── public
├── css
│ └── main.css
└── js
│ └── main.js
├── server.go
└── templates
├── error.tmpl
├── layout.tmpl
├── post.tmpl
└── posts.tmpl
/README.md:
--------------------------------------------------------------------------------
1 | sampleapp
2 | =========
3 |
4 | Sample GoLang App with Martini, Render, Binding, and GORM with MySQL
5 |
--------------------------------------------------------------------------------
/public/css/main.css:
--------------------------------------------------------------------------------
1 | h1 {font-size:100px}
2 |
--------------------------------------------------------------------------------
/public/js/main.js:
--------------------------------------------------------------------------------
1 | //your main js file
2 |
--------------------------------------------------------------------------------
/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "net/http"
5 | "database/sql"
6 | "github.com/coopernurse/gorp"
7 | "github.com/codegangsta/martini"
8 | "github.com/codegangsta/martini-contrib/render"
9 | "github.com/codegangsta/martini-contrib/binding"
10 | _ "github.com/go-sql-driver/mysql"
11 | "html/template"
12 | "log"
13 | "time"
14 | )
15 |
16 | type Post struct {
17 | Id int64 `db:"post_id"`
18 | Created int64
19 | Title string `form:"Title"`
20 | Body string `form:"Body" binding:"required"`
21 | }
22 |
23 | func (bp Post) Validate(errors *binding.Errors, req *http.Request) {
24 | //custom validation
25 | if len(bp.Title) == 0 {
26 | errors.Fields["title"] = "Title cannot be empty"
27 | }
28 | }
29 |
30 |
31 | func main() {
32 |
33 | // initialize the DbMap
34 | dbmap := initDb()
35 | defer dbmap.Db.Close()
36 |
37 | // setup some of the database
38 |
39 | // delete any existing rows
40 | err := dbmap.TruncateTables()
41 | checkErr(err, "TruncateTables failed")
42 |
43 | // create two posts
44 | p1 := newPost("Post 1", "Lorem ipsum lorem ipsum")
45 | p2 := newPost("Post 2", "This is my second post")
46 |
47 | // insert rows
48 | err = dbmap.Insert(&p1, &p2)
49 | checkErr(err, "Insert failed")
50 |
51 |
52 |
53 | // lets start martini and the real code
54 | m := martini.Classic()
55 |
56 | m.Use(render.Renderer(render.Options{
57 | Directory: "templates",
58 | Layout: "layout",
59 | Funcs: []template.FuncMap{
60 | {
61 | "formatTime": func(args ...interface{}) string {
62 | t1 := time.Unix(args[0].(int64), 0)
63 | return t1.Format(time.Stamp)
64 | },
65 | "unescaped": func(args ...interface{}) template.HTML {
66 | return template.HTML(args[0].(string))
67 | },
68 | },
69 | },
70 | }))
71 |
72 | m.Get("/", func(r render.Render) {
73 | //fetch all rows
74 | var posts []Post
75 | _, err = dbmap.Select(&posts, "select * from posts order by post_id")
76 | checkErr(err, "Select failed")
77 |
78 | newmap := map[string]interface{}{"metatitle": "this is my custom title", "posts": posts}
79 |
80 | r.HTML(200, "posts", newmap)
81 | })
82 |
83 | m.Get("/:id", func(args martini.Params, r render.Render) {
84 | var post Post
85 |
86 | err = dbmap.SelectOne(&post, "select * from posts where post_id=?", args["id"])
87 |
88 | //simple error check
89 | if err != nil {
90 | newmap := map[string]interface{}{"metatitle":"404 Error", "message":"This is not found"}
91 | r.HTML(404, "error", newmap)
92 | } else {
93 | newmap := map[string]interface{}{"metatitle": post.Title+" more custom", "post": post}
94 | r.HTML(200, "post", newmap)
95 | }
96 | })
97 |
98 | //shows how to create with binding params
99 | m.Post("/", binding.Bind(Post{}), func(post Post, r render.Render) {
100 |
101 | p1 := newPost(post.Title, post.Body)
102 |
103 | log.Println(p1)
104 |
105 | err = dbmap.Insert(&p1)
106 | checkErr(err, "Insert failed")
107 |
108 | newmap := map[string]interface{}{"metatitle": "created post", "post": p1}
109 | r.HTML(200, "post", newmap)
110 | })
111 |
112 | m.Run()
113 |
114 | }
115 |
116 |
117 | func newPost(title, body string) Post {
118 | return Post{
119 | //Created: time.Now().UnixNano(),
120 | Created: time.Now().Unix(),
121 | Title: title,
122 | Body: body,
123 | }
124 | }
125 |
126 | func initDb() *gorp.DbMap {
127 | // connect to db using standard Go database/sql API
128 | // use whatever database/sql driver you wish
129 |
130 | //db, err := sql.Open("sqlite3", "/tmp/post_db.bin")
131 | db, err := sql.Open("mysql", "USERNAME:PASSWORD@unix(/var/run/mysqld/mysqld.sock)/sample")
132 | checkErr(err, "sql.Open failed")
133 |
134 | // construct a gorp DbMap
135 | // dbmap := &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}
136 | dbmap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
137 |
138 | // add a table, setting the table name to 'posts' and
139 | // specifying that the Id property is an auto incrementing PK
140 | dbmap.AddTableWithName(Post{}, "posts").SetKeys(true, "Id")
141 |
142 | // create the table. in a production system you'd generally
143 | // use a migration tool, or create the tables via scripts
144 | err = dbmap.CreateTablesIfNotExists()
145 | checkErr(err, "Create tables failed")
146 |
147 | return dbmap
148 | }
149 |
150 | func checkErr(err error, msg string) {
151 | if err != nil {
152 | log.Fatalln(msg, err)
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/templates/error.tmpl:
--------------------------------------------------------------------------------
1 |
2 |