Skip to content

Commit 09f3b1b

Browse files
committed
refactor: ⚡ Improved context
1 parent c3eb967 commit 09f3b1b

File tree

4 files changed

+57
-53
lines changed

4 files changed

+57
-53
lines changed

context.go

+42-36
Original file line numberDiff line numberDiff line change
@@ -15,55 +15,57 @@ type Context interface {
1515
Status(int) Context
1616
Header(string, string) Context
1717
Set(string, any)
18-
Get(string) any
19-
Metadata() map[string]any
18+
Get(string) (any, bool)
19+
Unset(string)
2020
Throw(string, error)
21-
JSON(interface{})
22-
XML(interface{})
21+
JSON(any)
22+
XML(any)
2323
Text(string)
2424
Write([]byte)
2525
End()
2626
}
2727

28-
var (
28+
const (
2929
ErrCodeInvalidJSON = "INVALID_JSON"
3030
ErrCodeInvalidXML = "INVALID_XML"
3131
)
3232

33-
var (
33+
const HeaderContentType = "Content-Type"
34+
35+
const (
3436
headerText = "text/plain"
3537
headerJSON = "application/json"
3638
headerXML = "text/xml"
3739
)
3840

3941
type context struct {
40-
w http.ResponseWriter
41-
r *http.Request
42+
w http.ResponseWriter
43+
r *http.Request
44+
meta sync.Map
4245

4346
// for internal purpose
44-
params map[string]string
45-
headers map[string]string
46-
metadata map[string]any
47-
process *sync.Mutex
48-
end bool
49-
status int
50-
code string
51-
err error
47+
params map[string]string
48+
headers map[string]string
49+
end bool
50+
status int
51+
code string
52+
err error
5253
}
5354

5455
func (ctx *context) init() {
5556
ctx.headers = make(map[string]string)
56-
ctx.metadata = make(map[string]any)
57-
ctx.process = new(sync.Mutex)
5857
}
5958

6059
func (ctx *context) destroy() {
6160
ctx.w = nil
6261
ctx.r = nil
63-
ctx.headers = nil
62+
ctx.meta = sync.Map{}
6463
ctx.params = nil
64+
ctx.headers = nil
65+
ctx.end = true
66+
ctx.status = 0
67+
ctx.code = ""
6568
ctx.err = nil
66-
ctx.metadata = nil
6769
}
6870

6971
func (ctx *context) reset() {
@@ -89,17 +91,15 @@ func (ctx *context) Header(key string, value string) Context {
8991
}
9092

9193
func (ctx *context) Set(key string, value any) {
92-
ctx.process.Lock()
93-
ctx.metadata[key] = value
94-
ctx.process.Unlock()
94+
ctx.meta.Store(key, value)
9595
}
9696

97-
func (ctx *context) Get(key string) any {
98-
return ctx.metadata[key]
97+
func (ctx *context) Get(key string) (any, bool) {
98+
return ctx.meta.Load(key)
9999
}
100100

101-
func (ctx *context) Metadata() map[string]any {
102-
return ctx.metadata
101+
func (ctx *context) Unset(key string) {
102+
ctx.meta.Delete(key)
103103
}
104104

105105
func (ctx *context) Throw(code string, err error) {
@@ -114,35 +114,41 @@ func (ctx *context) JSON(data any) {
114114
ctx.Throw(ErrCodeInvalidJSON, err)
115115
return
116116
}
117-
ctx.Header("Content-Type", headerJSON)
117+
if _, exists := ctx.headers[HeaderContentType]; !exists {
118+
ctx.Header(HeaderContentType, headerJSON)
119+
}
118120
ctx.write(body)
119121
}
120122

121-
func (ctx *context) XML(data interface{}) {
123+
func (ctx *context) XML(data any) {
122124
body, err := xmlToBytes(data)
123125
if err != nil {
124126
ctx.Throw(ErrCodeInvalidXML, err)
125127
return
126128
}
127-
ctx.Header("Content-Type", headerXML)
129+
if _, exists := ctx.headers[HeaderContentType]; !exists {
130+
ctx.Header(HeaderContentType, headerXML)
131+
}
128132
ctx.write(body)
129133
}
130134

131135
// send Raw
132136
func (ctx *context) Text(data string) {
133-
ctx.Header("Content-Type", headerText)
137+
if _, exists := ctx.headers[HeaderContentType]; !exists {
138+
ctx.Header(HeaderContentType, headerText)
139+
}
134140
ctx.write([]byte(data))
135141
}
136142

143+
func (ctx *context) Write(data []byte) {
144+
ctx.write(data)
145+
}
146+
137147
// send blank
138148
func (ctx *context) End() {
139149
ctx.write(nil)
140150
}
141151

142-
func (ctx *context) Write(data []byte) {
143-
ctx.write(data)
144-
}
145-
146152
// write bytes in response
147153
func (ctx *context) write(body []byte) {
148154

@@ -179,7 +185,7 @@ func (ctx *context) unhandledException() {
179185
if ctx.err != nil {
180186
ctx.reset()
181187

182-
ctx.Header("Content-Type", headerText)
188+
ctx.Header(HeaderContentType, headerText)
183189

184190
if ctx.code == ErrCodeNotFound {
185191
ctx.Status(http.StatusNotFound)

context_test.go

+11-7
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func TestContext_init(t *testing.T) {
2929
func TestContext_destroy(t *testing.T) {
3030
ctx.destroy()
3131

32-
if ctx.w != nil || ctx.r != nil || ctx.headers != nil {
32+
if ctx.w != nil || ctx.r != nil {
3333
t.Error("context.destroy() should destroy the context")
3434
}
3535
}
@@ -90,7 +90,7 @@ func TestContext_Throw(t *testing.T) {
9090
}
9191

9292
func TestContext_JSON(t *testing.T) {
93-
res := "{\"message\":\"Hello, World!\"}"
93+
res := map[string]any{"message": "Hello, World!"}
9494
r := httptest.NewRequest(http.MethodGet, "/", nil)
9595
w := httptest.NewRecorder()
9696
ctx = &context{
@@ -103,8 +103,8 @@ func TestContext_JSON(t *testing.T) {
103103
ctx.JSON(res)
104104

105105
body, err := ioutil.ReadAll(w.Body)
106-
107-
if err != nil || string(body) != res {
106+
var expected = `{"message":"Hello, World!"}`
107+
if err != nil || string(body) != expected {
108108
t.Error("context.JSON() should write a response in JSON format")
109109
}
110110

@@ -114,7 +114,10 @@ func TestContext_JSON(t *testing.T) {
114114
}
115115

116116
func TestContext_XML(t *testing.T) {
117-
res := "<message>Hello, World!</message>"
117+
type Message struct {
118+
Data string `xml:"data"`
119+
}
120+
118121
r := httptest.NewRequest(http.MethodGet, "/", nil)
119122
w := httptest.NewRecorder()
120123
ctx = &context{
@@ -124,11 +127,12 @@ func TestContext_XML(t *testing.T) {
124127
ctx.init()
125128
defer ctx.destroy()
126129

127-
ctx.XML(res)
130+
ctx.XML(&Message{Data: "Hello, World!"})
128131

129132
body, err := ioutil.ReadAll(w.Body)
133+
var expected = "<Message><data>Hello, World!</data></Message>"
130134

131-
if err != nil || string(body) != res {
135+
if err != nil || string(body) != expected {
132136
t.Error("context.XML() should write a response in XML format")
133137
}
134138

examples/hello-world/main.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,14 @@ func main() {
6262
//==========================Error Handling==================================
6363

6464
api.Get("/test", func(ctx rest.Context) {
65-
ctx.Set("Hi", "There")
65+
ctx.Set("Hi", "{\"a\": 1}")
6666
ctx.Throw("CUSTOM_ERROR", errors.New("custom error"))
6767
})
6868

6969
api.CatchError("CUSTOM_ERROR", func(err error, ctx rest.Context) {
7070
//ctx.Status(412).JSON("{\"a\": 1}")
71-
ctx.Status(412).JSON(ctx.Metadata())
71+
text, _ := ctx.Get("Hi")
72+
ctx.Status(412).Header("Content-Type", "application/json; charset=utf-8").Text(text.(string))
7273
})
7374

7475
http.ListenAndServe(":8080", api)

helper.go

+1-8
Original file line numberDiff line numberDiff line change
@@ -89,17 +89,10 @@ func trim(str string) string {
8989
}
9090

9191
func jsonToBytes(data any) ([]byte, error) {
92-
if body, isString := data.(string); isString {
93-
return json.RawMessage(body).MarshalJSON()
94-
}
95-
9692
//standard JSON as per RFC 7159
9793
return json.Marshal(data)
9894
}
9995

100-
func xmlToBytes(data interface{}) ([]byte, error) {
101-
if body, isString := data.(string); isString {
102-
return []byte(body), nil
103-
}
96+
func xmlToBytes(data any) ([]byte, error) {
10497
return xml.Marshal(data)
10598
}

0 commit comments

Comments
 (0)