...
1 package main
2
3 import (
4 "database/sql"
5 "encoding/json"
6 "net/http"
7 )
8
9 type api struct {
10 db *sql.DB
11 }
12
13 type post struct {
14 ID int
15 Title string
16 Body string
17 }
18
19 func (a *api) posts(w http.ResponseWriter, r *http.Request) {
20 rows, err := a.db.Query("SELECT id, title, body FROM posts")
21 if err != nil {
22 a.fail(w, "failed to fetch posts: "+err.Error(), 500)
23 return
24 }
25 defer rows.Close()
26
27 var posts []*post
28 for rows.Next() {
29 p := &post{}
30 if err := rows.Scan(&p.ID, &p.Title, &p.Body); err != nil {
31 a.fail(w, "failed to scan post: "+err.Error(), 500)
32 return
33 }
34 posts = append(posts, p)
35 }
36 if rows.Err() != nil {
37 a.fail(w, "failed to read all posts: "+rows.Err().Error(), 500)
38 return
39 }
40
41 data := struct {
42 Posts []*post
43 }{posts}
44
45 a.ok(w, data)
46 }
47
48 func main() {
49
50 db, err := sql.Open("mysql", "root@/blog")
51 if err != nil {
52 panic(err)
53 }
54 app := &api{db: db}
55 http.HandleFunc("/posts", app.posts)
56 http.ListenAndServe(":8080", nil)
57 }
58
59 func (a *api) fail(w http.ResponseWriter, msg string, status int) {
60 w.Header().Set("Content-Type", "application/json")
61
62 data := struct {
63 Error string
64 }{Error: msg}
65
66 resp, _ := json.Marshal(data)
67 w.WriteHeader(status)
68 w.Write(resp)
69 }
70
71 func (a *api) ok(w http.ResponseWriter, data interface{}) {
72 w.Header().Set("Content-Type", "application/json")
73
74 resp, err := json.Marshal(data)
75 if err != nil {
76 w.WriteHeader(http.StatusInternalServerError)
77 a.fail(w, "oops something evil has happened", 500)
78 return
79 }
80 w.Write(resp)
81 }
82
View as plain text