/
article_resource.go
131 lines (109 loc) · 2.88 KB
/
article_resource.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package resources
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strconv"
"time"
"github.com/fivestar/resozyme"
"github.com/fivestar/resozyme/_examples/model"
"github.com/fivestar/resozyme/_examples/repos"
"github.com/go-chi/chi"
)
// NewArticleResource creates an ArticleResource.
func NewArticleResource(ctx context.Context) resozyme.Resource {
return &ArticleResource{
Base: resozyme.NewBase(ctx),
view: &articleView{},
articleRepo: repos.NewArticleRepository(),
}
}
// ArticleResource is a resource.
type ArticleResource struct {
*resozyme.Base
view *articleView
articleID int64
articleRepo repos.ArticleRepository
}
// articleView is a view for the ArticleResource.
type articleView struct {
ID int64 `json:"id"`
Title string `json:"title"`
PubDate string `json:"pubDate"`
}
// View returns a resource view.
func (resc *ArticleResource) View() interface{} {
return resc.view
}
// Href returns a path of resource.
func (resc *ArticleResource) Href() string {
return fmt.Sprintf("/articles/%d", resc.articleID)
}
// Bind binds specified values to the resource.
func (resc *ArticleResource) Bind(i interface{}) {
switch v := i.(type) {
case *model.Article:
resc.articleID = v.ID
resc.view.ID = v.ID
resc.view.Title = v.Title
resc.view.PubDate = v.PubDate.Format("2006-01-02")
}
}
// OnGet handles the GET request.
func (resc *ArticleResource) OnGet(w http.ResponseWriter, r *http.Request) {
articleID, _ := strconv.ParseInt(chi.URLParam(r, "articleID"), 10, 64)
article, err := resc.articleRepo.Find(articleID)
if err != nil {
resc.SetCode(http.StatusInternalServerError)
resc.SetError(err)
return
}
if article == nil {
resc.SetCode(http.StatusNotFound)
return
}
resozyme.BindTo(resc, article)
}
// OnPatch handles the PATCH request.
func (resc *ArticleResource) OnPatch(w http.ResponseWriter, r *http.Request) {
articleID, _ := strconv.ParseInt(chi.URLParam(r, "articleID"), 10, 64)
article, err := resc.articleRepo.Find(articleID)
if err != nil {
resc.SetCode(http.StatusInternalServerError)
resc.SetError(err)
return
}
if article == nil {
resc.SetCode(http.StatusNotFound)
return
}
//
resozyme.BindTo(resc, article)
if err := submitArticle(r, resc.view, article); err != nil {
resc.SetCode(http.StatusBadRequest)
resc.SetError(err)
return
}
resozyme.BindTo(resc, article)
}
// submitArticle submits request body to an article.
func submitArticle(r *http.Request, view *articleView, article *model.Article) error {
var err error
decoder := json.NewDecoder(r.Body)
if err = decoder.Decode(view); err != nil {
return err
}
if view.Title == "" {
return fmt.Errorf("title is required")
}
if view.PubDate == "" {
return fmt.Errorf("pubDate is required")
}
article.Title = view.Title
article.PubDate, err = time.Parse("2006-01-02", view.PubDate)
if err != nil {
return err
}
return nil
}