-
Notifications
You must be signed in to change notification settings - Fork 6
/
restful.go
109 lines (97 loc) · 2.67 KB
/
restful.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package main
import (
"net/http"
"os"
"sync"
"github.com/goburrow/melon"
"github.com/goburrow/melon/configuration/yaml"
"github.com/goburrow/melon/core"
"github.com/goburrow/melon/debug"
"github.com/goburrow/melon/server/router"
"github.com/goburrow/melon/views"
)
// User is data model for user.
type User struct {
Name string `valid:"notempty"`
Age int `valid:"min=13"`
}
var (
errUserNotFound = &views.ErrorMessage{http.StatusNotFound, "User not found."}
errUserExisted = &views.ErrorMessage{http.StatusConflict, "User existed."}
)
// app manages users.
type app struct {
mu sync.RWMutex
users map[string]*User
}
// Initialize adds support for RESTful API and debug endpoint in admin page.
func (a *app) Initialize(b *core.Bootstrap) {
// YAML config file
b.AddBundle(yaml.NewBundle())
// Support RESTful API
b.AddBundle(views.NewBundle(views.NewJSONProvider(), views.NewXMLProvider()))
b.AddBundle(debug.NewBundle())
a.users = make(map[string]*User)
}
func (a *app) Run(conf interface{}, env *core.Environment) error {
env.Server.Register(
views.NewResource("POST", "/user", http.HandlerFunc(a.createUser), views.WithTimerMetric("UserCreate")),
views.NewResource("GET", "/user", views.HandlerFunc(a.listUsers), views.WithTimerMetric("UserList")),
views.NewResource("GET", "/user/{name}", http.HandlerFunc(a.getUser)),
)
return nil
}
func (a *app) createUser(w http.ResponseWriter, r *http.Request) {
user := &User{}
if err := views.Entity(r, user); err != nil {
views.Error(w, r, err)
return
}
a.mu.Lock()
_, ok := a.users[user.Name]
if !ok {
a.users[user.Name] = user
}
a.mu.Unlock()
if ok {
views.Error(w, r, errUserExisted)
} else {
views.Serve(w, r, "Created.")
}
}
func (a *app) getUser(w http.ResponseWriter, r *http.Request) {
params := router.PathParams(r)
a.mu.RLock()
user, ok := a.users[params["name"]]
a.mu.RUnlock()
if ok {
views.Serve(w, r, user)
} else {
views.Error(w, r, errUserNotFound)
}
}
// listUsers demonstrates the usage of views.HandlerFunc.
func (a *app) listUsers(r *http.Request) (interface{}, error) {
a.mu.RLock()
list := make([]*User, len(a.users))
i := 0
for _, u := range a.users {
list[i] = u
i++
}
a.mu.RUnlock()
return list, nil
}
// To run the application:
// $ go run restful.go server config.json
//
// And try these commands to create and retrieve an user:
// curl -XPOST -H'Content-Type: application/json' -d'{"name":"foo","age":20}' 'http://localhost:8080/user'
// curl -XGET 'http://localhost:8080/user/foo'
//
// Check out new links for debug in admin page at http://localhost:8081
func main() {
if err := melon.Run(&app{}, os.Args[1:]); err != nil {
panic(err) // Show stacks
}
}